@powerhousedao/reactor-browser 6.2.2-dev.9 → 6.2.2
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/README.md +341 -0
- package/dist/attachment-service-KFFLBEuD.d.ts +1062 -0
- package/dist/attachment-service-KFFLBEuD.d.ts.map +1 -0
- package/dist/{client-u13cr-Vg.js → client-B8ezRmBB.js} +30 -3
- package/dist/client-B8ezRmBB.js.map +1 -0
- package/dist/client-BIHN_UyR.d.ts +14 -0
- package/dist/client-BIHN_UyR.d.ts.map +1 -0
- package/dist/{client-_Gh2Uf0E.js → client-D66jVnot.js} +79 -13
- package/dist/client-D66jVnot.js.map +1 -0
- package/dist/{document-by-id-dLYFX-xz.js → document-by-id-BSZqTN66.js} +81 -51
- package/dist/document-by-id-BSZqTN66.js.map +1 -0
- package/dist/document-model-modules-DfQBNGc-.js +419 -0
- package/dist/document-model-modules-DfQBNGc-.js.map +1 -0
- package/dist/document-operations-CBExT76y.js +2544 -0
- package/dist/document-operations-CBExT76y.js.map +1 -0
- package/dist/global-1rvI8VdA.d.ts +400 -0
- package/dist/global-1rvI8VdA.d.ts.map +1 -0
- package/dist/index-BE3wBHLP.d.ts +349 -0
- package/dist/index-BE3wBHLP.d.ts.map +1 -0
- package/dist/index-BIVDXw3K.d.ts +144 -0
- package/dist/index-BIVDXw3K.d.ts.map +1 -0
- package/dist/index.d.ts +385 -718
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +957 -1712
- package/dist/index.js.map +1 -1
- package/dist/{inspector-proxy-CvQDDxmT.d.ts → inspector-proxy-6h5VKAwt.d.ts} +4 -2
- package/dist/inspector-proxy-6h5VKAwt.d.ts.map +1 -0
- package/dist/{make-ph-event-functions-BHoLPif5.js → make-ph-event-functions-DBq3iWYn.js} +1 -1
- package/dist/{make-ph-event-functions-BHoLPif5.js.map → make-ph-event-functions-DBq3iWYn.js.map} +1 -1
- package/dist/{index-DS4W07Y8.d.ts → pglite-CntadC_p-9NDG14dS.d.ts} +2 -142
- package/dist/pglite-CntadC_p-9NDG14dS.d.ts.map +1 -0
- package/dist/{relational-Dj06-YkI.js → relational-D4sxGPz7.js} +2 -2
- package/dist/{relational-Dj06-YkI.js.map → relational-D4sxGPz7.js.map} +1 -1
- package/dist/renown-BHxwP7xU.js +97 -0
- package/dist/renown-BHxwP7xU.js.map +1 -0
- package/dist/{renown-D-1c_Bvx.js → renown-BIEv6bSI.js} +523 -57
- package/dist/renown-BIEv6bSI.js.map +1 -0
- package/dist/src/ai/index.d.ts +371 -0
- package/dist/src/ai/index.d.ts.map +1 -0
- package/dist/src/ai/index.js +1067 -0
- package/dist/src/ai/index.js.map +1 -0
- package/dist/src/analytics/index.d.ts +1 -1
- package/dist/src/analytics/index.js +2 -1
- package/dist/src/analytics/index.js.map +1 -1
- package/dist/src/graphql/client.d.ts +3 -2
- package/dist/src/graphql/client.js +1 -1
- package/dist/src/graphql-client/entry.d.ts +4 -0
- package/dist/src/graphql-client/entry.js +4 -0
- package/dist/src/relational/index.d.ts +1 -1
- package/dist/src/relational/index.js +1 -1
- package/dist/src/renown/index.d.ts +2 -2
- package/dist/src/renown/index.js +3 -2
- package/dist/src/rpc/index.d.ts +6 -3
- package/dist/src/rpc/index.d.ts.map +1 -1
- package/dist/src/rpc/index.js +41 -10
- package/dist/src/rpc/index.js.map +1 -1
- package/dist/store-BJYcr_FL.js +37 -0
- package/dist/store-BJYcr_FL.js.map +1 -0
- package/dist/switchboard-D4-_jwk-.js +271 -0
- package/dist/switchboard-D4-_jwk-.js.map +1 -0
- package/dist/{types-CPV0Cnsy.d.ts → types-6vDzbRRS.d.ts} +1 -1
- package/dist/{types-CPV0Cnsy.d.ts.map → types-6vDzbRRS.d.ts.map} +1 -1
- package/dist/{client-09xv0Dq6.d.ts → types-Dcv1ZLoW.d.ts} +87 -19
- package/dist/types-Dcv1ZLoW.d.ts.map +1 -0
- package/package.json +27 -10
- package/dist/client-09xv0Dq6.d.ts.map +0 -1
- package/dist/client-_Gh2Uf0E.js.map +0 -1
- package/dist/client-u13cr-Vg.js.map +0 -1
- package/dist/document-by-id-dLYFX-xz.js.map +0 -1
- package/dist/index-D3bV5rcl.d.ts +0 -216
- package/dist/index-D3bV5rcl.d.ts.map +0 -1
- package/dist/index-DS4W07Y8.d.ts.map +0 -1
- package/dist/inspector-proxy-CvQDDxmT.d.ts.map +0 -1
- package/dist/renown-D-1c_Bvx.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,578 +1,185 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as
|
|
1
|
+
import { a as setDocumentCache, c as useDocumentSafe, d as useGetDocumentAsync, f as useGetDocuments, h as readPromiseState, i as addDocumentCacheEventHandler, l as useDocuments, m as addPromiseState, n as useDocumentsByIds, o as useDocument, p as DocumentCache, r as useDispatch, s as useDocumentCache, t as useDocumentById, u as useGetDocument, y as dispatchActions } from "./document-by-id-BSZqTN66.js";
|
|
2
|
+
import { A as createUrlWithPreservedParams, B as makeNodeSlug, C as addResetSelectedNodeEventHandler, D as addDrivesEventHandler, E as setSelectedNode, F as extractNodeIdFromSlug, G as DocumentTypeMismatchError, H as ambientRenownTokenProvider, I as extractNodeSlugFromPath, K as NoSelectedDocumentError, L as findUuid, M as extractDriveIdFromSlug, N as extractDriveSlugFromPath, O as setDrives, P as extractNodeIdFromPath, R as getPathWithoutBase, S as useSelectedDriveSafe, T as addSetSelectedNodeOnPopStateEventHandler, U as makeAuthMiddleware, V as resolveUrlPathname, W as DocumentModelNotFoundError, _ as addSetSelectedDriveOnPopStateEventHandler, a as useVetraPackageManager, b as useSelectedDrive, c as useDocumentTypesInSelectedDrive, d as useFolderNodesInSelectedDrive, f as useNodesInSelectedDrive, g as addSelectedDriveIdEventHandler, h as sortNodesByName, i as setVetraPackageManager, j as extractDriveIdFromPath, k as useDrives, l as useDocumentsInSelectedDrive, m as isFolderNodeKind, n as useDocumentModelModules, o as useVetraPackages, p as isFileNodeKind, q as UnsupportedDocumentTypeError, r as addVetraPackageManagerEventHandler, s as useSelectedNode, t as useDocumentModelModuleById, u as useFileNodesInSelectedDrive, v as setSelectedDrive, w as addSelectedNodeIdEventHandler, x as useSelectedDriveId, y as setSelectedDriveId, z as makeDriveUrlComponent } from "./document-model-modules-DfQBNGc-.js";
|
|
3
|
+
import { t as makePHEventFunctions } from "./make-ph-event-functions-DBq3iWYn.js";
|
|
4
|
+
import { $ as addDefaultDrivesUrlEventHandler, $n as useIsAddLocalDrivesEnabled, $r as makeAuthConnectionParams, $t as setEnabledEditors, A as useReactorClientModule, Ai as getDocumentExtension, An as setRenownUrl, Ar as useSentryRelease, At as addRenownAdaptersEventHandler, B as useDragNode, Bi as closePHModal, Bn as setWarnOutdatedApp, Br as phAppConfigHooks, Bt as addSwitchboardUrlEventHandler, C as addReactorClientModuleEventHandler, Ci as addFileWithProgress, Cn as setIsRelationalProcessorsEnabled, Cr as useRenownChainId, Ct as addIsExternalRelationalProcessorsEnabledEventHandler, D as useModelRegistry, Di as exportFile, Dn as setRenownAdapters, Dr as useRouterBasename, Dt as addIsSentryTracingEnabledEventHandler, E as useDatabase, Ei as deleteNode, En as setLogLevel, Er as useRequiresHardRefresh, Et as addIsRelationalProcessorsEnabledEventHandler, F as usePackageDiscoveryService, Fi as setPreferredEditorOnNode, Fn as setSentryRelease, Fr as useWarnOutdatedApp, Ft as addRouterBasenameEventHandler, G as useFeatures, Gi as usePHModal, Gn as useDefaultDrivesUrl, Gr as setIsDragAndDropEnabled, Gt as phGlobalConfigSetters, H as useDropTarget, Hi as showCreateDocumentModal, Hn as useAnalyticsDatabaseName, Hr as phDocumentEditorConfigHooks, Ht as addVersionEventHandler, I as addGraphQLReactorClientEventHandler, Ii as upgradeDocument, In as setStudioMode, Ir as addAllowedDocumentTypesEventHandler, It as addSentryDsnEventHandler, J as useAttachmentService, Jn as useEnabledEditors, Jr as useIsDragAndDropEnabled, Jt as setBasePath, K as addAttachmentServiceEventHandler, Kn as useDisabledEditors, Kr as setIsExternalControlsEnabled, Kt as setAllowList, L as setGraphQLReactorClient, Li as getUserPermissions, Ln as setSwitchboardUrl, Lr as addIsDragAndDropEnabledEventHandler, Lt as addSentryEnvEventHandler, M as useSyncList, Mi as moveNode$1, Mn as setRouterBasename, Mr as useSwitchboardUrl, Mt as addRenownNetworkIdEventHandler, N as addPackageDiscoveryServiceEventHandler, Ni as renameDriveNode, Nn as setSentryDsn, Nr as useVersion, Nt as addRenownUrlEventHandler, O as usePGlite, Oi as extractInitialState, On as setRenownChainId, Or as useSentryDsn, Ot as addLocalDrivesEnabledEventHandler, P as setPackageDiscoveryService, Pi as renameNode, Pn as setSentryEnv, Pr as useVersionCheckInterval, Pt as addRequiresHardRefreshEventHandler, Q as addCliVersionEventHandler, Qn as useIsAddDriveEnabled, Qr as viewFilterInputFromViewFilter, Qt as setDrivesPreserveStrategy, R as useGraphQLReactorClient, Ri as isDocumentTypeSupported, Rn as setVersion, Rr as addIsExternalControlsEnabledEventHandler, Rt as addSentryReleaseEventHandler, S as addReactorClientEventHandler, Si as addDocument, Sn as setIsPublicDrivesEnabled, Sr as useRenownAdapters, St as addIsExternalProcessorsEnabledEventHandler, T as setReactorClientModule, Ti as copyNode$1, Tn as setLocalDrivesEnabled, Tr as useRenownUrl, Tt as addIsPublicDrivesEnabledEventHandler, U as addFeaturesEventHandler, Ui as showDeleteNodeModal, Un as useBasePath, Ur as phDocumentEditorConfigSetters, Ut as addWarnOutdatedAppEventHandler, V as useDropNode, Vi as setPHModal, Vn as useAllowList, Vr as phAppConfigSetters, Vt as addVersionCheckIntervalEventHandler, W as setFeatures, Wi as showPHModal, Wn as useCliVersion, Wr as setAllowedDocumentTypes, Wt as phGlobalConfigHooks, X as addAnalyticsDatabaseNameEventHandler, Xn as useGaTrackingId, Xr as GraphQLReactorClient, Xt as setDefaultDrivesUrl, Y as addAllowListEventHandler, Yn as useFileUploadOperationsChunkSize, Yr as useIsExternalControlsEnabled, Yt as setCliVersion, Z as addBasePathEventHandler, Zn as useIsAddCloudDrivesEnabled, Zr as isGraphQLReactorClient, Zt as setDisabledEditors, _ as addRevisionHistoryVisibleEventHandler, _i as buildPulledDocument, _n as setIsEditorReadModeEnabled, _r as useIsPublicDrivesEnabled, _t as addIsDocumentModelSelectionSettingsEnabledEventHandler, a as addPHEventHandlers, ai as StaticPackageManager, an as setIsAddPublicDrivesEnabled, ar as useIsDeleteCloudDrivesEnabled, at as addIsAddCloudDrivesEnabledEventHandler, b as showRevisionHistory, bi as hasRevisionConflict, bn as setIsExternalRelationalProcessorsEnabled, br as useLocalDrivesEnabled, bt as addIsEditorReadModeEnabledEventHandler, c as addToastEventHandler, ci as prepareSignedActions, cn as setIsAnalyticsExternalProcessorsEnabled, cr as useIsDiffAnalyticsEnabled, ct as addIsAddPublicDrivesEnabledEventHandler, d as addSelectedTimelineRevisionEventHandler, di as MutateDocumentWithOperationsDocument, dn as setIsDeleteLocalDrivesEnabled, dr as useIsEditorDebugModeEnabled, dt as addIsAnalyticsExternalProcessorsEnabledEventHandler, ei as startDocumentChangesSubscription, en as setFileUploadOperationsChunkSize, er as useIsAddPublicDrivesEnabled, et as addDisabledEditorsEventHandler, f as setSelectedTimelineRevision, fi as ReactorOperationFieldsFragmentDoc, fn as setIsDeletePublicDrivesEnabled, fr as useIsEditorReadModeEnabled, ft as addIsCloudDrivesEnabledEventHandler, g as useSelectedTimelineItem, gi as ConflictError, gn as setIsEditorDebugModeEnabled, gr as useIsLocalDrivesEnabled, gt as addIsDiffAnalyticsEnabledEventHandler, h as setSelectedTimelineItem, hi as revisionMapFromRevisionsList, hn as setIsDriveAnalyticsEnabled, hr as useIsExternalRelationalProcessorsEnabled, ht as addIsDeletePublicDrivesEnabledEventHandler, i as useSwitchboardClient, ii as subgraphUrlFromGraphqlUrl, in as setIsAddLocalDrivesEnabled, ir as useIsCloudDrivesEnabled, it as addGaTrackingIdEventHandler, j as useSync, ji as loadFile, jn as setRequiresHardRefresh, jr as useStudioMode, jt as addRenownChainIdEventHandler, k as useReactorClient, ki as fetchDocumentOperations, kn as setRenownNetworkId, kr as useSentryEnv, kt as addLogLevelEventHandler, l as setPHToast, li as signStampedAction, ln as setIsCloudDrivesEnabled, lr as useIsDocumentModelSelectionSettingsEnabled, lt as addIsAnalyticsDatabaseWorkerEnabledEventHandler, m as addSelectedTimelineItemEventHandler, mi as phDocumentFromMutation, mn as setIsDocumentModelSelectionSettingsEnabled, mr as useIsExternalProcessorsEnabled, mt as addIsDeleteLocalDrivesEnabledEventHandler, n as GraphQLReactorProvider, ni as SubgraphSdkRegistry, nn as setIsAddCloudDrivesEnabled, nr as useIsAnalyticsEnabled, nt as addEnabledEditorsEventHandler, o as callEventHandlerRegisterFunctions, oi as packageFromDocumentModels, on as setIsAnalyticsDatabaseWorkerEnabled, or as useIsDeleteLocalDrivesEnabled, ot as addIsAddDriveEnabledEventHandler, p as useSelectedTimelineRevision, pi as phDocumentFromGetDocument, pn as setIsDiffAnalyticsEnabled, pr as useIsExternalPackagesEnabled, pt as addIsDeleteCloudDrivesEnabledEventHandler, q as setAttachmentService, qn as useDrivesPreserveStrategy, qr as useAllowedDocumentTypes, qt as setAnalyticsDatabaseName, r as ensurePHEventHandlers, ri as describeGraphQLDocument, rn as setIsAddDriveEnabled, rr as useIsAnalyticsExternalProcessorsEnabled, rt as addFileUploadOperationsChunkSizeEventHandler, s as commonGlobalEventHandlerFunctions, si as resolveDocumentModelModule, sn as setIsAnalyticsEnabled, sr as useIsDeletePublicDrivesEnabled, st as addIsAddLocalDrivesEnabledEventHandler, t as useDocumentOperations, ti as subscriptionsUrlFromGraphqlUrl, tn as setGaTrackingId, tr as useIsAnalyticsDatabaseWorkerEnabled, tt as addDrivesPreserveStrategyEventHandler, u as usePHToast, ui as stampAction, un as setIsDeleteCloudDrivesEnabled, ur as useIsDriveAnalyticsEnabled, ut as addIsAnalyticsEnabledEventHandler, v as hideRevisionHistory, vi as convertRemoteOperations, vn as setIsExternalPackagesEnabled, vr as useIsRelationalProcessorsEnabled, vt as addIsDriveAnalyticsEnabledEventHandler, w as setReactorClient, wi as addFolder, wn as setIsSentryTracingEnabled, wr as useRenownNetworkId, wt as addIsLocalDrivesEnabledEventHandler, x as useRevisionHistoryVisible, xi as screamingSnakeToCamel, xn as setIsLocalDrivesEnabled, xr as useLogLevel, xt as addIsExternalPackagesEnabledEventHandler, y as setRevisionHistoryVisible, yi as extractRevisionMap, yn as setIsExternalProcessorsEnabled, yr as useIsSentryTracingEnabled, yt as addIsEditorDebugModeEnabledEventHandler, z as addDraggingNodeEventHandler, zi as addModalEventHandler, zn as setVersionCheckInterval, zr as isExternalControlsEnabledEventFunctions, zt as addStudioModeEventHandler } from "./document-operations-CBExT76y.js";
|
|
5
|
+
import { a as setGlobal, i as getGlobal, n as getAnalyticsStore, r as clearGlobal, t as createAnalyticsStore } from "./store-BJYcr_FL.js";
|
|
3
6
|
import { baseDocumentModels, baseDocumentModelsMap } from "./src/document-model.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { i as
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
7
|
+
import { i as GetDocumentWithOperationsDocument, o as PropagationMode, t as createClient } from "./client-D66jVnot.js";
|
|
8
|
+
import { a as useRenown, c as RENOWN_INITIAL_UNKNOWN, d as useRenownInitialUser, f as addLoadingEventHandler, h as useLoading, i as useLoginStatus, l as RenownInitialUserProvider, m as setLoading, n as setRenown, o as useUser, p as loading, r as useDid, s as RENOWN_INITIAL_ANONYMOUS, t as addRenownEventHandler, u as useRenownInitialAuth } from "./renown-BHxwP7xU.js";
|
|
9
|
+
import { A as RENOWN_CHAIN_ID, C as logout, D as CREDENTIAL_TYPES, E as CREDENTIAL_SUBJECT_TYPE, M as RENOWN_URL, N as VERIFIABLE_CREDENTIAL_EIP712_TYPE, O as DOMAIN_TYPE, S as login, T as CREDENTIAL_SCHEMA_EIP712_TYPE, _ as RenownLogo, a as Renown, b as useRenownAuth, c as useRenownSessionSynced, d as RenownAuthButton, f as RenownUserButton, g as DisconnectIcon, h as CopyIcon, i as RenownWalletProvider, j as RENOWN_NETWORK_ID, k as ISSUER_TYPE, l as initConnectCrypto, m as ChevronDownIcon, n as useRenownLoginMethods, o as useRenownInit, p as RenownLoginButton, r as RenownProvider, s as useRenownSessionCookie, t as useRenownWalletAdapter, u as initRenownCrypto, v as SpinnerIcon, w as openRenown, x as useRenownAuthAsync, y as UserIcon } from "./renown-BIEv6bSI.js";
|
|
10
|
+
import { c as useSelectedDocument, d as useSelectedDocumentSafe, f as useDocumentOfType, l as useSelectedDocumentId, t as GQL_CHANNEL_SUFFIX, u as useSelectedDocumentOfType } from "./switchboard-D4-_jwk-.js";
|
|
11
|
+
import { i as setPGliteDB, n as useRelationalQuery, r as useRelationalDb, t as createProcessorQuery } from "./relational-D4sxGPz7.js";
|
|
12
|
+
import { a as getPackagesForDocumentType, i as getPackagesByDocumentType, n as getPackagePage, o as trimTrailingSlash, r as getPackages, t as RegistryClient } from "./client-B8ezRmBB.js";
|
|
13
|
+
import { createZip, isDocumentZip, parseBulkArchive, toTransportAction, validateInitialState, validateModules, validateStateSchemaName, zipEntries } from "@powerhousedao/shared/document-model";
|
|
14
|
+
import { DriveDocumentSchema, driveCreateDocument, getDescendants, getNextCopyNumber, isFileNode, isFolderNode, setAvailableOffline, setDriveIcon, setDriveName, setSharingType } from "@powerhousedao/shared/document-drive";
|
|
15
|
+
import { allPass, filter, find, forEach, funnel, hasAtLeast, isArray, isDefined, isIncludedIn, isStrictEqual, isTruthy, last, map, mapToObj, once, pipe, prop, split, unique } from "remeda";
|
|
16
|
+
import { pascalCase } from "change-case";
|
|
13
17
|
import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
18
|
+
import { AuthEnforcementDisabledError, ChannelScheme, DocumentChangeType, DocumentChangeType as DocumentChangeType$1, DocumentIntegrityService, DriveCollectionId, DriveCollectionId as DriveCollectionId$1, GqlRequestChannel, InMemoryQueue, IntervalPollTimer, PollBehavior, PropagationMode as PropagationMode$1, REACTOR_SCHEMA, REACTOR_SCHEMA as REACTOR_SCHEMA$1, ReactorBuilder, ReactorClientBuilder, RelationalDbProcessor, SyncOperationStatus, SyncStatus, driveIdFromUrl, isDriveAuthError, isDriveAuthError as isDriveAuthError$1, parseDriveUrl } from "@powerhousedao/reactor";
|
|
19
|
+
import { Kind, parse } from "graphql";
|
|
14
20
|
import { z } from "zod";
|
|
15
|
-
import slug from "slug";
|
|
16
21
|
import normalizeException from "normalize-exception";
|
|
17
|
-
import
|
|
22
|
+
import lzString from "lz-string";
|
|
18
23
|
import { createAttachmentClient } from "@powerhousedao/reactor-attachments/client";
|
|
19
|
-
//#region src/
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
static isError(error) {
|
|
37
|
-
return Error.isError(error) && error.name === "DocumentModelNotFoundError";
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
var DocumentTypeMismatchError = class extends Error {
|
|
41
|
-
constructor(documentId, expectedType, actualType) {
|
|
42
|
-
super(`Document ${documentId} is not of type ${expectedType}. Actual type: ${actualType}`);
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
var NoSelectedDocumentError = class extends Error {
|
|
46
|
-
constructor() {
|
|
47
|
-
super("There is no selected document. Did you mean to call 'useSelectedDocumentSafe' instead?");
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
//#endregion
|
|
51
|
-
//#region src/utils/documents.ts
|
|
52
|
-
function isDocumentTypeSupported(documentType, supportedDocuments) {
|
|
53
|
-
if (!supportedDocuments?.length) return true;
|
|
54
|
-
return supportedDocuments.some((pattern) => {
|
|
55
|
-
if (pattern.endsWith("/*")) {
|
|
56
|
-
const prefix = pattern.slice(0, -2);
|
|
57
|
-
return documentType.startsWith(prefix + "/");
|
|
58
|
-
}
|
|
59
|
-
if (pattern.endsWith("*") && !pattern.endsWith("/*")) {
|
|
60
|
-
const prefix = pattern.slice(0, -1);
|
|
61
|
-
return documentType.startsWith(prefix);
|
|
62
|
-
}
|
|
63
|
-
return pattern === documentType;
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
//#endregion
|
|
67
|
-
//#region src/utils/user.ts
|
|
68
|
-
function getUserPermissions() {
|
|
69
|
-
const user = window.ph?.renown?.user;
|
|
70
|
-
const allowList = window.ph?.allowList;
|
|
71
|
-
if (!allowList) return {
|
|
72
|
-
isAllowedToCreateDocuments: true,
|
|
73
|
-
isAllowedToEditDocuments: true
|
|
74
|
-
};
|
|
75
|
-
return {
|
|
76
|
-
isAllowedToCreateDocuments: allowList.includes(user?.address ?? ""),
|
|
77
|
-
isAllowedToEditDocuments: allowList.includes(user?.address ?? "")
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
//#endregion
|
|
81
|
-
//#region src/actions/document.ts
|
|
82
|
-
const BASE_STATE_KEYS = new Set(["auth"]);
|
|
83
|
-
const NON_DOMAIN_SCOPES = new Set(["auth", "document"]);
|
|
84
|
-
async function isDocumentInLocation(document, driveId, parentFolder) {
|
|
24
|
+
//#region src/actions/bulk-archive.ts
|
|
25
|
+
/**
|
|
26
|
+
* Expand a dropped file into import jobs. A single-document zip is passed
|
|
27
|
+
* through unchanged. A bulk archive (a zip whose tree of files are
|
|
28
|
+
* single-document zips) has its top-level folder — and subfolders —
|
|
29
|
+
* recreated under `targetParent` (existing same-named folders are reused),
|
|
30
|
+
* and each leaf becomes one job targeting its recreated folder. Throws
|
|
31
|
+
* without touching the drive when no leaf is a document zip.
|
|
32
|
+
*/
|
|
33
|
+
async function expandBulkArchive(file, driveId, targetParent) {
|
|
34
|
+
const data = new Uint8Array(await file.arrayBuffer());
|
|
35
|
+
if (await isDocumentZip(data)) return [{
|
|
36
|
+
file,
|
|
37
|
+
parent: targetParent
|
|
38
|
+
}];
|
|
39
|
+
const entries = await parseBulkArchive(data);
|
|
40
|
+
if (!(await Promise.all(entries.map((entry) => isDocumentZip(entry.data)))).some(Boolean)) throw new Error("Archive contains no Powerhouse documents");
|
|
85
41
|
const reactorClient = window.ph?.reactorClient;
|
|
86
|
-
if (!reactorClient)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
nodeId: nodeById.id
|
|
98
|
-
};
|
|
99
|
-
const nodeByNameAndType = drive.state.global.nodes.find((node) => isFileNode(node) && node.name === document.header.name && node.documentType === document.header.documentType && node.parentFolder === (parentFolder ?? null));
|
|
100
|
-
if (nodeByNameAndType) return {
|
|
101
|
-
isDuplicate: true,
|
|
102
|
-
duplicateType: "name",
|
|
103
|
-
nodeId: nodeByNameAndType.id
|
|
42
|
+
if (!reactorClient) throw new Error("ReactorClient not initialized");
|
|
43
|
+
const knownNodes = [...(await reactorClient.get(driveId)).state.global.nodes];
|
|
44
|
+
const dirToNode = /* @__PURE__ */ new Map();
|
|
45
|
+
const ensureDir = async (dirPath, parent) => {
|
|
46
|
+
const cached = dirToNode.get(dirPath);
|
|
47
|
+
if (cached) return cached;
|
|
48
|
+
const name = dirPath.split("/").pop() ?? dirPath;
|
|
49
|
+
const node = knownNodes.find((n) => isFolderNode(n) && n.name === name && (n.parentFolder ?? null) === (parent?.id ?? null)) ?? await addFolder(driveId, name, parent?.id);
|
|
50
|
+
dirToNode.set(dirPath, node);
|
|
51
|
+
knownNodes.push(node);
|
|
52
|
+
return node;
|
|
104
53
|
};
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
case "powerhouse/processor": {
|
|
115
|
-
const processorType = document.state.global?.type;
|
|
116
|
-
if (processorType === "analytics") return "analytics-processor";
|
|
117
|
-
if (processorType === "relational") return "relational-processor";
|
|
118
|
-
if (processorType === "codegen") return "codegen-processor";
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
default: return;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
async function downloadFile(document, fileName) {
|
|
125
|
-
try {
|
|
126
|
-
const data = await createZip(document);
|
|
127
|
-
const blob = new Blob([new Uint8Array(data)], { type: "application/zip" });
|
|
128
|
-
const link = window.document.createElement("a");
|
|
129
|
-
link.style.display = "none";
|
|
130
|
-
link.href = URL.createObjectURL(blob);
|
|
131
|
-
link.download = fileName;
|
|
132
|
-
window.document.body.appendChild(link);
|
|
133
|
-
link.click();
|
|
134
|
-
window.document.body.removeChild(link);
|
|
135
|
-
} catch (e) {
|
|
136
|
-
logger.error(e instanceof Error ? e.message : String(e));
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
async function getDocumentExtension(document) {
|
|
140
|
-
const documentType = document.header.documentType;
|
|
141
|
-
let rawExtension;
|
|
142
|
-
if (documentType === documentModelDocumentType) rawExtension = document.state.global?.extension;
|
|
143
|
-
else {
|
|
144
|
-
const reactorClient = window.ph?.reactorClient;
|
|
145
|
-
if (reactorClient) {
|
|
146
|
-
const { results: documentModelModules } = await reactorClient.getDocumentModelModules();
|
|
147
|
-
rawExtension = documentModelModules.find((m) => m.documentModel.global.id === documentType)?.utils.fileExtension;
|
|
54
|
+
const jobs = [];
|
|
55
|
+
for (const entry of entries) {
|
|
56
|
+
const segments = entry.path.split("/");
|
|
57
|
+
const leaf = segments.pop();
|
|
58
|
+
let parent = targetParent;
|
|
59
|
+
let prefix = "";
|
|
60
|
+
for (const segment of segments) {
|
|
61
|
+
prefix = prefix ? `${prefix}/${segment}` : segment;
|
|
62
|
+
parent = await ensureDir(prefix, parent);
|
|
148
63
|
}
|
|
64
|
+
jobs.push({
|
|
65
|
+
file: new File([new Uint8Array(entry.data)], leaf),
|
|
66
|
+
parent
|
|
67
|
+
});
|
|
149
68
|
}
|
|
150
|
-
return
|
|
69
|
+
return jobs;
|
|
151
70
|
}
|
|
71
|
+
//#endregion
|
|
72
|
+
//#region src/actions/folder-zip.ts
|
|
73
|
+
const sanitize = (segment) => segment.replace(/\//g, "-");
|
|
152
74
|
/**
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
75
|
+
* Name segments from the exported folder (exclusive) down to `node`
|
|
76
|
+
* (inclusive), in top-down order. `root === undefined` means the drive root:
|
|
77
|
+
* all ancestors. A node that IS the exported folder yields no segments.
|
|
156
78
|
*/
|
|
157
|
-
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
cursor,
|
|
165
|
-
limit: pageSize
|
|
166
|
-
});
|
|
167
|
-
for (const op of page.results) {
|
|
168
|
-
const scope = op.action.scope ?? "global";
|
|
169
|
-
if (operations[scope]) operations[scope].push(op);
|
|
170
|
-
}
|
|
171
|
-
cursor = page.nextCursor ?? "";
|
|
172
|
-
} while (cursor);
|
|
173
|
-
return operations;
|
|
174
|
-
}
|
|
175
|
-
function extractInitialState(documentScopeOps) {
|
|
176
|
-
const upgradeOp = documentScopeOps.find((op) => op.action.type === "UPGRADE_DOCUMENT");
|
|
177
|
-
if (!upgradeOp) throw new Error("No UPGRADE_DOCUMENT operation found — document is invalid");
|
|
178
|
-
const input = upgradeOp.action.input;
|
|
179
|
-
const initialState = input.initialState ?? input.state;
|
|
180
|
-
if (!initialState) throw new Error("UPGRADE_DOCUMENT operation has no initialState — document is invalid");
|
|
181
|
-
return initialState;
|
|
182
|
-
}
|
|
183
|
-
function filterDomainOperations(operations) {
|
|
184
|
-
return Object.fromEntries(Object.entries(operations).filter(([scope]) => !NON_DOMAIN_SCOPES.has(scope)));
|
|
185
|
-
}
|
|
186
|
-
async function exportFile(document, suggestedName) {
|
|
187
|
-
const reactorClient = window.ph?.reactorClient;
|
|
188
|
-
if (!reactorClient) throw new Error("ReactorClient not initialized");
|
|
189
|
-
const operations = await fetchDocumentOperations(reactorClient, document);
|
|
190
|
-
const initialState = extractInitialState(operations["document"] ?? []);
|
|
191
|
-
const documentWithOps = {
|
|
192
|
-
...document,
|
|
193
|
-
operations,
|
|
194
|
-
initialState
|
|
195
|
-
};
|
|
196
|
-
const extension = await getDocumentExtension(documentWithOps);
|
|
197
|
-
const baseName = suggestedName || documentWithOps.header.name || "Untitled";
|
|
198
|
-
const name = extension ? `${baseName}.${extension}.phd` : `${baseName}.phd`;
|
|
199
|
-
if (!window.showSaveFilePicker) return await downloadFile(documentWithOps, name);
|
|
200
|
-
try {
|
|
201
|
-
const fileHandle = await window.showSaveFilePicker({ suggestedName: name });
|
|
202
|
-
await baseSaveToFileHandle(documentWithOps, fileHandle);
|
|
203
|
-
return fileHandle;
|
|
204
|
-
} catch (e) {
|
|
205
|
-
if (!(e instanceof DOMException && e.name === "AbortError")) throw e;
|
|
79
|
+
function segmentsBelow(root, node, allNodes) {
|
|
80
|
+
const segments = [];
|
|
81
|
+
let current = node;
|
|
82
|
+
while (current && current.id !== root?.id) {
|
|
83
|
+
segments.push(sanitize(current.name));
|
|
84
|
+
const parentId = current.parentFolder;
|
|
85
|
+
current = parentId ? allNodes.find((n) => n.id === parentId) : void 0;
|
|
206
86
|
}
|
|
87
|
+
return segments.reverse();
|
|
207
88
|
}
|
|
208
89
|
/**
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
90
|
+
* Assemble the archive zip for a folder (or the whole drive when
|
|
91
|
+
* `folderNode` is undefined). Every folder in the subtree becomes a
|
|
92
|
+
* directory entry (empty folders survive); every file becomes a standard
|
|
93
|
+
* single-document zip named after the node (drive naming convention:
|
|
94
|
+
* `${name}.${extension}.phd`, ` (copy) N` on a same-folder collision).
|
|
95
|
+
*
|
|
96
|
+
* `fetchDocument` must return the document WITH its full operations and
|
|
97
|
+
* initialState (see downloadFolderZip).
|
|
212
98
|
*/
|
|
213
|
-
async function
|
|
214
|
-
const
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
const
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
99
|
+
async function buildFolderZip(drive, folderNode, fetchDocument, onProgress) {
|
|
100
|
+
const allNodes = drive.state.global.nodes;
|
|
101
|
+
const topName = sanitize(folderNode?.name ?? (drive.state.global.name || drive.header.name));
|
|
102
|
+
const subtree = folderNode ? [folderNode, ...getDescendants(folderNode, allNodes)] : allNodes;
|
|
103
|
+
const entries = { [topName + "/"]: new Uint8Array(0) };
|
|
104
|
+
for (const node of subtree) {
|
|
105
|
+
if (!isFolderNode(node)) continue;
|
|
106
|
+
const dir = [topName, ...segmentsBelow(folderNode, node, allNodes)].join("/");
|
|
107
|
+
entries[dir + "/"] = new Uint8Array(0);
|
|
108
|
+
}
|
|
109
|
+
const files = subtree.filter(isFileNode);
|
|
110
|
+
const failed = [];
|
|
111
|
+
const usedNamesByDir = /* @__PURE__ */ new Map();
|
|
112
|
+
let done = 0;
|
|
113
|
+
for (const node of files) try {
|
|
114
|
+
const doc = await fetchDocument(node.id);
|
|
115
|
+
const extension = await getDocumentExtension(doc);
|
|
116
|
+
const parent = node.parentFolder ? allNodes.find((n) => n.id === node.parentFolder) : void 0;
|
|
117
|
+
const dir = [topName, ...parent ? segmentsBelow(folderNode, parent, allNodes) : []].join("/");
|
|
118
|
+
let usedNames = usedNamesByDir.get(dir);
|
|
119
|
+
if (!usedNames) {
|
|
120
|
+
usedNames = /* @__PURE__ */ new Set();
|
|
121
|
+
usedNamesByDir.set(dir, usedNames);
|
|
122
|
+
}
|
|
123
|
+
const base = sanitize(node.name);
|
|
124
|
+
let candidate = base;
|
|
125
|
+
let count = getNextCopyNumber([...usedNames], base);
|
|
126
|
+
while (usedNames.has(candidate)) {
|
|
127
|
+
candidate = `${base} (copy) ${count}`;
|
|
128
|
+
count += 1;
|
|
129
|
+
}
|
|
130
|
+
usedNames.add(candidate);
|
|
131
|
+
const leaf = extension ? `${candidate}.${extension}.phd` : `${candidate}.phd`;
|
|
132
|
+
entries[`${dir}/${leaf}`] = await createZip(doc);
|
|
133
|
+
} catch {
|
|
134
|
+
failed.push(node.name);
|
|
135
|
+
} finally {
|
|
136
|
+
done += 1;
|
|
137
|
+
onProgress?.(done, files.length);
|
|
251
138
|
}
|
|
252
139
|
return {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
kind: "file"
|
|
140
|
+
zip: await zipEntries(entries),
|
|
141
|
+
archiveName: `${topName}.zip`,
|
|
142
|
+
entryCount: files.length - failed.length,
|
|
143
|
+
failed
|
|
258
144
|
};
|
|
259
145
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
146
|
+
/**
|
|
147
|
+
* Export a folder (or whole drive) to disk: fetches every document with its
|
|
148
|
+
* full operation history, builds the archive, and saves it via
|
|
149
|
+
* showSaveFilePicker (fallback: blob download), mirroring exportFile.
|
|
150
|
+
*/
|
|
151
|
+
async function downloadFolderZip(drive, folderNode, onProgress) {
|
|
266
152
|
const reactorClient = window.ph?.reactorClient;
|
|
267
153
|
if (!reactorClient) throw new Error("ReactorClient not initialized");
|
|
268
|
-
|
|
269
|
-
await reactorClient.get(
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
header.name = name || document.header.name;
|
|
277
|
-
const initialDocument = {
|
|
278
|
-
...document,
|
|
279
|
-
header,
|
|
280
|
-
state: document.initialState,
|
|
281
|
-
operations: Object.keys(document.operations).reduce((acc, key) => {
|
|
282
|
-
acc[key] = [];
|
|
283
|
-
return acc;
|
|
284
|
-
}, {})
|
|
285
|
-
};
|
|
286
|
-
await addDocument(driveId, name || document.header.name, document.header.documentType, parentFolder, initialDocument, documentId, document.header.meta?.preferredEditor);
|
|
287
|
-
await uploadOperations(documentId, filterDomainOperations(document.operations), queueOperations);
|
|
288
|
-
}
|
|
289
|
-
async function addFileWithProgress(file, driveId, name, parentFolder, onProgress, documentTypes, resolveConflict) {
|
|
290
|
-
logger.verbose(`addFileWithProgress(drive: ${driveId}, name: ${name}, folder: ${parentFolder})`);
|
|
291
|
-
const reactor = window.ph?.reactorClient;
|
|
292
|
-
if (!reactor) return;
|
|
293
|
-
const { isAllowedToCreateDocuments } = getUserPermissions();
|
|
294
|
-
if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to create files");
|
|
295
|
-
try {
|
|
296
|
-
onProgress?.({
|
|
297
|
-
stage: "loading",
|
|
298
|
-
progress: 0
|
|
299
|
-
});
|
|
300
|
-
let document;
|
|
301
|
-
try {
|
|
302
|
-
document = await loadFile(file);
|
|
303
|
-
} catch (loadError) {
|
|
304
|
-
const discoveryService = window.ph?.packageDiscoveryService;
|
|
305
|
-
if (discoveryService && DocumentModelNotFoundError.isError(loadError)) {
|
|
306
|
-
retryAfterDiscovery(discoveryService, loadError.documentType, file, driveId, name, parentFolder, onProgress, documentTypes, resolveConflict);
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
309
|
-
throw loadError;
|
|
310
|
-
}
|
|
311
|
-
const duplicateCheck = await isDocumentInLocation(document, driveId, parentFolder);
|
|
312
|
-
if (duplicateCheck.isDuplicate && !resolveConflict) {
|
|
313
|
-
onProgress?.({
|
|
314
|
-
stage: "conflict",
|
|
315
|
-
progress: 0,
|
|
316
|
-
duplicateType: duplicateCheck.duplicateType
|
|
317
|
-
});
|
|
318
|
-
return;
|
|
319
|
-
}
|
|
320
|
-
const documentType = getDocumentTypeIcon(document);
|
|
321
|
-
if (documentType) onProgress?.({
|
|
322
|
-
stage: "loading",
|
|
323
|
-
progress: 10,
|
|
324
|
-
documentType
|
|
325
|
-
});
|
|
326
|
-
else onProgress?.({
|
|
327
|
-
stage: "loading",
|
|
328
|
-
progress: 10
|
|
329
|
-
});
|
|
330
|
-
if (!isDocumentTypeSupported(document.header.documentType, documentTypes)) {
|
|
331
|
-
onProgress?.({
|
|
332
|
-
stage: "unsupported-document-type",
|
|
333
|
-
progress: 100,
|
|
334
|
-
error: `Document type ${document.header.documentType} is not supported`
|
|
335
|
-
});
|
|
336
|
-
throw new UnsupportedDocumentTypeError(document.header.documentType);
|
|
337
|
-
}
|
|
338
|
-
await reactor.getDocumentModelModule(document.header.documentType);
|
|
339
|
-
onProgress?.({
|
|
340
|
-
stage: "initializing",
|
|
341
|
-
progress: 10
|
|
342
|
-
});
|
|
343
|
-
let duplicateId = false;
|
|
344
|
-
try {
|
|
345
|
-
await reactor.get(document.header.id);
|
|
346
|
-
duplicateId = true;
|
|
347
|
-
} catch {}
|
|
348
|
-
const documentId = duplicateId ? generateId() : document.header.id;
|
|
349
|
-
const header = createPresignedHeader(documentId, document.header.documentType);
|
|
350
|
-
header.lastModifiedAtUtcIso = document.header.createdAtUtcIso;
|
|
351
|
-
header.meta = document.header.meta;
|
|
352
|
-
header.name = name || document.header.name;
|
|
353
|
-
const initialDocument = {
|
|
354
|
-
...document,
|
|
355
|
-
header,
|
|
356
|
-
state: document.initialState,
|
|
357
|
-
operations: Object.keys(document.operations).reduce((acc, key) => {
|
|
358
|
-
acc[key] = [];
|
|
359
|
-
return acc;
|
|
360
|
-
}, {})
|
|
154
|
+
const result = await buildFolderZip(drive, folderNode, async (id) => {
|
|
155
|
+
const doc = await reactorClient.get(id);
|
|
156
|
+
const operations = await fetchDocumentOperations(reactorClient, doc);
|
|
157
|
+
const initialState = extractInitialState(operations["document"] ?? []);
|
|
158
|
+
return {
|
|
159
|
+
...doc,
|
|
160
|
+
operations,
|
|
161
|
+
initialState
|
|
361
162
|
};
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
const overallProgress = 20 + Math.round(uploadPercent * 80);
|
|
374
|
-
onProgress?.({
|
|
375
|
-
stage: "uploading",
|
|
376
|
-
progress: overallProgress,
|
|
377
|
-
totalOperations: uploadProgress.totalOperations,
|
|
378
|
-
uploadedOperations: uploadProgress.uploadedOperations
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
|
-
} });
|
|
382
|
-
onProgress?.({
|
|
383
|
-
stage: "complete",
|
|
384
|
-
progress: 100,
|
|
385
|
-
fileNode
|
|
386
|
-
});
|
|
387
|
-
return fileNode;
|
|
388
|
-
} catch (error) {
|
|
389
|
-
if (!UnsupportedDocumentTypeError.isError(error)) {
|
|
390
|
-
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
391
|
-
onProgress?.({
|
|
392
|
-
stage: "failed",
|
|
393
|
-
progress: 100,
|
|
394
|
-
error: errorMessage
|
|
395
|
-
});
|
|
396
|
-
}
|
|
397
|
-
throw error;
|
|
163
|
+
}, onProgress);
|
|
164
|
+
if (!window.showSaveFilePicker) {
|
|
165
|
+
const blob = new Blob([new Uint8Array(result.zip)], { type: "application/zip" });
|
|
166
|
+
const link = window.document.createElement("a");
|
|
167
|
+
link.style.display = "none";
|
|
168
|
+
link.href = URL.createObjectURL(blob);
|
|
169
|
+
link.download = result.archiveName;
|
|
170
|
+
window.document.body.appendChild(link);
|
|
171
|
+
link.click();
|
|
172
|
+
window.document.body.removeChild(link);
|
|
173
|
+
return result;
|
|
398
174
|
}
|
|
399
|
-
}
|
|
400
|
-
async function retryAfterDiscovery(discoveryService, documentType, file, driveId, name, parentFolder, onProgress, documentTypes, resolveConflict) {
|
|
401
|
-
if (!discoveryService) return;
|
|
402
175
|
try {
|
|
403
|
-
await
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
stage: "unsupported-document-type",
|
|
407
|
-
progress: 100,
|
|
408
|
-
error: `Document type ${documentType} is not supported`
|
|
409
|
-
});
|
|
410
|
-
return;
|
|
411
|
-
}
|
|
412
|
-
await addFileWithProgress(file, driveId, name, parentFolder, onProgress, documentTypes, resolveConflict);
|
|
413
|
-
}
|
|
414
|
-
async function addFolder(driveId, name, parentFolder) {
|
|
415
|
-
const { isAllowedToCreateDocuments } = getUserPermissions();
|
|
416
|
-
if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to create folders");
|
|
417
|
-
const reactorClient = window.ph?.reactorClient;
|
|
418
|
-
if (!reactorClient) throw new Error("ReactorClient not initialized");
|
|
419
|
-
await reactorClient.get(driveId);
|
|
420
|
-
const folderId = generateId();
|
|
421
|
-
const node = (await reactorClient.execute(driveId, "main", [addFolder$1({
|
|
422
|
-
id: folderId,
|
|
423
|
-
name,
|
|
424
|
-
parentFolder
|
|
425
|
-
})])).state.global.nodes.find((node) => node.id === folderId);
|
|
426
|
-
if (!node || !isFolderNode(node)) throw new Error("There was an error adding folder");
|
|
427
|
-
return node;
|
|
428
|
-
}
|
|
429
|
-
async function deleteNode(driveId, nodeId) {
|
|
430
|
-
const { isAllowedToCreateDocuments } = getUserPermissions();
|
|
431
|
-
if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to delete documents");
|
|
432
|
-
const reactorClient = window.ph?.reactorClient;
|
|
433
|
-
if (!reactorClient) throw new Error("ReactorClient not initialized");
|
|
434
|
-
await reactorClient.drives.removeNode(driveId, nodeId);
|
|
435
|
-
}
|
|
436
|
-
async function renameNode(driveId, nodeId, name) {
|
|
437
|
-
const { isAllowedToCreateDocuments } = getUserPermissions();
|
|
438
|
-
if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to rename documents");
|
|
439
|
-
const reactorClient = window.ph?.reactorClient;
|
|
440
|
-
if (!reactorClient) throw new Error("ReactorClient not initialized");
|
|
441
|
-
if ((await reactorClient.execute(nodeId, "main", [setName({ name })])).header.name !== name) throw new Error("There was an error renaming the node");
|
|
442
|
-
const node = (await reactorClient.execute(driveId, "main", [updateNode({
|
|
443
|
-
id: nodeId,
|
|
444
|
-
name
|
|
445
|
-
})])).state.global.nodes.find((n) => n.id === nodeId);
|
|
446
|
-
if (!node) throw new Error("There was an error renaming node in the drive");
|
|
447
|
-
return node;
|
|
448
|
-
}
|
|
449
|
-
async function renameDriveNode(driveId, nodeId, name) {
|
|
450
|
-
const { isAllowedToCreateDocuments } = getUserPermissions();
|
|
451
|
-
if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to rename documents");
|
|
452
|
-
const reactorClient = window.ph?.reactorClient;
|
|
453
|
-
if (!reactorClient) throw new Error("ReactorClient not initialized");
|
|
454
|
-
if ((await reactorClient.execute(nodeId, "main", [setName({ name })])).header.name !== name) throw new Error("There was an error renaming the node");
|
|
455
|
-
await reactorClient.execute(driveId, "main", [updateNode({
|
|
456
|
-
id: nodeId,
|
|
457
|
-
name
|
|
458
|
-
})]);
|
|
459
|
-
return (await reactorClient.get(driveId)).state.global.nodes.find((n) => n.id === nodeId);
|
|
460
|
-
}
|
|
461
|
-
async function moveNodeById(args) {
|
|
462
|
-
const { driveId, srcId, targetId } = args;
|
|
463
|
-
if (!driveId || !srcId) return;
|
|
464
|
-
const { isAllowedToCreateDocuments } = getUserPermissions();
|
|
465
|
-
if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to move documents");
|
|
466
|
-
const reactorClient = window.ph?.reactorClient;
|
|
467
|
-
if (!reactorClient) throw new Error("ReactorClient not initialized");
|
|
468
|
-
const targetParentFolder = conditional(targetId, [isNot(isDefined), constant(void 0)], [isStrictEqual(driveId), constant(void 0)], constant(targetId));
|
|
469
|
-
if (isStrictEqual(targetParentFolder, srcId)) return;
|
|
470
|
-
return await reactorClient.execute(driveId, "main", [moveNode({
|
|
471
|
-
srcFolder: srcId,
|
|
472
|
-
targetParentFolder
|
|
473
|
-
})]);
|
|
474
|
-
}
|
|
475
|
-
async function moveNode$1(driveId, src, target) {
|
|
476
|
-
const { isAllowedToCreateDocuments } = getUserPermissions();
|
|
477
|
-
if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to move documents");
|
|
478
|
-
const reactorClient = window.ph?.reactorClient;
|
|
479
|
-
if (!reactorClient) throw new Error("ReactorClient not initialized");
|
|
480
|
-
return await reactorClient.execute(driveId, "main", [moveNode({
|
|
481
|
-
srcFolder: src.id,
|
|
482
|
-
targetParentFolder: target?.id
|
|
483
|
-
})]);
|
|
484
|
-
}
|
|
485
|
-
/**
|
|
486
|
-
* Duplicates a document under a new id using version-aware replay.
|
|
487
|
-
* Falls back gracefully when no upgrade manifest is registered for the document type.
|
|
488
|
-
*/
|
|
489
|
-
async function _duplicateDocument(reactor, document, newId = generateId()) {
|
|
490
|
-
const documentType = document.header.documentType;
|
|
491
|
-
const { results: allModules } = await reactor.getDocumentModelModules();
|
|
492
|
-
const modulesForType = allModules.filter((m) => m.documentModel.global.id === documentType);
|
|
493
|
-
const reducers = {};
|
|
494
|
-
for (const m of modulesForType) reducers[m.version ?? 1] = m.reducer;
|
|
495
|
-
if (Object.keys(reducers).length === 0) throw new Error(`Document model module not found for type: ${documentType}`);
|
|
496
|
-
const registry = window.ph?.reactorClientModule?.reactorModule?.documentModelRegistry;
|
|
497
|
-
let upgradeManifest;
|
|
498
|
-
if (registry) try {
|
|
499
|
-
upgradeManifest = registry.getUpgradeManifest(documentType);
|
|
500
|
-
} catch {}
|
|
501
|
-
const config = {
|
|
502
|
-
reducers,
|
|
503
|
-
upgradeManifest
|
|
504
|
-
};
|
|
505
|
-
const header = createPresignedHeader(newId, documentType);
|
|
506
|
-
return replayDocumentVersioned(document.initialState, document.operations, config, header);
|
|
507
|
-
}
|
|
508
|
-
async function copyNode$1(driveId, src, target) {
|
|
509
|
-
const reactor = window.ph?.reactorClient;
|
|
510
|
-
if (!reactor) return;
|
|
511
|
-
const { isAllowedToCreateDocuments } = getUserPermissions();
|
|
512
|
-
if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to copy documents");
|
|
513
|
-
const drive = await reactor.get(driveId);
|
|
514
|
-
const copyNodesInput = generateNodesCopy({
|
|
515
|
-
srcId: src.id,
|
|
516
|
-
targetParentFolder: target?.id,
|
|
517
|
-
targetName: src.name
|
|
518
|
-
}, () => generateId(), drive.state.global.nodes);
|
|
519
|
-
const resolvedNamesMap = /* @__PURE__ */ new Map();
|
|
520
|
-
for (const copyNodeInput of copyNodesInput) {
|
|
521
|
-
const node = drive.state.global.nodes.find((n) => n.id === copyNodeInput.srcId);
|
|
522
|
-
if (node) {
|
|
523
|
-
const resolvedName = handleTargetNameCollisions({
|
|
524
|
-
nodes: drive.state.global.nodes,
|
|
525
|
-
srcName: copyNodeInput.targetName || node.name,
|
|
526
|
-
srcKind: isFileNode(node) ? "file" : "folder",
|
|
527
|
-
targetParentFolder: copyNodeInput.targetParentFolder || null
|
|
528
|
-
});
|
|
529
|
-
resolvedNamesMap.set(copyNodeInput.targetId, resolvedName);
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
const fileNodesToCopy = copyNodesInput.filter((copyNodeInput) => {
|
|
533
|
-
const node = drive.state.global.nodes.find((node) => node.id === copyNodeInput.srcId);
|
|
534
|
-
return node !== void 0 && isFileNode(node);
|
|
535
|
-
});
|
|
536
|
-
for (const fileNodeToCopy of fileNodesToCopy) try {
|
|
537
|
-
const duplicatedDocument = await _duplicateDocument(reactor, await reactor.get(fileNodeToCopy.srcId), fileNodeToCopy.targetId);
|
|
538
|
-
const resolvedName = resolvedNamesMap.get(fileNodeToCopy.targetId);
|
|
539
|
-
if (resolvedName) duplicatedDocument.header.name = resolvedName;
|
|
540
|
-
await reactor.drives.addFile(driveId, duplicatedDocument, target?.id);
|
|
176
|
+
const writable = await (await window.showSaveFilePicker({ suggestedName: result.archiveName })).createWritable();
|
|
177
|
+
await writable.write(new Uint8Array(result.zip));
|
|
178
|
+
await writable.close();
|
|
541
179
|
} catch (e) {
|
|
542
|
-
|
|
180
|
+
if (!(e instanceof DOMException && e.name === "AbortError")) throw e;
|
|
543
181
|
}
|
|
544
|
-
return
|
|
545
|
-
}
|
|
546
|
-
//#endregion
|
|
547
|
-
//#region src/hooks/modals.ts
|
|
548
|
-
const modalEventFunctions = makePHEventFunctions("modal");
|
|
549
|
-
/** Returns the current modal */
|
|
550
|
-
const usePHModal = modalEventFunctions.useValue;
|
|
551
|
-
/** Sets the current modal */
|
|
552
|
-
const setPHModal = modalEventFunctions.setValue;
|
|
553
|
-
/** Adds an event handler for the modal */
|
|
554
|
-
const addModalEventHandler = modalEventFunctions.addEventHandler;
|
|
555
|
-
/** Shows a modal */
|
|
556
|
-
function showPHModal(modal) {
|
|
557
|
-
setPHModal(modal);
|
|
558
|
-
}
|
|
559
|
-
/** Closes the current modal */
|
|
560
|
-
function closePHModal() {
|
|
561
|
-
setPHModal(void 0);
|
|
562
|
-
}
|
|
563
|
-
/** Shows the create document modal */
|
|
564
|
-
function showCreateDocumentModal(documentType) {
|
|
565
|
-
setPHModal({
|
|
566
|
-
type: "createDocument",
|
|
567
|
-
documentType
|
|
568
|
-
});
|
|
569
|
-
}
|
|
570
|
-
/** Shows the delete node modal */
|
|
571
|
-
function showDeleteNodeModal(nodeOrId) {
|
|
572
|
-
setPHModal({
|
|
573
|
-
type: "deleteItem",
|
|
574
|
-
id: typeof nodeOrId === "string" ? nodeOrId : nodeOrId.id
|
|
575
|
-
});
|
|
182
|
+
return result;
|
|
576
183
|
}
|
|
577
184
|
//#endregion
|
|
578
185
|
//#region src/actions/drive.ts
|
|
@@ -630,11 +237,12 @@ async function addDrive(input, preferredEditor) {
|
|
|
630
237
|
icon: input.global.icon ?? null,
|
|
631
238
|
nodes: []
|
|
632
239
|
} });
|
|
240
|
+
if (input.id) driveDoc.header.id = input.id;
|
|
633
241
|
if (preferredEditor) driveDoc.header.meta = { preferredEditor };
|
|
634
242
|
return await reactorClient.create(driveDoc);
|
|
635
243
|
}
|
|
636
244
|
async function addRemoteDrive(url, driveId, options) {
|
|
637
|
-
const reactorClient = window.ph?.
|
|
245
|
+
const reactorClient = window.ph?.reactorClientModule?.client;
|
|
638
246
|
if (!reactorClient) throw new Error("ReactorClient not initialized");
|
|
639
247
|
const sync = window.ph?.reactorClientModule?.reactorModule?.syncModule?.syncManager;
|
|
640
248
|
if (!sync) throw new Error("Sync not initialized");
|
|
@@ -681,7 +289,7 @@ async function deleteDrive(driveId) {
|
|
|
681
289
|
async function renameDrive(driveId, name) {
|
|
682
290
|
const { isAllowedToCreateDocuments } = getUserPermissions();
|
|
683
291
|
if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to rename drives");
|
|
684
|
-
const reactorClient = window.ph?.
|
|
292
|
+
const reactorClient = window.ph?.reactorClientModule?.client;
|
|
685
293
|
if (!reactorClient) throw new Error("ReactorClient not initialized");
|
|
686
294
|
return await reactorClient.rename(driveId, name);
|
|
687
295
|
}
|
|
@@ -706,7 +314,7 @@ async function setDriveMetadata(driveId, metadata) {
|
|
|
706
314
|
if (!reactorClient) throw new Error("ReactorClient not initialized");
|
|
707
315
|
const actions = [];
|
|
708
316
|
if (metadata.name) actions.push(setDriveName({ name: metadata.name }));
|
|
709
|
-
if (metadata.icon !== void 0
|
|
317
|
+
if (metadata.icon !== void 0) actions.push(setDriveIcon({ icon: metadata.icon }));
|
|
710
318
|
if (actions.length === 0) return;
|
|
711
319
|
return await reactorClient.execute(driveId, "main", actions);
|
|
712
320
|
}
|
|
@@ -993,876 +601,6 @@ async function reactorGraphqlMutateDocument(documentIdentifier, ...actions) {
|
|
|
993
601
|
});
|
|
994
602
|
}
|
|
995
603
|
//#endregion
|
|
996
|
-
//#region src/hooks/config/editor.ts
|
|
997
|
-
const isExternalControlsEnabledEventFunctions = makePHEventFunctions("isExternalControlsEnabled");
|
|
998
|
-
/** Sets whether external controls are enabled for a given editor. */
|
|
999
|
-
const setIsExternalControlsEnabled = isExternalControlsEnabledEventFunctions.setValue;
|
|
1000
|
-
/** Gets whether external controls are enabled for a given editor. */
|
|
1001
|
-
const useIsExternalControlsEnabled = isExternalControlsEnabledEventFunctions.useValue;
|
|
1002
|
-
/** Adds an event handler for when the external controls enabled state changes. */
|
|
1003
|
-
const addIsExternalControlsEnabledEventHandler = isExternalControlsEnabledEventFunctions.addEventHandler;
|
|
1004
|
-
const isDragAndDropEnabledEventFunctions = makePHEventFunctions("isDragAndDropEnabled");
|
|
1005
|
-
/** Sets whether drag and drop is enabled for a given app. */
|
|
1006
|
-
const setIsDragAndDropEnabled = isDragAndDropEnabledEventFunctions.setValue;
|
|
1007
|
-
/** Gets whether drag and drop is enabled for a given app. */
|
|
1008
|
-
const useIsDragAndDropEnabled = isDragAndDropEnabledEventFunctions.useValue;
|
|
1009
|
-
/** Adds an event handler for when the drag and drop enabled state changes. */
|
|
1010
|
-
const addIsDragAndDropEnabledEventHandler = isDragAndDropEnabledEventFunctions.addEventHandler;
|
|
1011
|
-
const allowedDocumentTypesEventFunctions = makePHEventFunctions("allowedDocumentTypes");
|
|
1012
|
-
/** Sets the allowed document types for a given app. */
|
|
1013
|
-
const setAllowedDocumentTypes = allowedDocumentTypesEventFunctions.setValue;
|
|
1014
|
-
/** Defines the document types a drive supports.
|
|
1015
|
-
*
|
|
1016
|
-
* Defaults to all of the document types registered in the reactor.
|
|
1017
|
-
*/
|
|
1018
|
-
function useAllowedDocumentTypes() {
|
|
1019
|
-
return allowedDocumentTypesEventFunctions.useValue();
|
|
1020
|
-
}
|
|
1021
|
-
/** Adds an event handler for when the allowed document types for a given app changes. */
|
|
1022
|
-
const addAllowedDocumentTypesEventHandler = allowedDocumentTypesEventFunctions.addEventHandler;
|
|
1023
|
-
const phAppConfigSetters = {
|
|
1024
|
-
allowedDocumentTypes: setAllowedDocumentTypes,
|
|
1025
|
-
isDragAndDropEnabled: setIsDragAndDropEnabled
|
|
1026
|
-
};
|
|
1027
|
-
const phDocumentEditorConfigSetters = { isExternalControlsEnabled: setIsExternalControlsEnabled };
|
|
1028
|
-
const phAppConfigHooks = {
|
|
1029
|
-
allowedDocumentTypes: useAllowedDocumentTypes,
|
|
1030
|
-
isDragAndDropEnabled: useIsDragAndDropEnabled
|
|
1031
|
-
};
|
|
1032
|
-
const phDocumentEditorConfigHooks = { isExternalControlsEnabled: useIsExternalControlsEnabled };
|
|
1033
|
-
//#endregion
|
|
1034
|
-
//#region src/hooks/config/connect.ts
|
|
1035
|
-
const { useValue: useRouterBasename, setValue: setRouterBasename, addEventHandler: addRouterBasenameEventHandler } = makePHEventFunctions("routerBasename");
|
|
1036
|
-
const { useValue: useVersion, setValue: setVersion, addEventHandler: addVersionEventHandler } = makePHEventFunctions("version");
|
|
1037
|
-
const { useValue: useRequiresHardRefresh, setValue: setRequiresHardRefresh, addEventHandler: addRequiresHardRefreshEventHandler } = makePHEventFunctions("requiresHardRefresh");
|
|
1038
|
-
const { useValue: useWarnOutdatedApp, setValue: setWarnOutdatedApp, addEventHandler: addWarnOutdatedAppEventHandler } = makePHEventFunctions("warnOutdatedApp");
|
|
1039
|
-
const { useValue: useStudioMode, setValue: setStudioMode, addEventHandler: addStudioModeEventHandler } = makePHEventFunctions("studioMode");
|
|
1040
|
-
const { useValue: useBasePath, setValue: setBasePath, addEventHandler: addBasePathEventHandler } = makePHEventFunctions("basePath");
|
|
1041
|
-
const { useValue: useVersionCheckInterval, setValue: setVersionCheckInterval, addEventHandler: addVersionCheckIntervalEventHandler } = makePHEventFunctions("versionCheckInterval");
|
|
1042
|
-
const { useValue: useCliVersion, setValue: setCliVersion, addEventHandler: addCliVersionEventHandler } = makePHEventFunctions("cliVersion");
|
|
1043
|
-
const { useValue: useFileUploadOperationsChunkSize, setValue: setFileUploadOperationsChunkSize, addEventHandler: addFileUploadOperationsChunkSizeEventHandler } = makePHEventFunctions("fileUploadOperationsChunkSize");
|
|
1044
|
-
const { useValue: useIsDocumentModelSelectionSettingsEnabled, setValue: setIsDocumentModelSelectionSettingsEnabled, addEventHandler: addIsDocumentModelSelectionSettingsEnabledEventHandler } = makePHEventFunctions("isDocumentModelSelectionSettingsEnabled");
|
|
1045
|
-
const { useValue: useGaTrackingId, setValue: setGaTrackingId, addEventHandler: addGaTrackingIdEventHandler } = makePHEventFunctions("gaTrackingId");
|
|
1046
|
-
const { useValue: useDefaultDrivesUrl, setValue: setDefaultDrivesUrl, addEventHandler: addDefaultDrivesUrlEventHandler } = makePHEventFunctions("defaultDrivesUrl");
|
|
1047
|
-
const { useValue: useDrivesPreserveStrategy, setValue: setDrivesPreserveStrategy, addEventHandler: addDrivesPreserveStrategyEventHandler } = makePHEventFunctions("drivesPreserveStrategy");
|
|
1048
|
-
const { useValue: useIsLocalDrivesEnabled, setValue: setIsLocalDrivesEnabled, addEventHandler: addIsLocalDrivesEnabledEventHandler } = makePHEventFunctions("isLocalDrivesEnabled");
|
|
1049
|
-
const { useValue: useIsAddDriveEnabled, setValue: setIsAddDriveEnabled, addEventHandler: addIsAddDriveEnabledEventHandler } = makePHEventFunctions("isAddDriveEnabled");
|
|
1050
|
-
const { useValue: useIsPublicDrivesEnabled, setValue: setIsPublicDrivesEnabled, addEventHandler: addIsPublicDrivesEnabledEventHandler } = makePHEventFunctions("isPublicDrivesEnabled");
|
|
1051
|
-
const { useValue: useIsAddPublicDrivesEnabled, setValue: setIsAddPublicDrivesEnabled, addEventHandler: addIsAddPublicDrivesEnabledEventHandler } = makePHEventFunctions("isAddPublicDrivesEnabled");
|
|
1052
|
-
const { useValue: useIsDeletePublicDrivesEnabled, setValue: setIsDeletePublicDrivesEnabled, addEventHandler: addIsDeletePublicDrivesEnabledEventHandler } = makePHEventFunctions("isDeletePublicDrivesEnabled");
|
|
1053
|
-
const { useValue: useIsCloudDrivesEnabled, setValue: setIsCloudDrivesEnabled, addEventHandler: addIsCloudDrivesEnabledEventHandler } = makePHEventFunctions("isCloudDrivesEnabled");
|
|
1054
|
-
const { useValue: useIsAddCloudDrivesEnabled, setValue: setIsAddCloudDrivesEnabled, addEventHandler: addIsAddCloudDrivesEnabledEventHandler } = makePHEventFunctions("isAddCloudDrivesEnabled");
|
|
1055
|
-
const { useValue: useIsDeleteCloudDrivesEnabled, setValue: setIsDeleteCloudDrivesEnabled, addEventHandler: addIsDeleteCloudDrivesEnabledEventHandler } = makePHEventFunctions("isDeleteCloudDrivesEnabled");
|
|
1056
|
-
const { useValue: useLocalDrivesEnabled, setValue: setLocalDrivesEnabled, addEventHandler: addLocalDrivesEnabledEventHandler } = makePHEventFunctions("isLocalDrivesEnabled");
|
|
1057
|
-
const { useValue: useIsAddLocalDrivesEnabled, setValue: setIsAddLocalDrivesEnabled, addEventHandler: addIsAddLocalDrivesEnabledEventHandler } = makePHEventFunctions("isAddLocalDrivesEnabled");
|
|
1058
|
-
const { useValue: useIsDeleteLocalDrivesEnabled, setValue: setIsDeleteLocalDrivesEnabled, addEventHandler: addIsDeleteLocalDrivesEnabledEventHandler } = makePHEventFunctions("isDeleteLocalDrivesEnabled");
|
|
1059
|
-
const { useValue: useIsEditorDebugModeEnabled, setValue: setIsEditorDebugModeEnabled, addEventHandler: addIsEditorDebugModeEnabledEventHandler } = makePHEventFunctions("isEditorDebugModeEnabled");
|
|
1060
|
-
const { useValue: useIsEditorReadModeEnabled, setValue: setIsEditorReadModeEnabled, addEventHandler: addIsEditorReadModeEnabledEventHandler } = makePHEventFunctions("isEditorReadModeEnabled");
|
|
1061
|
-
const { useValue: useIsAnalyticsDatabaseWorkerEnabled, setValue: setIsAnalyticsDatabaseWorkerEnabled, addEventHandler: addIsAnalyticsDatabaseWorkerEnabledEventHandler } = makePHEventFunctions("isAnalyticsDatabaseWorkerEnabled");
|
|
1062
|
-
const { useValue: useIsDiffAnalyticsEnabled, setValue: setIsDiffAnalyticsEnabled, addEventHandler: addIsDiffAnalyticsEnabledEventHandler } = makePHEventFunctions("isDiffAnalyticsEnabled");
|
|
1063
|
-
const { useValue: useIsDriveAnalyticsEnabled, setValue: setIsDriveAnalyticsEnabled, addEventHandler: addIsDriveAnalyticsEnabledEventHandler } = makePHEventFunctions("isDriveAnalyticsEnabled");
|
|
1064
|
-
const { useValue: useRenownUrl, setValue: setRenownUrl, addEventHandler: addRenownUrlEventHandler } = makePHEventFunctions("renownUrl");
|
|
1065
|
-
const { useValue: useRenownNetworkId, setValue: setRenownNetworkId, addEventHandler: addRenownNetworkIdEventHandler } = makePHEventFunctions("renownNetworkId");
|
|
1066
|
-
const { useValue: useRenownChainId, setValue: setRenownChainId, addEventHandler: addRenownChainIdEventHandler } = makePHEventFunctions("renownChainId");
|
|
1067
|
-
const { useValue: useSentryRelease, setValue: setSentryRelease, addEventHandler: addSentryReleaseEventHandler } = makePHEventFunctions("sentryRelease");
|
|
1068
|
-
const { useValue: useSentryDsn, setValue: setSentryDsn, addEventHandler: addSentryDsnEventHandler } = makePHEventFunctions("sentryDsn");
|
|
1069
|
-
const { useValue: useSentryEnv, setValue: setSentryEnv, addEventHandler: addSentryEnvEventHandler } = makePHEventFunctions("sentryEnv");
|
|
1070
|
-
const { useValue: useIsSentryTracingEnabled, setValue: setIsSentryTracingEnabled, addEventHandler: addIsSentryTracingEnabledEventHandler } = makePHEventFunctions("isSentryTracingEnabled");
|
|
1071
|
-
const { useValue: useIsExternalProcessorsEnabled, setValue: setIsExternalProcessorsEnabled, addEventHandler: addIsExternalProcessorsEnabledEventHandler } = makePHEventFunctions("isExternalProcessorsEnabled");
|
|
1072
|
-
const { useValue: useIsExternalPackagesEnabled, setValue: setIsExternalPackagesEnabled, addEventHandler: addIsExternalPackagesEnabledEventHandler } = makePHEventFunctions("isExternalPackagesEnabled");
|
|
1073
|
-
const enabledEditorsEventFunctions = makePHEventFunctions("enabledEditors");
|
|
1074
|
-
/** Sets the enabled editors for Connect. */
|
|
1075
|
-
const setEnabledEditors = enabledEditorsEventFunctions.setValue;
|
|
1076
|
-
/** Gets the enabled editors for Connect. */
|
|
1077
|
-
const useEnabledEditors = enabledEditorsEventFunctions.useValue;
|
|
1078
|
-
/** Adds an event handler for when the enabled editors for Connect changes. */
|
|
1079
|
-
const addEnabledEditorsEventHandler = enabledEditorsEventFunctions.addEventHandler;
|
|
1080
|
-
const disabledEditorsEventFunctions = makePHEventFunctions("disabledEditors");
|
|
1081
|
-
/** Sets the disabled editors for Connect. */
|
|
1082
|
-
const setDisabledEditors = disabledEditorsEventFunctions.setValue;
|
|
1083
|
-
/** Gets the disabled editors for Connect. */
|
|
1084
|
-
const useDisabledEditors = disabledEditorsEventFunctions.useValue;
|
|
1085
|
-
/** Adds an event handler for when the disabled editors for Connect changes. */
|
|
1086
|
-
const addDisabledEditorsEventHandler = disabledEditorsEventFunctions.addEventHandler;
|
|
1087
|
-
const isRelationalProcessorsEnabled = makePHEventFunctions("isRelationalProcessorsEnabled");
|
|
1088
|
-
/** Sets the isRelationalProcessorsEnabled for Connect. */
|
|
1089
|
-
const setIsRelationalProcessorsEnabled = isRelationalProcessorsEnabled.setValue;
|
|
1090
|
-
/** Gets the isRelationalProcessorsEnabled for Connect. */
|
|
1091
|
-
const useIsRelationalProcessorsEnabled = isRelationalProcessorsEnabled.useValue;
|
|
1092
|
-
/** Adds an event handler for when the isRelationalProcessorsEnabled for Connect changes. */
|
|
1093
|
-
const addIsRelationalProcessorsEnabledEventHandler = isRelationalProcessorsEnabled.addEventHandler;
|
|
1094
|
-
const isExternalRelationalProcessorsEnabled = makePHEventFunctions("isExternalRelationalProcessorsEnabled");
|
|
1095
|
-
/** Sets the isExternalRelationalProcessorsEnabled for Connect. */
|
|
1096
|
-
const setIsExternalRelationalProcessorsEnabled = isExternalRelationalProcessorsEnabled.setValue;
|
|
1097
|
-
/** Gets the isExternalRelationalProcessorsEnabled for Connect. */
|
|
1098
|
-
const useIsExternalRelationalProcessorsEnabled = isExternalRelationalProcessorsEnabled.useValue;
|
|
1099
|
-
/** Adds an event handler for when the isExternalRelationalProcessorsEnabled for Connect changes. */
|
|
1100
|
-
const addIsExternalRelationalProcessorsEnabledEventHandler = isExternalRelationalProcessorsEnabled.addEventHandler;
|
|
1101
|
-
const isAnalyticsEnabledEventFunctions = makePHEventFunctions("isAnalyticsEnabled");
|
|
1102
|
-
/** Sets the isAnalyticsEnabled for Connect. */
|
|
1103
|
-
const setIsAnalyticsEnabled = isAnalyticsEnabledEventFunctions.setValue;
|
|
1104
|
-
/** Gets the isAnalyticsEnabled for Connect. */
|
|
1105
|
-
const useIsAnalyticsEnabled = isAnalyticsEnabledEventFunctions.useValue;
|
|
1106
|
-
/** Adds an event handler for when the isAnalyticsEnabled for Connect changes. */
|
|
1107
|
-
const addIsAnalyticsEnabledEventHandler = isAnalyticsEnabledEventFunctions.addEventHandler;
|
|
1108
|
-
const isAnalyticsExternalProcessorsEnabled = makePHEventFunctions("isAnalyticsExternalProcessorsEnabled");
|
|
1109
|
-
/** Sets the isAnalyticsExternalProcessorsEnabled for Connect. */
|
|
1110
|
-
const setIsAnalyticsExternalProcessorsEnabled = isAnalyticsExternalProcessorsEnabled.setValue;
|
|
1111
|
-
/** Gets the isAnalyticsExternalProcessorsEnabled for Connect. */
|
|
1112
|
-
const useIsAnalyticsExternalProcessorsEnabled = isAnalyticsExternalProcessorsEnabled.useValue;
|
|
1113
|
-
/** Adds an event handler for when the isAnalyticsExternalProcessorsEnabled for Connect changes. */
|
|
1114
|
-
const addIsAnalyticsExternalProcessorsEnabledEventHandler = isAnalyticsExternalProcessorsEnabled.addEventHandler;
|
|
1115
|
-
const analyticsDatabaseNameEventFunctions = makePHEventFunctions("analyticsDatabaseName");
|
|
1116
|
-
/** Sets the analytics database name for Connect. */
|
|
1117
|
-
const setAnalyticsDatabaseName = analyticsDatabaseNameEventFunctions.setValue;
|
|
1118
|
-
/** Gets the analytics database name for Connect. */
|
|
1119
|
-
const useAnalyticsDatabaseName = analyticsDatabaseNameEventFunctions.useValue;
|
|
1120
|
-
/** Adds an event handler for when the analytics database name for Connect changes. */
|
|
1121
|
-
const addAnalyticsDatabaseNameEventHandler = analyticsDatabaseNameEventFunctions.addEventHandler;
|
|
1122
|
-
const logLevelEventFunctions = makePHEventFunctions("logLevel");
|
|
1123
|
-
/** Sets the log level for Connect. */
|
|
1124
|
-
const setLogLevel = logLevelEventFunctions.setValue;
|
|
1125
|
-
/** Gets the log level for Connect. */
|
|
1126
|
-
const useLogLevel = logLevelEventFunctions.useValue;
|
|
1127
|
-
/** Adds an event handler for when the log level for Connect changes. */
|
|
1128
|
-
const addLogLevelEventHandler = logLevelEventFunctions.addEventHandler;
|
|
1129
|
-
const allowListEventFunctions = makePHEventFunctions("allowList");
|
|
1130
|
-
/** Sets the allow list for Connect. */
|
|
1131
|
-
const setAllowList = allowListEventFunctions.setValue;
|
|
1132
|
-
/** Gets the allow list for Connect. */
|
|
1133
|
-
const useAllowList = allowListEventFunctions.useValue;
|
|
1134
|
-
/** Adds an event handler for when the allow list for Connect changes. */
|
|
1135
|
-
const addAllowListEventHandler = allowListEventFunctions.addEventHandler;
|
|
1136
|
-
const nonUserConfigSetters = {
|
|
1137
|
-
routerBasename: setRouterBasename,
|
|
1138
|
-
version: setVersion,
|
|
1139
|
-
requiresHardRefresh: setRequiresHardRefresh,
|
|
1140
|
-
warnOutdatedApp: setWarnOutdatedApp,
|
|
1141
|
-
studioMode: setStudioMode,
|
|
1142
|
-
basePath: setBasePath,
|
|
1143
|
-
versionCheckInterval: setVersionCheckInterval,
|
|
1144
|
-
cliVersion: setCliVersion,
|
|
1145
|
-
fileUploadOperationsChunkSize: setFileUploadOperationsChunkSize,
|
|
1146
|
-
isDocumentModelSelectionSettingsEnabled: setIsDocumentModelSelectionSettingsEnabled,
|
|
1147
|
-
gaTrackingId: setGaTrackingId,
|
|
1148
|
-
defaultDrivesUrl: setDefaultDrivesUrl,
|
|
1149
|
-
drivesPreserveStrategy: setDrivesPreserveStrategy,
|
|
1150
|
-
isLocalDrivesEnabled: setIsLocalDrivesEnabled,
|
|
1151
|
-
isAddDriveEnabled: setIsAddDriveEnabled,
|
|
1152
|
-
isPublicDrivesEnabled: setIsPublicDrivesEnabled,
|
|
1153
|
-
isAddPublicDrivesEnabled: setIsAddPublicDrivesEnabled,
|
|
1154
|
-
isDeletePublicDrivesEnabled: setIsDeletePublicDrivesEnabled,
|
|
1155
|
-
isCloudDrivesEnabled: setIsCloudDrivesEnabled,
|
|
1156
|
-
isAddCloudDrivesEnabled: setIsAddCloudDrivesEnabled,
|
|
1157
|
-
isDeleteCloudDrivesEnabled: setIsDeleteCloudDrivesEnabled,
|
|
1158
|
-
isAddLocalDrivesEnabled: setIsAddLocalDrivesEnabled,
|
|
1159
|
-
isDeleteLocalDrivesEnabled: setIsDeleteLocalDrivesEnabled,
|
|
1160
|
-
isEditorDebugModeEnabled: setIsEditorDebugModeEnabled,
|
|
1161
|
-
isEditorReadModeEnabled: setIsEditorReadModeEnabled,
|
|
1162
|
-
isRelationalProcessorsEnabled: setIsRelationalProcessorsEnabled,
|
|
1163
|
-
isExternalRelationalProcessorsEnabled: setIsExternalRelationalProcessorsEnabled,
|
|
1164
|
-
isAnalyticsEnabled: setIsAnalyticsEnabled,
|
|
1165
|
-
analyticsDatabaseName: setAnalyticsDatabaseName,
|
|
1166
|
-
isAnalyticsExternalProcessorsEnabled: setIsAnalyticsExternalProcessorsEnabled,
|
|
1167
|
-
isAnalyticsDatabaseWorkerEnabled: setIsAnalyticsDatabaseWorkerEnabled,
|
|
1168
|
-
isDiffAnalyticsEnabled: setIsDiffAnalyticsEnabled,
|
|
1169
|
-
isDriveAnalyticsEnabled: setIsDriveAnalyticsEnabled,
|
|
1170
|
-
renownUrl: setRenownUrl,
|
|
1171
|
-
renownNetworkId: setRenownNetworkId,
|
|
1172
|
-
renownChainId: setRenownChainId,
|
|
1173
|
-
sentryRelease: setSentryRelease,
|
|
1174
|
-
sentryDsn: setSentryDsn,
|
|
1175
|
-
sentryEnv: setSentryEnv,
|
|
1176
|
-
isSentryTracingEnabled: setIsSentryTracingEnabled,
|
|
1177
|
-
isExternalProcessorsEnabled: setIsExternalProcessorsEnabled,
|
|
1178
|
-
isExternalPackagesEnabled: setIsExternalPackagesEnabled,
|
|
1179
|
-
allowList: setAllowList,
|
|
1180
|
-
logLevel: setLogLevel,
|
|
1181
|
-
disabledEditors: setDisabledEditors,
|
|
1182
|
-
enabledEditors: setEnabledEditors
|
|
1183
|
-
};
|
|
1184
|
-
const phGlobalConfigSetters = {
|
|
1185
|
-
...phAppConfigSetters,
|
|
1186
|
-
...phDocumentEditorConfigSetters,
|
|
1187
|
-
...nonUserConfigSetters
|
|
1188
|
-
};
|
|
1189
|
-
const nonUserConfigHooks = {
|
|
1190
|
-
routerBasename: useRouterBasename,
|
|
1191
|
-
version: useVersion,
|
|
1192
|
-
requiresHardRefresh: useRequiresHardRefresh,
|
|
1193
|
-
warnOutdatedApp: useWarnOutdatedApp,
|
|
1194
|
-
studioMode: useStudioMode,
|
|
1195
|
-
basePath: useBasePath,
|
|
1196
|
-
versionCheckInterval: useVersionCheckInterval,
|
|
1197
|
-
cliVersion: useCliVersion,
|
|
1198
|
-
fileUploadOperationsChunkSize: useFileUploadOperationsChunkSize,
|
|
1199
|
-
isDocumentModelSelectionSettingsEnabled: useIsDocumentModelSelectionSettingsEnabled,
|
|
1200
|
-
gaTrackingId: useGaTrackingId,
|
|
1201
|
-
defaultDrivesUrl: useDefaultDrivesUrl,
|
|
1202
|
-
drivesPreserveStrategy: useDrivesPreserveStrategy,
|
|
1203
|
-
isAddDriveEnabled: useIsAddDriveEnabled,
|
|
1204
|
-
isPublicDrivesEnabled: useIsPublicDrivesEnabled,
|
|
1205
|
-
isAddPublicDrivesEnabled: useIsAddPublicDrivesEnabled,
|
|
1206
|
-
isDeletePublicDrivesEnabled: useIsDeletePublicDrivesEnabled,
|
|
1207
|
-
isCloudDrivesEnabled: useIsCloudDrivesEnabled,
|
|
1208
|
-
isAddCloudDrivesEnabled: useIsAddCloudDrivesEnabled,
|
|
1209
|
-
isDeleteCloudDrivesEnabled: useIsDeleteCloudDrivesEnabled,
|
|
1210
|
-
isLocalDrivesEnabled: useIsLocalDrivesEnabled,
|
|
1211
|
-
isAddLocalDrivesEnabled: useIsAddLocalDrivesEnabled,
|
|
1212
|
-
isDeleteLocalDrivesEnabled: useIsDeleteLocalDrivesEnabled,
|
|
1213
|
-
isEditorDebugModeEnabled: useIsEditorDebugModeEnabled,
|
|
1214
|
-
isEditorReadModeEnabled: useIsEditorReadModeEnabled,
|
|
1215
|
-
isAnalyticsDatabaseWorkerEnabled: useIsAnalyticsDatabaseWorkerEnabled,
|
|
1216
|
-
isDiffAnalyticsEnabled: useIsDiffAnalyticsEnabled,
|
|
1217
|
-
isDriveAnalyticsEnabled: useIsDriveAnalyticsEnabled,
|
|
1218
|
-
renownUrl: useRenownUrl,
|
|
1219
|
-
renownNetworkId: useRenownNetworkId,
|
|
1220
|
-
renownChainId: useRenownChainId,
|
|
1221
|
-
sentryRelease: useSentryRelease,
|
|
1222
|
-
sentryDsn: useSentryDsn,
|
|
1223
|
-
sentryEnv: useSentryEnv,
|
|
1224
|
-
isSentryTracingEnabled: useIsSentryTracingEnabled,
|
|
1225
|
-
isExternalProcessorsEnabled: useIsExternalProcessorsEnabled,
|
|
1226
|
-
isExternalPackagesEnabled: useIsExternalPackagesEnabled,
|
|
1227
|
-
allowList: useAllowList,
|
|
1228
|
-
isAnalyticsEnabled: useIsAnalyticsEnabled,
|
|
1229
|
-
isAnalyticsExternalProcessorsEnabled: useIsAnalyticsExternalProcessorsEnabled,
|
|
1230
|
-
isRelationalProcessorsEnabled: useIsRelationalProcessorsEnabled,
|
|
1231
|
-
isExternalRelationalProcessorsEnabled: useIsExternalRelationalProcessorsEnabled,
|
|
1232
|
-
analyticsDatabaseName: useAnalyticsDatabaseName,
|
|
1233
|
-
logLevel: useLogLevel,
|
|
1234
|
-
disabledEditors: useDisabledEditors,
|
|
1235
|
-
enabledEditors: useEnabledEditors
|
|
1236
|
-
};
|
|
1237
|
-
const phGlobalConfigHooks = {
|
|
1238
|
-
...phAppConfigHooks,
|
|
1239
|
-
...phDocumentEditorConfigHooks,
|
|
1240
|
-
...nonUserConfigHooks
|
|
1241
|
-
};
|
|
1242
|
-
//#endregion
|
|
1243
|
-
//#region src/hooks/attachment-service.ts
|
|
1244
|
-
const attachmentServiceEventFunctions = makePHEventFunctions("attachmentService");
|
|
1245
|
-
/** Returns the attachment service from window.ph */
|
|
1246
|
-
const useAttachmentService = attachmentServiceEventFunctions.useValue;
|
|
1247
|
-
/** Sets the attachment service on window.ph */
|
|
1248
|
-
const setAttachmentService = attachmentServiceEventFunctions.setValue;
|
|
1249
|
-
/** Registers the attachmentService window event handler */
|
|
1250
|
-
const addAttachmentServiceEventHandler = attachmentServiceEventFunctions.addEventHandler;
|
|
1251
|
-
//#endregion
|
|
1252
|
-
//#region src/hooks/features.ts
|
|
1253
|
-
const featuresEventFunctions = makePHEventFunctions("features");
|
|
1254
|
-
const useFeatures = featuresEventFunctions.useValue;
|
|
1255
|
-
const setFeatures = featuresEventFunctions.setValue;
|
|
1256
|
-
const addFeaturesEventHandler = featuresEventFunctions.addEventHandler;
|
|
1257
|
-
//#endregion
|
|
1258
|
-
//#region src/utils/url.ts
|
|
1259
|
-
function resolveUrlPathname(path) {
|
|
1260
|
-
return new URL(path.replace(/^\/+/, ""), window.location.origin + (window.ph?.basePath ?? "/")).pathname;
|
|
1261
|
-
}
|
|
1262
|
-
/** Returns the current path without the base path */
|
|
1263
|
-
function getPathWithoutBase(path) {
|
|
1264
|
-
const basePath = window.ph?.basePath ?? "/";
|
|
1265
|
-
return path.replace(basePath, basePath.endsWith("/") ? "/" : "");
|
|
1266
|
-
}
|
|
1267
|
-
/** Makes a URL component for a drive. */
|
|
1268
|
-
function makeDriveUrlComponent(drive) {
|
|
1269
|
-
if (!drive) return "";
|
|
1270
|
-
return `/d/${slug(drive.header.slug)}`;
|
|
1271
|
-
}
|
|
1272
|
-
/** Makes a URL component for a node. */
|
|
1273
|
-
function makeNodeSlug(node) {
|
|
1274
|
-
if (!node) return "";
|
|
1275
|
-
const nodeName = node.name;
|
|
1276
|
-
if (!nodeName) return slug(node.id);
|
|
1277
|
-
return slug(`${nodeName}-${node.id}`);
|
|
1278
|
-
}
|
|
1279
|
-
/** Extracts the node slug from a path.
|
|
1280
|
-
*
|
|
1281
|
-
* The path is expected to be in the format `/d/<drive-slug>/<node-slug>`.
|
|
1282
|
-
*/
|
|
1283
|
-
function extractNodeSlugFromPath(path) {
|
|
1284
|
-
const currentPath = getPathWithoutBase(path);
|
|
1285
|
-
return /^\/d\/[^/]+\/([^/]+)$/.exec(currentPath)?.[1];
|
|
1286
|
-
}
|
|
1287
|
-
/** Finds a UUID in a string, used for extracting node ids from node slugs in the URL. */
|
|
1288
|
-
function findUuid(input) {
|
|
1289
|
-
if (!input) return void 0;
|
|
1290
|
-
return /\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b/.exec(input)?.[0];
|
|
1291
|
-
}
|
|
1292
|
-
function extractNodeIdFromSlug(nodeSlug) {
|
|
1293
|
-
return findUuid(nodeSlug);
|
|
1294
|
-
}
|
|
1295
|
-
function extractNodeIdFromPath(path) {
|
|
1296
|
-
return extractNodeIdFromSlug(extractNodeSlugFromPath(path));
|
|
1297
|
-
}
|
|
1298
|
-
/** Extracts the drive slug from a path.
|
|
1299
|
-
* Used for extracting drive ids from drive slugs in the URL.
|
|
1300
|
-
* Expects the path to be in the format `/d/<drive-slug>`.
|
|
1301
|
-
*/
|
|
1302
|
-
function extractDriveSlugFromPath(path) {
|
|
1303
|
-
const currentPath = getPathWithoutBase(path);
|
|
1304
|
-
return /^\/d\/([^/]+)/.exec(currentPath)?.[1] ?? "";
|
|
1305
|
-
}
|
|
1306
|
-
function extractDriveIdFromSlug(driveSlug) {
|
|
1307
|
-
return findUuid(driveSlug);
|
|
1308
|
-
}
|
|
1309
|
-
function extractDriveIdFromPath(path) {
|
|
1310
|
-
return extractDriveIdFromSlug(extractDriveSlugFromPath(path));
|
|
1311
|
-
}
|
|
1312
|
-
/**
|
|
1313
|
-
* Creates a URL string with the given pathname while preserving existing query parameters.
|
|
1314
|
-
*/
|
|
1315
|
-
function createUrlWithPreservedParams(pathname) {
|
|
1316
|
-
const search = window.location.search;
|
|
1317
|
-
return search ? `${pathname}${search}` : pathname;
|
|
1318
|
-
}
|
|
1319
|
-
//#endregion
|
|
1320
|
-
//#region src/hooks/drives.ts
|
|
1321
|
-
const drivesEventFunctions = makePHEventFunctions("drives");
|
|
1322
|
-
/** Returns all of the drives in the reactor */
|
|
1323
|
-
const useDrives = drivesEventFunctions.useValue;
|
|
1324
|
-
/** Sets the drives in the reactor */
|
|
1325
|
-
const setDrives = drivesEventFunctions.setValue;
|
|
1326
|
-
/** Adds an event handler for the drives */
|
|
1327
|
-
const addDrivesEventHandler = drivesEventFunctions.addEventHandler;
|
|
1328
|
-
//#endregion
|
|
1329
|
-
//#region src/hooks/set-selected-node.ts
|
|
1330
|
-
const selectedNodeIdEventFunctions = makePHEventFunctions("selectedNodeId");
|
|
1331
|
-
const useSelectedNodeId = selectedNodeIdEventFunctions.useValue;
|
|
1332
|
-
const setSelectedNodeId = selectedNodeIdEventFunctions.setValue;
|
|
1333
|
-
const addSelectedNodeIdEventHandler = selectedNodeIdEventFunctions.addEventHandler;
|
|
1334
|
-
/** Sets the selected node (file or folder). */
|
|
1335
|
-
function setSelectedNode(nodeOrNodeSlug) {
|
|
1336
|
-
const nodeSlug = typeof nodeOrNodeSlug === "string" ? nodeOrNodeSlug : makeNodeSlug(nodeOrNodeSlug);
|
|
1337
|
-
setSelectedNodeId(extractNodeIdFromSlug(nodeSlug));
|
|
1338
|
-
const driveSlugFromPath = extractDriveSlugFromPath(window.location.pathname);
|
|
1339
|
-
if (!driveSlugFromPath) return;
|
|
1340
|
-
if (!nodeSlug) {
|
|
1341
|
-
const pathname = resolveUrlPathname(`/d/${driveSlugFromPath}`);
|
|
1342
|
-
if (pathname === window.location.pathname) return;
|
|
1343
|
-
window.history.pushState(null, "", createUrlWithPreservedParams(pathname));
|
|
1344
|
-
return;
|
|
1345
|
-
}
|
|
1346
|
-
const pathname = resolveUrlPathname(`/d/${driveSlugFromPath}/${nodeSlug}`);
|
|
1347
|
-
if (pathname === window.location.pathname) return;
|
|
1348
|
-
window.history.pushState(null, "", createUrlWithPreservedParams(pathname));
|
|
1349
|
-
}
|
|
1350
|
-
function addResetSelectedNodeEventHandler() {
|
|
1351
|
-
window.addEventListener("ph:selectedDriveIdUpdated", () => {
|
|
1352
|
-
setSelectedNodeId(void 0);
|
|
1353
|
-
});
|
|
1354
|
-
}
|
|
1355
|
-
function addSetSelectedNodeOnPopStateEventHandler() {
|
|
1356
|
-
window.addEventListener("popstate", () => {
|
|
1357
|
-
const pathname = window.location.pathname;
|
|
1358
|
-
const nodeSlug = extractNodeSlugFromPath(pathname);
|
|
1359
|
-
if (extractNodeIdFromSlug(nodeSlug) !== window.ph?.selectedNodeId) setSelectedNode(nodeSlug);
|
|
1360
|
-
});
|
|
1361
|
-
}
|
|
1362
|
-
//#endregion
|
|
1363
|
-
//#region src/hooks/selected-drive.ts
|
|
1364
|
-
const selectedDriveIdEventFunctions = makePHEventFunctions("selectedDriveId");
|
|
1365
|
-
/** Returns the selected drive id */
|
|
1366
|
-
const useSelectedDriveId = selectedDriveIdEventFunctions.useValue;
|
|
1367
|
-
/** Sets the selected drive id */
|
|
1368
|
-
const setSelectedDriveId = selectedDriveIdEventFunctions.setValue;
|
|
1369
|
-
/** Adds an event handler for the selected drive id */
|
|
1370
|
-
const addSelectedDriveIdEventHandler = selectedDriveIdEventFunctions.addEventHandler;
|
|
1371
|
-
/** Returns the selected drive */
|
|
1372
|
-
function useSelectedDrive() {
|
|
1373
|
-
const drive = useSelectedDriveSafe();
|
|
1374
|
-
if (!drive[0]) throw new Error("There is no drive selected. Did you mean to call 'useSelectedDriveSafe'?");
|
|
1375
|
-
return drive;
|
|
1376
|
-
}
|
|
1377
|
-
/** Returns the selected drive, or undefined if no drive is selected */
|
|
1378
|
-
function useSelectedDriveSafe() {
|
|
1379
|
-
const selectedDriveId = useSelectedDriveId();
|
|
1380
|
-
const selectedDrive = useDrives()?.find((drive) => drive.header.id === selectedDriveId);
|
|
1381
|
-
const [drive, dispatch] = useDispatch(selectedDrive);
|
|
1382
|
-
if (!selectedDrive) return [void 0, void 0];
|
|
1383
|
-
return [drive, dispatch];
|
|
1384
|
-
}
|
|
1385
|
-
function setSelectedDrive(driveOrDriveSlug) {
|
|
1386
|
-
const driveSlug = typeof driveOrDriveSlug === "string" ? driveOrDriveSlug : driveOrDriveSlug?.header.slug;
|
|
1387
|
-
const drives = window.ph?.drives;
|
|
1388
|
-
const driveId = (typeof driveOrDriveSlug === "object" && driveOrDriveSlug !== null ? driveOrDriveSlug : drives?.find((d) => d.header.slug === driveSlug))?.header.id;
|
|
1389
|
-
if (!driveId && driveSlug && extractDriveSlugFromPath(window.location.pathname) === driveSlug) {
|
|
1390
|
-
if (window.ph?.selectedDriveId) setSelectedDriveId(void 0);
|
|
1391
|
-
deferDriveSelection(driveSlug);
|
|
1392
|
-
return;
|
|
1393
|
-
}
|
|
1394
|
-
cancelPendingDriveSelection();
|
|
1395
|
-
setSelectedDriveId(driveId);
|
|
1396
|
-
if (!driveId) {
|
|
1397
|
-
const pathname = resolveUrlPathname("/");
|
|
1398
|
-
if (pathname === window.location.pathname) return;
|
|
1399
|
-
window.history.pushState(null, "", createUrlWithPreservedParams(pathname));
|
|
1400
|
-
return;
|
|
1401
|
-
}
|
|
1402
|
-
const pathname = resolveUrlPathname(`/d/${driveSlug}`);
|
|
1403
|
-
if (pathname === window.location.pathname) return;
|
|
1404
|
-
window.history.pushState(null, "", createUrlWithPreservedParams(pathname));
|
|
1405
|
-
}
|
|
1406
|
-
const DEFERRED_DRIVE_TICK_MS = 2e3;
|
|
1407
|
-
const DEFERRED_DRIVE_MAX_WAIT_MS = 15e3;
|
|
1408
|
-
function isInitialSyncInFlight() {
|
|
1409
|
-
const remotes = window.ph?.reactorClientModule?.reactorModule?.syncModule?.syncManager?.list();
|
|
1410
|
-
if (!remotes?.length) return false;
|
|
1411
|
-
return remotes.some((remote) => {
|
|
1412
|
-
try {
|
|
1413
|
-
const snapshot = remote.channel.getConnectionState();
|
|
1414
|
-
return snapshot.receivingPages || !snapshot.lastSuccessUtcMs && snapshot.state !== "error";
|
|
1415
|
-
} catch {
|
|
1416
|
-
return false;
|
|
1417
|
-
}
|
|
1418
|
-
});
|
|
1419
|
-
}
|
|
1420
|
-
let pendingHandler;
|
|
1421
|
-
let pendingTimeout;
|
|
1422
|
-
function cancelPendingDriveSelection() {
|
|
1423
|
-
if (pendingHandler) {
|
|
1424
|
-
window.removeEventListener("ph:drivesUpdated", pendingHandler);
|
|
1425
|
-
pendingHandler = void 0;
|
|
1426
|
-
}
|
|
1427
|
-
if (pendingTimeout) {
|
|
1428
|
-
clearTimeout(pendingTimeout);
|
|
1429
|
-
pendingTimeout = void 0;
|
|
1430
|
-
}
|
|
1431
|
-
}
|
|
1432
|
-
function deferDriveSelection(driveSlug) {
|
|
1433
|
-
cancelPendingDriveSelection();
|
|
1434
|
-
const nodeSlug = extractNodeSlugFromPath(window.location.pathname);
|
|
1435
|
-
const handler = () => {
|
|
1436
|
-
if (!window.ph?.drives?.find((d) => d.header.slug === driveSlug)) return;
|
|
1437
|
-
cancelPendingDriveSelection();
|
|
1438
|
-
setSelectedDrive(driveSlug);
|
|
1439
|
-
setSelectedNode(nodeSlug);
|
|
1440
|
-
};
|
|
1441
|
-
pendingHandler = handler;
|
|
1442
|
-
window.addEventListener("ph:drivesUpdated", handler);
|
|
1443
|
-
const deadline = Date.now() + DEFERRED_DRIVE_MAX_WAIT_MS;
|
|
1444
|
-
const scheduleTick = () => {
|
|
1445
|
-
pendingTimeout = setTimeout(() => {
|
|
1446
|
-
if (Date.now() < deadline && isInitialSyncInFlight()) {
|
|
1447
|
-
scheduleTick();
|
|
1448
|
-
return;
|
|
1449
|
-
}
|
|
1450
|
-
cancelPendingDriveSelection();
|
|
1451
|
-
const pathname = resolveUrlPathname("/");
|
|
1452
|
-
if (pathname === window.location.pathname) return;
|
|
1453
|
-
window.history.pushState(null, "", createUrlWithPreservedParams(pathname));
|
|
1454
|
-
}, DEFERRED_DRIVE_TICK_MS);
|
|
1455
|
-
};
|
|
1456
|
-
scheduleTick();
|
|
1457
|
-
}
|
|
1458
|
-
function addSetSelectedDriveOnPopStateEventHandler() {
|
|
1459
|
-
window.addEventListener("popstate", () => {
|
|
1460
|
-
const pathname = window.location.pathname;
|
|
1461
|
-
const driveId = extractDriveIdFromPath(pathname);
|
|
1462
|
-
if (driveId !== window.ph?.selectedDriveId) setSelectedDrive(driveId);
|
|
1463
|
-
});
|
|
1464
|
-
}
|
|
1465
|
-
//#endregion
|
|
1466
|
-
//#region src/hooks/use-drop-target.ts
|
|
1467
|
-
function useDropTarget() {
|
|
1468
|
-
const [isDropTarget, setIsDropTarget] = useState(false);
|
|
1469
|
-
const isDragAndDropEnabled = useIsDragAndDropEnabled();
|
|
1470
|
-
const targetSetter = funnel(() => setIsDropTarget(true), {
|
|
1471
|
-
triggerAt: "start",
|
|
1472
|
-
minQuietPeriodMs: 100
|
|
1473
|
-
});
|
|
1474
|
-
const targetUnsetter = funnel(() => setIsDropTarget(false), {
|
|
1475
|
-
triggerAt: "start",
|
|
1476
|
-
minQuietPeriodMs: 100
|
|
1477
|
-
});
|
|
1478
|
-
function setTarget() {
|
|
1479
|
-
if (!isDragAndDropEnabled) return;
|
|
1480
|
-
targetUnsetter.cancel();
|
|
1481
|
-
targetSetter.call();
|
|
1482
|
-
}
|
|
1483
|
-
function unsetTarget() {
|
|
1484
|
-
if (!isDragAndDropEnabled) return;
|
|
1485
|
-
targetSetter.cancel();
|
|
1486
|
-
targetUnsetter.call();
|
|
1487
|
-
}
|
|
1488
|
-
return {
|
|
1489
|
-
isDropTarget,
|
|
1490
|
-
setTarget,
|
|
1491
|
-
unsetTarget
|
|
1492
|
-
};
|
|
1493
|
-
}
|
|
1494
|
-
//#endregion
|
|
1495
|
-
//#region src/hooks/node-drag-and-drop.ts
|
|
1496
|
-
const draggingNodeEventFunctions = makePHEventFunctions("draggingNode");
|
|
1497
|
-
const useDraggingNode = draggingNodeEventFunctions.useValue;
|
|
1498
|
-
const setDraggingNode = draggingNodeEventFunctions.setValue;
|
|
1499
|
-
const addDraggingNodeEventHandler = draggingNodeEventFunctions.addEventHandler;
|
|
1500
|
-
const draggingNodeSetter = funnel((node) => setDraggingNode(node), {
|
|
1501
|
-
reducer: (_, newNode) => newNode,
|
|
1502
|
-
triggerAt: "start",
|
|
1503
|
-
minQuietPeriodMs: 100
|
|
1504
|
-
});
|
|
1505
|
-
const draggingNodeUnsetter = funnel(() => setDraggingNode(void 0), {
|
|
1506
|
-
triggerAt: "start",
|
|
1507
|
-
minQuietPeriodMs: 100
|
|
1508
|
-
});
|
|
1509
|
-
function setDragging(node) {
|
|
1510
|
-
draggingNodeUnsetter.cancel();
|
|
1511
|
-
draggingNodeSetter.call(node);
|
|
1512
|
-
}
|
|
1513
|
-
function unsetDragging() {
|
|
1514
|
-
draggingNodeSetter.cancel();
|
|
1515
|
-
draggingNodeUnsetter.call();
|
|
1516
|
-
}
|
|
1517
|
-
const isNodeDrag = (params) => conditional(params, [({ srcId }) => isNot(isTruthy)(srcId), constant(false)], [({ driveId }) => isNot(isTruthy)(driveId), constant(false)], [({ driveId, srcId }) => isStrictEqual(driveId, srcId), constant(false)], constant(true));
|
|
1518
|
-
function useDragNode(args) {
|
|
1519
|
-
const { srcId, parentId } = args;
|
|
1520
|
-
const driveId = useSelectedDriveId();
|
|
1521
|
-
const draggingNodeId = useDraggingNode()?.srcId;
|
|
1522
|
-
const params = {
|
|
1523
|
-
driveId,
|
|
1524
|
-
srcId,
|
|
1525
|
-
parentId
|
|
1526
|
-
};
|
|
1527
|
-
const draggable = isNodeDrag(params);
|
|
1528
|
-
const isDragging = allPass({
|
|
1529
|
-
srcId,
|
|
1530
|
-
draggingNodeId
|
|
1531
|
-
}, [
|
|
1532
|
-
() => draggable,
|
|
1533
|
-
({ srcId }) => isString(srcId),
|
|
1534
|
-
({ draggingNodeId }) => isString(draggingNodeId),
|
|
1535
|
-
({ srcId, draggingNodeId }) => isStrictEqual(srcId, draggingNodeId)
|
|
1536
|
-
]);
|
|
1537
|
-
const onDragStart = () => {
|
|
1538
|
-
if (!draggable) return;
|
|
1539
|
-
setDragging(params);
|
|
1540
|
-
};
|
|
1541
|
-
const onDragEnd = () => {
|
|
1542
|
-
if (!draggable) return;
|
|
1543
|
-
unsetDragging();
|
|
1544
|
-
};
|
|
1545
|
-
return {
|
|
1546
|
-
isDragging,
|
|
1547
|
-
draggable,
|
|
1548
|
-
onDragStart,
|
|
1549
|
-
onDragEnd
|
|
1550
|
-
};
|
|
1551
|
-
}
|
|
1552
|
-
const isNodeDrop = (params) => conditional(params, [({ srcId }) => isNot(isTruthy)(srcId), constant(false)], [({ driveId }) => isNot(isDefined)(driveId), constant(false)], [({ srcId, targetId }) => isStrictEqual(srcId, targetId), constant(false)], [({ driveId, parentId, targetId }) => isNot(isTruthy)(parentId) && isStrictEqual(targetId, driveId), constant(false)], [({ targetId, parentId }) => isStrictEqual(targetId, parentId), constant(false)], constant(true));
|
|
1553
|
-
function useDropNode(targetId) {
|
|
1554
|
-
const driveId = useSelectedDriveId();
|
|
1555
|
-
const { srcId, parentId } = useDraggingNode() ?? {};
|
|
1556
|
-
const { isDropTarget, setTarget, unsetTarget } = useDropTarget();
|
|
1557
|
-
const params = {
|
|
1558
|
-
driveId,
|
|
1559
|
-
parentId,
|
|
1560
|
-
targetId,
|
|
1561
|
-
srcId
|
|
1562
|
-
};
|
|
1563
|
-
function handleNodeDrop(event, cb) {
|
|
1564
|
-
if (!isNodeDrop(params)) return;
|
|
1565
|
-
event.preventDefault();
|
|
1566
|
-
event.stopPropagation();
|
|
1567
|
-
cb?.();
|
|
1568
|
-
}
|
|
1569
|
-
const onDragEnter = (event) => handleNodeDrop(event);
|
|
1570
|
-
const onDragOver = (event) => handleNodeDrop(event, once(setTarget));
|
|
1571
|
-
const onDragLeave = (event) => handleNodeDrop(event, once(unsetTarget));
|
|
1572
|
-
const onDrop = (event) => handleNodeDrop(event, once(() => {
|
|
1573
|
-
unsetDragging();
|
|
1574
|
-
unsetTarget();
|
|
1575
|
-
moveNodeById(params).catch(console.error);
|
|
1576
|
-
}));
|
|
1577
|
-
return {
|
|
1578
|
-
isDropTarget,
|
|
1579
|
-
onDragEnter,
|
|
1580
|
-
onDragOver,
|
|
1581
|
-
onDragLeave,
|
|
1582
|
-
onDrop
|
|
1583
|
-
};
|
|
1584
|
-
}
|
|
1585
|
-
//#endregion
|
|
1586
|
-
//#region src/hooks/graphql-reactor-client.ts
|
|
1587
|
-
const graphQLReactorClientEventFunctions = makePHEventFunctions("reactorGraphQLClient");
|
|
1588
|
-
const useGraphQLReactorClient = graphQLReactorClientEventFunctions.useValue;
|
|
1589
|
-
const setGraphQLReactorClient = graphQLReactorClientEventFunctions.setValue;
|
|
1590
|
-
const addGraphQLReactorClientEventHandler = graphQLReactorClientEventFunctions.addEventHandler;
|
|
1591
|
-
//#endregion
|
|
1592
|
-
//#region src/hooks/package-discovery.ts
|
|
1593
|
-
const packageDiscoveryFunctions = makePHEventFunctions("packageDiscoveryService");
|
|
1594
|
-
const usePackageDiscoveryService = packageDiscoveryFunctions.useValue;
|
|
1595
|
-
const setPackageDiscoveryService = packageDiscoveryFunctions.setValue;
|
|
1596
|
-
const addPackageDiscoveryServiceEventHandler = packageDiscoveryFunctions.addEventHandler;
|
|
1597
|
-
//#endregion
|
|
1598
|
-
//#region src/hooks/reactor.ts
|
|
1599
|
-
const reactorClientModuleEventFunctions = makePHEventFunctions("reactorClientModule");
|
|
1600
|
-
const reactorClientEventFunctions = makePHEventFunctions("reactorClient");
|
|
1601
|
-
/** Returns the reactor client module (in-process or worker-backed) */
|
|
1602
|
-
const useReactorClientModule = reactorClientModuleEventFunctions.useValue;
|
|
1603
|
-
/** Sets the reactor client module */
|
|
1604
|
-
const setReactorClientModule = reactorClientModuleEventFunctions.setValue;
|
|
1605
|
-
/** Adds an event handler for the reactor client module */
|
|
1606
|
-
const addReactorClientModuleEventHandler = reactorClientModuleEventFunctions.addEventHandler;
|
|
1607
|
-
/** Returns the reactor client */
|
|
1608
|
-
const useReactorClient = reactorClientEventFunctions.useValue;
|
|
1609
|
-
/** Sets the reactor client */
|
|
1610
|
-
const setReactorClient = reactorClientEventFunctions.setValue;
|
|
1611
|
-
/** Adds an event handler for the reactor client */
|
|
1612
|
-
const addReactorClientEventHandler = reactorClientEventFunctions.addEventHandler;
|
|
1613
|
-
const useSync = () => useReactorClientModule()?.reactorModule?.syncModule?.syncManager;
|
|
1614
|
-
const useSyncList = () => {
|
|
1615
|
-
return useSync()?.list() ?? [];
|
|
1616
|
-
};
|
|
1617
|
-
const useModelRegistry = () => useReactorClientModule()?.reactorModule?.documentModelRegistry;
|
|
1618
|
-
const useDatabase = () => {
|
|
1619
|
-
const module = useReactorClientModule();
|
|
1620
|
-
return module?.kind === "browser" ? module.reactorModule?.database : void 0;
|
|
1621
|
-
};
|
|
1622
|
-
const usePGlite = () => {
|
|
1623
|
-
const module = useReactorClientModule();
|
|
1624
|
-
return module?.kind === "browser" ? module.reactorModule?.pg : void 0;
|
|
1625
|
-
};
|
|
1626
|
-
//#endregion
|
|
1627
|
-
//#region src/hooks/revision-history.ts
|
|
1628
|
-
const revisionHistoryEventFunctions = makePHEventFunctions("revisionHistoryVisible");
|
|
1629
|
-
/** Returns whether revision history is visible */
|
|
1630
|
-
const useRevisionHistoryVisible = revisionHistoryEventFunctions.useValue;
|
|
1631
|
-
/** Sets revision history visibility */
|
|
1632
|
-
const setRevisionHistoryVisible = revisionHistoryEventFunctions.setValue;
|
|
1633
|
-
/** Adds event handler for revision history visibility */
|
|
1634
|
-
const addRevisionHistoryVisibleEventHandler = revisionHistoryEventFunctions.addEventHandler;
|
|
1635
|
-
/** Shows the revision history */
|
|
1636
|
-
function showRevisionHistory() {
|
|
1637
|
-
setRevisionHistoryVisible(true);
|
|
1638
|
-
}
|
|
1639
|
-
/** Hides the revision history */
|
|
1640
|
-
function hideRevisionHistory() {
|
|
1641
|
-
setRevisionHistoryVisible(false);
|
|
1642
|
-
}
|
|
1643
|
-
//#endregion
|
|
1644
|
-
//#region src/utils/nodes.ts
|
|
1645
|
-
/** Sorts nodes by name. */
|
|
1646
|
-
function sortNodesByName(nodes) {
|
|
1647
|
-
return nodes.toSorted((a, b) => a.name.localeCompare(b.name));
|
|
1648
|
-
}
|
|
1649
|
-
/** Returns whether a node is a file. */
|
|
1650
|
-
function isFileNodeKind(node) {
|
|
1651
|
-
if (!node) return false;
|
|
1652
|
-
return node.kind.toUpperCase() === "FILE";
|
|
1653
|
-
}
|
|
1654
|
-
/** Returns whether a node is a folder. */
|
|
1655
|
-
function isFolderNodeKind(node) {
|
|
1656
|
-
if (!node) return false;
|
|
1657
|
-
return node.kind.toUpperCase() === "FOLDER";
|
|
1658
|
-
}
|
|
1659
|
-
//#endregion
|
|
1660
|
-
//#region src/hooks/items-in-selected-drive.ts
|
|
1661
|
-
/** Returns the nodes in the selected drive. */
|
|
1662
|
-
function useNodesInSelectedDrive() {
|
|
1663
|
-
const [selectedDrive] = useSelectedDriveSafe();
|
|
1664
|
-
return selectedDrive?.state.global.nodes;
|
|
1665
|
-
}
|
|
1666
|
-
/** Returns the file nodes in the selected drive. */
|
|
1667
|
-
function useFileNodesInSelectedDrive() {
|
|
1668
|
-
return useNodesInSelectedDrive()?.filter((n) => isFileNodeKind(n));
|
|
1669
|
-
}
|
|
1670
|
-
/** Returns the folder nodes in the selected drive. */
|
|
1671
|
-
function useFolderNodesInSelectedDrive() {
|
|
1672
|
-
return useNodesInSelectedDrive()?.filter((n) => isFolderNodeKind(n));
|
|
1673
|
-
}
|
|
1674
|
-
/** Returns the documents in the selected drive. */
|
|
1675
|
-
function useDocumentsInSelectedDrive() {
|
|
1676
|
-
const fileNodeIds = useFileNodesInSelectedDrive()?.map((node) => node.id);
|
|
1677
|
-
return useDocumentsByIds(fileNodeIds);
|
|
1678
|
-
}
|
|
1679
|
-
/** Returns the document types supported by the selected drive, as defined by the document model documents present in the drive */
|
|
1680
|
-
function useDocumentTypesInSelectedDrive() {
|
|
1681
|
-
return (useDocumentsInSelectedDrive()?.filter(isDocumentModelDocument))?.map((doc) => doc.state.global.id);
|
|
1682
|
-
}
|
|
1683
|
-
function isDocumentModelDocument(document) {
|
|
1684
|
-
return document.header.documentType === "powerhouse/document-model";
|
|
1685
|
-
}
|
|
1686
|
-
//#endregion
|
|
1687
|
-
//#region src/hooks/selected-node.ts
|
|
1688
|
-
/** Returns the selected node. */
|
|
1689
|
-
function useSelectedNode() {
|
|
1690
|
-
const selectedNodeId = useSelectedNodeId();
|
|
1691
|
-
return useNodesInSelectedDrive()?.find((n) => n.id === selectedNodeId);
|
|
1692
|
-
}
|
|
1693
|
-
//#endregion
|
|
1694
|
-
//#region src/hooks/selected-timeline-item.ts
|
|
1695
|
-
const selectedTimelineItemEventFunctions = makePHEventFunctions("selectedTimelineItem");
|
|
1696
|
-
/** Returns the selected timeline item */
|
|
1697
|
-
const useSelectedTimelineItem = selectedTimelineItemEventFunctions.useValue;
|
|
1698
|
-
/** Sets the selected timeline item */
|
|
1699
|
-
const setSelectedTimelineItem = selectedTimelineItemEventFunctions.setValue;
|
|
1700
|
-
/** Adds event handler for selected timeline item */
|
|
1701
|
-
const addSelectedTimelineItemEventHandler = selectedTimelineItemEventFunctions.addEventHandler;
|
|
1702
|
-
//#endregion
|
|
1703
|
-
//#region src/hooks/timeline-revision.ts
|
|
1704
|
-
const selectedTimelineRevisionEventFunctions = makePHEventFunctions("selectedTimelineRevision");
|
|
1705
|
-
/** Returns the selected timeline revision. */
|
|
1706
|
-
const useSelectedTimelineRevision = selectedTimelineRevisionEventFunctions.useValue;
|
|
1707
|
-
/** Sets the selected timeline revision. */
|
|
1708
|
-
const setSelectedTimelineRevision = selectedTimelineRevisionEventFunctions.setValue;
|
|
1709
|
-
/** Adds an event handler for the selected timeline revision. */
|
|
1710
|
-
const addSelectedTimelineRevisionEventHandler = selectedTimelineRevisionEventFunctions.addEventHandler;
|
|
1711
|
-
//#endregion
|
|
1712
|
-
//#region src/hooks/toast.ts
|
|
1713
|
-
const toastEventFunctions = makePHEventFunctions("toast");
|
|
1714
|
-
/** Returns the toast function */
|
|
1715
|
-
const usePHToast = toastEventFunctions.useValue;
|
|
1716
|
-
/** Sets the toast function */
|
|
1717
|
-
const setPHToast = toastEventFunctions.setValue;
|
|
1718
|
-
/** Adds an event handler for the toast */
|
|
1719
|
-
const addToastEventHandler = toastEventFunctions.addEventHandler;
|
|
1720
|
-
//#endregion
|
|
1721
|
-
//#region src/hooks/vetra-packages.ts
|
|
1722
|
-
const vetraPackageManagerFunctions = makePHEventFunctions("vetraPackageManager");
|
|
1723
|
-
const useVetraPackageManager = vetraPackageManagerFunctions.useValue;
|
|
1724
|
-
/** Returns all of the Vetra packages loaded by the Connect instance */
|
|
1725
|
-
const useVetraPackages = () => {
|
|
1726
|
-
const packageManager = useVetraPackageManager();
|
|
1727
|
-
return useSyncExternalStore((cb) => packageManager ? packageManager.subscribe(cb) : () => {}, () => packageManager?.packages ?? []);
|
|
1728
|
-
};
|
|
1729
|
-
/** Adds the Vetra package manager event handler */
|
|
1730
|
-
const addVetraPackageManagerEventHandler = vetraPackageManagerFunctions.addEventHandler;
|
|
1731
|
-
/** Sets the Vetra package manager and registers its packages */
|
|
1732
|
-
function setVetraPackageManager(packageManager) {
|
|
1733
|
-
vetraPackageManagerFunctions.setValue(packageManager);
|
|
1734
|
-
updateReactorClientDocumentModels(packageManager.packages);
|
|
1735
|
-
updateReactorClientUpgradeManifests(packageManager.packages);
|
|
1736
|
-
packageManager.subscribe(({ packages }) => {
|
|
1737
|
-
updateReactorClientDocumentModels(packages);
|
|
1738
|
-
updateReactorClientUpgradeManifests(packages);
|
|
1739
|
-
});
|
|
1740
|
-
}
|
|
1741
|
-
function updateReactorClientDocumentModels(packages) {
|
|
1742
|
-
const documentModelModules = packages.flatMap((pkg) => pkg.documentModels);
|
|
1743
|
-
const registry = window.ph?.reactorClientModule?.reactorModule?.documentModelRegistry;
|
|
1744
|
-
if (!registry || documentModelModules.length === 0) return;
|
|
1745
|
-
const results = registry.registerModules(...documentModelModules);
|
|
1746
|
-
const duplicates = [];
|
|
1747
|
-
for (const result of results) if (result.status === "error") if (DuplicateModuleError.isError(result.error)) duplicates.push(result);
|
|
1748
|
-
else console.error("Failed to register document model module:", result.error);
|
|
1749
|
-
if (duplicates.length > 0) {
|
|
1750
|
-
const duplicateTypes = duplicates.map((r) => r.item.documentModel.global.id);
|
|
1751
|
-
registry.unregisterModules(...duplicateTypes);
|
|
1752
|
-
registry.registerModules(...duplicates.map((r) => r.item));
|
|
1753
|
-
}
|
|
1754
|
-
}
|
|
1755
|
-
function updateReactorClientUpgradeManifests(packages) {
|
|
1756
|
-
const upgradeManifests = packages.flatMap((pkg) => pkg.upgradeManifests).filter((u) => u !== void 0);
|
|
1757
|
-
const registry = window.ph?.reactorClientModule?.reactorModule?.documentModelRegistry;
|
|
1758
|
-
if (!registry || upgradeManifests.length === 0) return;
|
|
1759
|
-
const results = registry.registerUpgradeManifests(...upgradeManifests);
|
|
1760
|
-
const duplicates = [];
|
|
1761
|
-
for (const result of results) if (result.status === "error") if (DuplicateManifestError.isError(result.error)) duplicates.push(result);
|
|
1762
|
-
else console.error("Failed to register upgrade manifest:", result.error);
|
|
1763
|
-
if (duplicates.length > 0) {
|
|
1764
|
-
const duplicateTypes = duplicates.map((r) => r.item.documentType).filter((t) => !!t);
|
|
1765
|
-
registry.unregisterUpgradeManifests(...duplicateTypes);
|
|
1766
|
-
registry.registerUpgradeManifests(...duplicates.map((r) => r.item));
|
|
1767
|
-
}
|
|
1768
|
-
}
|
|
1769
|
-
//#endregion
|
|
1770
|
-
//#region src/hooks/add-ph-event-handlers.ts
|
|
1771
|
-
const commonGlobalEventHandlerFunctions = {
|
|
1772
|
-
loading: addLoadingEventHandler,
|
|
1773
|
-
drives: addDrivesEventHandler,
|
|
1774
|
-
selectedDriveId: () => {
|
|
1775
|
-
addSelectedDriveIdEventHandler();
|
|
1776
|
-
addSetSelectedDriveOnPopStateEventHandler();
|
|
1777
|
-
addResetSelectedNodeEventHandler();
|
|
1778
|
-
},
|
|
1779
|
-
selectedNodeId: () => {
|
|
1780
|
-
addSelectedNodeIdEventHandler();
|
|
1781
|
-
addSetSelectedNodeOnPopStateEventHandler();
|
|
1782
|
-
},
|
|
1783
|
-
documentCache: addDocumentCacheEventHandler,
|
|
1784
|
-
reactorGraphQLClient: addGraphQLReactorClientEventHandler,
|
|
1785
|
-
draggingNode: addDraggingNodeEventHandler
|
|
1786
|
-
};
|
|
1787
|
-
const phGlobalEventHandlerRegisterFunctions = {
|
|
1788
|
-
...commonGlobalEventHandlerFunctions,
|
|
1789
|
-
reactorClientModule: addReactorClientModuleEventHandler,
|
|
1790
|
-
reactorClient: addReactorClientEventHandler,
|
|
1791
|
-
attachmentService: addAttachmentServiceEventHandler,
|
|
1792
|
-
features: addFeaturesEventHandler,
|
|
1793
|
-
modal: addModalEventHandler,
|
|
1794
|
-
renown: addRenownEventHandler,
|
|
1795
|
-
vetraPackageManager: addVetraPackageManagerEventHandler,
|
|
1796
|
-
packageDiscoveryService: addPackageDiscoveryServiceEventHandler,
|
|
1797
|
-
selectedTimelineRevision: addSelectedTimelineRevisionEventHandler,
|
|
1798
|
-
revisionHistoryVisible: addRevisionHistoryVisibleEventHandler,
|
|
1799
|
-
selectedTimelineItem: addSelectedTimelineItemEventHandler,
|
|
1800
|
-
routerBasename: addRouterBasenameEventHandler,
|
|
1801
|
-
version: addVersionEventHandler,
|
|
1802
|
-
logLevel: addLogLevelEventHandler,
|
|
1803
|
-
requiresHardRefresh: addRequiresHardRefreshEventHandler,
|
|
1804
|
-
warnOutdatedApp: addWarnOutdatedAppEventHandler,
|
|
1805
|
-
studioMode: addStudioModeEventHandler,
|
|
1806
|
-
basePath: addBasePathEventHandler,
|
|
1807
|
-
versionCheckInterval: addVersionCheckIntervalEventHandler,
|
|
1808
|
-
cliVersion: addCliVersionEventHandler,
|
|
1809
|
-
fileUploadOperationsChunkSize: addFileUploadOperationsChunkSizeEventHandler,
|
|
1810
|
-
isDocumentModelSelectionSettingsEnabled: addIsDocumentModelSelectionSettingsEnabledEventHandler,
|
|
1811
|
-
gaTrackingId: addGaTrackingIdEventHandler,
|
|
1812
|
-
allowList: addAllowListEventHandler,
|
|
1813
|
-
defaultDrivesUrl: addDefaultDrivesUrlEventHandler,
|
|
1814
|
-
drivesPreserveStrategy: addDrivesPreserveStrategyEventHandler,
|
|
1815
|
-
allowedDocumentTypes: addAllowedDocumentTypesEventHandler,
|
|
1816
|
-
enabledEditors: addEnabledEditorsEventHandler,
|
|
1817
|
-
disabledEditors: addDisabledEditorsEventHandler,
|
|
1818
|
-
isAddDriveEnabled: addIsAddDriveEnabledEventHandler,
|
|
1819
|
-
isLocalDrivesEnabled: addIsLocalDrivesEnabledEventHandler,
|
|
1820
|
-
isPublicDrivesEnabled: addIsPublicDrivesEnabledEventHandler,
|
|
1821
|
-
isAddPublicDrivesEnabled: addIsAddPublicDrivesEnabledEventHandler,
|
|
1822
|
-
isDeletePublicDrivesEnabled: addIsDeletePublicDrivesEnabledEventHandler,
|
|
1823
|
-
isCloudDrivesEnabled: addIsCloudDrivesEnabledEventHandler,
|
|
1824
|
-
isAddCloudDrivesEnabled: addIsAddCloudDrivesEnabledEventHandler,
|
|
1825
|
-
isDeleteCloudDrivesEnabled: addIsDeleteCloudDrivesEnabledEventHandler,
|
|
1826
|
-
isAddLocalDrivesEnabled: addIsAddLocalDrivesEnabledEventHandler,
|
|
1827
|
-
isDeleteLocalDrivesEnabled: addIsDeleteLocalDrivesEnabledEventHandler,
|
|
1828
|
-
isDragAndDropEnabled: addIsDragAndDropEnabledEventHandler,
|
|
1829
|
-
isExternalControlsEnabled: addIsExternalControlsEnabledEventHandler,
|
|
1830
|
-
isEditorDebugModeEnabled: addIsEditorDebugModeEnabledEventHandler,
|
|
1831
|
-
isEditorReadModeEnabled: addIsEditorReadModeEnabledEventHandler,
|
|
1832
|
-
isRelationalProcessorsEnabled: addIsRelationalProcessorsEnabledEventHandler,
|
|
1833
|
-
isExternalRelationalProcessorsEnabled: addIsExternalRelationalProcessorsEnabledEventHandler,
|
|
1834
|
-
isAnalyticsEnabled: addIsAnalyticsEnabledEventHandler,
|
|
1835
|
-
isAnalyticsExternalProcessorsEnabled: addIsAnalyticsExternalProcessorsEnabledEventHandler,
|
|
1836
|
-
analyticsDatabaseName: addAnalyticsDatabaseNameEventHandler,
|
|
1837
|
-
isAnalyticsDatabaseWorkerEnabled: addIsAnalyticsDatabaseWorkerEnabledEventHandler,
|
|
1838
|
-
isDiffAnalyticsEnabled: addIsDiffAnalyticsEnabledEventHandler,
|
|
1839
|
-
isDriveAnalyticsEnabled: addIsDriveAnalyticsEnabledEventHandler,
|
|
1840
|
-
renownUrl: addRenownUrlEventHandler,
|
|
1841
|
-
renownNetworkId: addRenownNetworkIdEventHandler,
|
|
1842
|
-
renownChainId: addRenownChainIdEventHandler,
|
|
1843
|
-
sentryRelease: addSentryReleaseEventHandler,
|
|
1844
|
-
sentryDsn: addSentryDsnEventHandler,
|
|
1845
|
-
sentryEnv: addSentryEnvEventHandler,
|
|
1846
|
-
isSentryTracingEnabled: addIsSentryTracingEnabledEventHandler,
|
|
1847
|
-
isExternalProcessorsEnabled: addIsExternalProcessorsEnabledEventHandler,
|
|
1848
|
-
isExternalPackagesEnabled: addIsExternalPackagesEnabledEventHandler,
|
|
1849
|
-
toast: addToastEventHandler
|
|
1850
|
-
};
|
|
1851
|
-
function addPHEventHandlers() {
|
|
1852
|
-
callEventHandlerRegisterFunctions(phGlobalEventHandlerRegisterFunctions);
|
|
1853
|
-
}
|
|
1854
|
-
function callEventHandlerRegisterFunctions(registerFunctions) {
|
|
1855
|
-
forEachObj(registerFunctions, (fn) => fn());
|
|
1856
|
-
}
|
|
1857
|
-
//#endregion
|
|
1858
|
-
//#region src/hooks/document-model-modules.ts
|
|
1859
|
-
function useDocumentModelModules() {
|
|
1860
|
-
return useVetraPackages().flatMap((pkg) => pkg.documentModels).filter((module, index, modules) => modules.findIndex((m) => m.documentModel.global.id === module.documentModel.global.id && m.version === module.version) === index);
|
|
1861
|
-
}
|
|
1862
|
-
function useDocumentModelModuleById(id) {
|
|
1863
|
-
return useDocumentModelModules()?.find((module) => module.documentModel.global.id === id);
|
|
1864
|
-
}
|
|
1865
|
-
//#endregion
|
|
1866
604
|
//#region src/hooks/allowed-document-model-modules.ts
|
|
1867
605
|
function useAllowedDocumentModelModules() {
|
|
1868
606
|
const documentModelModules = useDocumentModelModules();
|
|
@@ -2017,130 +755,34 @@ function useConnectionStates() {
|
|
|
2017
755
|
unsubscribesRef.current = [];
|
|
2018
756
|
const remotes = syncManager.list();
|
|
2019
757
|
for (const remote of remotes) {
|
|
2020
|
-
const unsub = remote.channel.onConnectionStateChange(() => {
|
|
2021
|
-
setStates(buildSnapshot(syncManager));
|
|
2022
|
-
});
|
|
2023
|
-
unsubscribesRef.current.push(unsub);
|
|
2024
|
-
}
|
|
2025
|
-
setStates(buildSnapshot(syncManager));
|
|
2026
|
-
}
|
|
2027
|
-
subscribe();
|
|
2028
|
-
const interval = setInterval(subscribe, 5e3);
|
|
2029
|
-
return () => {
|
|
2030
|
-
clearInterval(interval);
|
|
2031
|
-
for (const unsub of unsubscribesRef.current) unsub();
|
|
2032
|
-
unsubscribesRef.current = [];
|
|
2033
|
-
};
|
|
2034
|
-
}, [syncManager]);
|
|
2035
|
-
return states;
|
|
2036
|
-
}
|
|
2037
|
-
/**
|
|
2038
|
-
* Returns the connection state snapshot for a specific remote by name.
|
|
2039
|
-
*/
|
|
2040
|
-
function useConnectionState(remoteName) {
|
|
2041
|
-
return useConnectionStates().get(remoteName);
|
|
2042
|
-
}
|
|
2043
|
-
function buildSnapshot(syncManager) {
|
|
2044
|
-
const map = /* @__PURE__ */ new Map();
|
|
2045
|
-
if (!syncManager) return map;
|
|
2046
|
-
for (const remote of syncManager.list()) map.set(remote.meta.name, remote.channel.getConnectionState());
|
|
2047
|
-
return map;
|
|
2048
|
-
}
|
|
2049
|
-
//#endregion
|
|
2050
|
-
//#region src/hooks/document-of-type.ts
|
|
2051
|
-
/** Returns a document of a specific type, throws an error if the found document has a different type */
|
|
2052
|
-
function useDocumentOfType(documentId, documentType) {
|
|
2053
|
-
const [document, dispatch] = useDocumentById(documentId);
|
|
2054
|
-
const documentModelModule = useDocumentModelModuleById(documentType);
|
|
2055
|
-
if (!documentId || !documentType) return [];
|
|
2056
|
-
if (!document) throw new Error(`Document not found: ${documentId}`);
|
|
2057
|
-
if (!documentModelModule) throw new ModuleNotFoundError(documentType);
|
|
2058
|
-
if (document.header.documentType !== documentType) throw new DocumentTypeMismatchError(documentId, documentType, document.header.documentType);
|
|
2059
|
-
return [document, dispatch];
|
|
2060
|
-
}
|
|
2061
|
-
//#endregion
|
|
2062
|
-
//#region src/hooks/document-operations.ts
|
|
2063
|
-
/**
|
|
2064
|
-
* Hook to fetch document operations via the reactor client.
|
|
2065
|
-
* Operations are no longer auto-populated on documents and must be fetched explicitly.
|
|
2066
|
-
*
|
|
2067
|
-
* @param documentId - The document ID to fetch operations for
|
|
2068
|
-
* @returns Object containing globalOperations, localOperations, isLoading, and error
|
|
2069
|
-
*/
|
|
2070
|
-
function useDocumentOperations(documentId) {
|
|
2071
|
-
const reactorClient = useReactorClient();
|
|
2072
|
-
const hasFetchedRef = useRef(false);
|
|
2073
|
-
const [state, setState] = useState(() => ({
|
|
2074
|
-
globalOperations: [],
|
|
2075
|
-
localOperations: [],
|
|
2076
|
-
isLoading: !!documentId,
|
|
2077
|
-
error: void 0
|
|
2078
|
-
}));
|
|
2079
|
-
const fetchOperations = useCallback(async (retryCount = 0) => {
|
|
2080
|
-
const MAX_RETRIES = 5;
|
|
2081
|
-
const RETRY_DELAY_MS = 500;
|
|
2082
|
-
if (!documentId || !reactorClient) {
|
|
2083
|
-
setState({
|
|
2084
|
-
globalOperations: [],
|
|
2085
|
-
localOperations: [],
|
|
2086
|
-
isLoading: false,
|
|
2087
|
-
error: void 0
|
|
2088
|
-
});
|
|
2089
|
-
return;
|
|
2090
|
-
}
|
|
2091
|
-
setState((prev) => ({
|
|
2092
|
-
...prev,
|
|
2093
|
-
isLoading: true,
|
|
2094
|
-
error: void 0
|
|
2095
|
-
}));
|
|
2096
|
-
let globalOps = [];
|
|
2097
|
-
let localOps = [];
|
|
2098
|
-
let fetchError;
|
|
2099
|
-
try {
|
|
2100
|
-
globalOps = (await reactorClient.getOperations(documentId, { scopes: ["global"] })).results;
|
|
2101
|
-
} catch (err) {
|
|
2102
|
-
fetchError = err instanceof Error ? err : new Error(String(err));
|
|
2103
|
-
}
|
|
2104
|
-
if (!fetchError) try {
|
|
2105
|
-
localOps = (await reactorClient.getOperations(documentId, { scopes: ["local"] })).results;
|
|
2106
|
-
} catch (err) {
|
|
2107
|
-
fetchError = err instanceof Error ? err : new Error(String(err));
|
|
2108
|
-
}
|
|
2109
|
-
if (!fetchError && globalOps.length === 0 && localOps.length === 0 && retryCount < MAX_RETRIES) {
|
|
2110
|
-
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS));
|
|
2111
|
-
return fetchOperations(retryCount + 1);
|
|
2112
|
-
}
|
|
2113
|
-
setState({
|
|
2114
|
-
globalOperations: globalOps,
|
|
2115
|
-
localOperations: localOps,
|
|
2116
|
-
isLoading: false,
|
|
2117
|
-
error: fetchError
|
|
2118
|
-
});
|
|
2119
|
-
hasFetchedRef.current = true;
|
|
2120
|
-
}, [documentId, reactorClient]);
|
|
2121
|
-
useEffect(() => {
|
|
2122
|
-
if (documentId && reactorClient) fetchOperations();
|
|
2123
|
-
else if (!documentId) {
|
|
2124
|
-
setState({
|
|
2125
|
-
globalOperations: [],
|
|
2126
|
-
localOperations: [],
|
|
2127
|
-
isLoading: false,
|
|
2128
|
-
error: void 0
|
|
2129
|
-
});
|
|
2130
|
-
hasFetchedRef.current = false;
|
|
2131
|
-
}
|
|
2132
|
-
}, [
|
|
2133
|
-
documentId,
|
|
2134
|
-
reactorClient,
|
|
2135
|
-
fetchOperations
|
|
2136
|
-
]);
|
|
2137
|
-
const refetch = useCallback(() => {
|
|
2138
|
-
fetchOperations(0);
|
|
2139
|
-
}, [fetchOperations]);
|
|
2140
|
-
return {
|
|
2141
|
-
...state,
|
|
2142
|
-
refetch
|
|
2143
|
-
};
|
|
758
|
+
const unsub = remote.channel.onConnectionStateChange(() => {
|
|
759
|
+
setStates(buildSnapshot(syncManager));
|
|
760
|
+
});
|
|
761
|
+
unsubscribesRef.current.push(unsub);
|
|
762
|
+
}
|
|
763
|
+
setStates(buildSnapshot(syncManager));
|
|
764
|
+
}
|
|
765
|
+
subscribe();
|
|
766
|
+
const interval = setInterval(subscribe, 5e3);
|
|
767
|
+
return () => {
|
|
768
|
+
clearInterval(interval);
|
|
769
|
+
for (const unsub of unsubscribesRef.current) unsub();
|
|
770
|
+
unsubscribesRef.current = [];
|
|
771
|
+
};
|
|
772
|
+
}, [syncManager]);
|
|
773
|
+
return states;
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Returns the connection state snapshot for a specific remote by name.
|
|
777
|
+
*/
|
|
778
|
+
function useConnectionState(remoteName) {
|
|
779
|
+
return useConnectionStates().get(remoteName);
|
|
780
|
+
}
|
|
781
|
+
function buildSnapshot(syncManager) {
|
|
782
|
+
const map = /* @__PURE__ */ new Map();
|
|
783
|
+
if (!syncManager) return map;
|
|
784
|
+
for (const remote of syncManager.list()) map.set(remote.meta.name, remote.channel.getConnectionState());
|
|
785
|
+
return map;
|
|
2144
786
|
}
|
|
2145
787
|
//#endregion
|
|
2146
788
|
//#region src/hooks/supported-document-types.ts
|
|
@@ -2161,6 +803,52 @@ function useDocumentTypes() {
|
|
|
2161
803
|
return allowedDocumentTypes ?? supportedDocumentTypes;
|
|
2162
804
|
}
|
|
2163
805
|
//#endregion
|
|
806
|
+
//#region src/hooks/document-version-status.ts
|
|
807
|
+
/**
|
|
808
|
+
* Classifies a document's model version against the installed module
|
|
809
|
+
* versions. Pure logic, extracted for testing.
|
|
810
|
+
*/
|
|
811
|
+
function getDocumentVersionStatus(documentVersion, availableVersions, hasUpgradePath) {
|
|
812
|
+
if (availableVersions.length === 0) return;
|
|
813
|
+
const sorted = [...availableVersions].sort((a, b) => a - b);
|
|
814
|
+
const latestVersion = sorted[sorted.length - 1];
|
|
815
|
+
if (documentVersion > latestVersion) return {
|
|
816
|
+
kind: "unsupported",
|
|
817
|
+
documentVersion,
|
|
818
|
+
availableVersions: sorted
|
|
819
|
+
};
|
|
820
|
+
if (documentVersion === latestVersion) return {
|
|
821
|
+
kind: "current",
|
|
822
|
+
documentVersion
|
|
823
|
+
};
|
|
824
|
+
return {
|
|
825
|
+
kind: "upgrade-available",
|
|
826
|
+
documentVersion,
|
|
827
|
+
latestVersion,
|
|
828
|
+
canUpgrade: hasUpgradePath(documentVersion, latestVersion)
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* Compares the given document's model version against the versions available
|
|
833
|
+
* from installed Vetra packages. Returns undefined while packages load or
|
|
834
|
+
* when the document type has no installed modules.
|
|
835
|
+
*/
|
|
836
|
+
function useDocumentVersionStatus(document) {
|
|
837
|
+
const modules = useDocumentModelModules();
|
|
838
|
+
const registry = useModelRegistry();
|
|
839
|
+
if (!document || !modules) return;
|
|
840
|
+
const documentType = document.header.documentType;
|
|
841
|
+
return getDocumentVersionStatus(document.state.document.version || 1, modules.filter((m) => m.documentModel.global.id === documentType).map((m) => m.version ?? 1), (fromVersion, toVersion) => {
|
|
842
|
+
if (!registry) return false;
|
|
843
|
+
try {
|
|
844
|
+
registry.computeUpgradePath(documentType, fromVersion, toVersion);
|
|
845
|
+
return true;
|
|
846
|
+
} catch {
|
|
847
|
+
return false;
|
|
848
|
+
}
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
//#endregion
|
|
2164
852
|
//#region src/utils/validate-document.ts
|
|
2165
853
|
const validateDocument = (document) => {
|
|
2166
854
|
const errors = [];
|
|
@@ -2233,6 +921,27 @@ function useDownloadDocument(id) {
|
|
|
2233
921
|
};
|
|
2234
922
|
}
|
|
2235
923
|
//#endregion
|
|
924
|
+
//#region src/hooks/download-folder.ts
|
|
925
|
+
/**
|
|
926
|
+
* Downloads the selected drive's folder (or the whole drive when no folder
|
|
927
|
+
* is given) as a single zip archive mirroring the folder tree.
|
|
928
|
+
*/
|
|
929
|
+
function useDownloadFolder(folderNode) {
|
|
930
|
+
const [selectedDrive] = useSelectedDriveSafe();
|
|
931
|
+
const toast = usePHToast();
|
|
932
|
+
return async () => {
|
|
933
|
+
if (!selectedDrive) return;
|
|
934
|
+
const name = folderNode?.name ?? selectedDrive.header.name;
|
|
935
|
+
toast?.(`Downloading "${name}"…`);
|
|
936
|
+
try {
|
|
937
|
+
const { entryCount, failed } = await downloadFolderZip(selectedDrive, folderNode);
|
|
938
|
+
toast?.(failed.length ? `Downloaded ${entryCount} files (${failed.length} failed)` : `Downloaded ${entryCount} files`);
|
|
939
|
+
} catch (error) {
|
|
940
|
+
toast?.(`Failed to download "${name}": ${error.message}`);
|
|
941
|
+
}
|
|
942
|
+
};
|
|
943
|
+
}
|
|
944
|
+
//#endregion
|
|
2236
945
|
//#region src/hooks/drive-by-id.ts
|
|
2237
946
|
function useDriveById(driveId) {
|
|
2238
947
|
const foundDrive = useDrives()?.find((drive) => drive.header.id === driveId);
|
|
@@ -2354,6 +1063,7 @@ function useDropFile(handleAddFile) {
|
|
|
2354
1063
|
const { isDropTarget, setTarget, unsetTarget } = useDropTarget();
|
|
2355
1064
|
const isDragAndDropEnabled = useIsDragAndDropEnabled();
|
|
2356
1065
|
const selectedFolder = useSelectedFolder();
|
|
1066
|
+
const selectedDriveId = useSelectedDriveId();
|
|
2357
1067
|
function handleDragEvent(event, cb) {
|
|
2358
1068
|
if (!isDragAndDropEnabled) return;
|
|
2359
1069
|
if (!isFileDrop(event)) return;
|
|
@@ -2365,7 +1075,24 @@ function useDropFile(handleAddFile) {
|
|
|
2365
1075
|
event.stopPropagation();
|
|
2366
1076
|
cb?.();
|
|
2367
1077
|
}
|
|
2368
|
-
const handleAddFiles =
|
|
1078
|
+
const handleAddFiles = async (event) => {
|
|
1079
|
+
const dropped = pipe(event, getFileItems, filter(hasAllowedExtension));
|
|
1080
|
+
const jobs = [];
|
|
1081
|
+
for (const file of dropped) {
|
|
1082
|
+
if (selectedDriveId) try {
|
|
1083
|
+
const expanded = await expandBulkArchive(file, selectedDriveId, selectedFolder);
|
|
1084
|
+
jobs.push(...expanded);
|
|
1085
|
+
continue;
|
|
1086
|
+
} catch (error) {
|
|
1087
|
+
console.error("Bulk archive expansion failed", error);
|
|
1088
|
+
}
|
|
1089
|
+
jobs.push({
|
|
1090
|
+
file,
|
|
1091
|
+
parent: selectedFolder
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
1094
|
+
await Promise.all(jobs.map((job) => handleAddFile(job.file, job.parent)));
|
|
1095
|
+
};
|
|
2369
1096
|
const onDragEnter = (event) => handleDragEvent(event);
|
|
2370
1097
|
const onDragOver = (event) => handleDragEvent(event, setTarget);
|
|
2371
1098
|
const onDragLeave = (event) => handleDragEvent(event, unsetTarget);
|
|
@@ -2481,7 +1208,7 @@ function useNodeActions() {
|
|
|
2481
1208
|
const drives = useDrives();
|
|
2482
1209
|
async function onAddFile(file, parent) {
|
|
2483
1210
|
if (!selectedDriveId) return;
|
|
2484
|
-
return
|
|
1211
|
+
return addFileWithProgress(file, selectedDriveId, file.name.replace(/\..+/gim, ""), resolveNode(selectedDriveId, parent)?.id, void 0, void 0, "duplicate");
|
|
2485
1212
|
}
|
|
2486
1213
|
async function onAddFolder(name, parent) {
|
|
2487
1214
|
if (!selectedDriveId) return;
|
|
@@ -2582,29 +1309,6 @@ function useParentFolderForSelectedNode() {
|
|
|
2582
1309
|
return useNodeParentFolderById(useSelectedNode()?.id);
|
|
2583
1310
|
}
|
|
2584
1311
|
//#endregion
|
|
2585
|
-
//#region src/hooks/selected-document.ts
|
|
2586
|
-
/** Returns the selected document id */
|
|
2587
|
-
function useSelectedDocumentId() {
|
|
2588
|
-
const selectedNode = useSelectedNode();
|
|
2589
|
-
return selectedNode && isFileNode(selectedNode) ? selectedNode.id : void 0;
|
|
2590
|
-
}
|
|
2591
|
-
/** Returns the selected document. */
|
|
2592
|
-
function useSelectedDocument() {
|
|
2593
|
-
const [document, dispatch] = useDocumentById(useSelectedDocumentId());
|
|
2594
|
-
if (!document) throw new NoSelectedDocumentError();
|
|
2595
|
-
return [document, dispatch];
|
|
2596
|
-
}
|
|
2597
|
-
/** Returns the selected document. */
|
|
2598
|
-
function useSelectedDocumentSafe() {
|
|
2599
|
-
return useDocumentById(useSelectedDocumentId());
|
|
2600
|
-
}
|
|
2601
|
-
function useSelectedDocumentOfType(documentType) {
|
|
2602
|
-
const documentId = useSelectedDocumentId();
|
|
2603
|
-
if (!documentType) return [];
|
|
2604
|
-
if (!documentId) throw new NoSelectedDocumentError();
|
|
2605
|
-
return useDocumentOfType(documentId, documentType);
|
|
2606
|
-
}
|
|
2607
|
-
//#endregion
|
|
2608
1312
|
//#region src/hooks/subgraph-modules.ts
|
|
2609
1313
|
function useSubgraphModules() {
|
|
2610
1314
|
return useVetraPackages().flatMap((pkg) => pkg.subgraphs || []);
|
|
@@ -2706,6 +1410,138 @@ function useTheme() {
|
|
|
2706
1410
|
};
|
|
2707
1411
|
}
|
|
2708
1412
|
//#endregion
|
|
1413
|
+
//#region src/hooks/use-can-execute.ts
|
|
1414
|
+
const IDLE = { status: "idle" };
|
|
1415
|
+
const LOADING = { status: "loading" };
|
|
1416
|
+
const UNSUPPORTED = { status: "unsupported" };
|
|
1417
|
+
function readyState(answer) {
|
|
1418
|
+
return {
|
|
1419
|
+
status: "ready",
|
|
1420
|
+
evaluations: answer.evaluations,
|
|
1421
|
+
allAllowed: answer.allAllowed,
|
|
1422
|
+
anyAllowed: answer.anyAllowed,
|
|
1423
|
+
allDenied: answer.allDenied,
|
|
1424
|
+
anyDenied: answer.anyDenied
|
|
1425
|
+
};
|
|
1426
|
+
}
|
|
1427
|
+
/**
|
|
1428
|
+
* Whether the subject the reactor client would decide for now is the one it is
|
|
1429
|
+
* going to keep.
|
|
1430
|
+
*
|
|
1431
|
+
* Renown's login status is the signal. Only `checking` is transient --
|
|
1432
|
+
* mid-login, about to resolve -- and `authorized` without a user yet is still
|
|
1433
|
+
* mid-resolution. Everything else is a steady state: `initial` is the anonymous
|
|
1434
|
+
* subject for a user who never logged in or just logged out (a restored session
|
|
1435
|
+
* is `authorized` from construction, so `initial` is not a pre-login window),
|
|
1436
|
+
* and `not-authorized` is a failed login, anonymous too.
|
|
1437
|
+
*
|
|
1438
|
+
* An absent status counts as unsettled, which is one render in a host that wires
|
|
1439
|
+
* renown -- and forever in a host that does not. Such a host names its subject
|
|
1440
|
+
* through the `subject` parameter instead, which needs nothing to settle.
|
|
1441
|
+
*/
|
|
1442
|
+
function subjectSettled(loginStatus, user) {
|
|
1443
|
+
if (loginStatus === "authorized") return user !== void 0;
|
|
1444
|
+
return loginStatus === "initial" || loginStatus === "not-authorized";
|
|
1445
|
+
}
|
|
1446
|
+
/**
|
|
1447
|
+
* Predicts whether the current subject may execute each of a set of candidate
|
|
1448
|
+
* operations on one document, so a UI can disable a control rather than offer an
|
|
1449
|
+
* action that fails on submit.
|
|
1450
|
+
*
|
|
1451
|
+
* The answer is a prediction and not a promise: the submit path is the only
|
|
1452
|
+
* authority, and this cannot reproduce the append condition real admission
|
|
1453
|
+
* compiles. Treat an allow as "worth offering", never as "will succeed", and
|
|
1454
|
+
* keep handling the submit's refusal.
|
|
1455
|
+
*
|
|
1456
|
+
* A candidate whose verdict depends on its input has to carry that input, since
|
|
1457
|
+
* a conditional grant reads it. A candidate standing for a form the user has not
|
|
1458
|
+
* filled in yet predicts the verdict an empty form earns.
|
|
1459
|
+
*
|
|
1460
|
+
* Deliberately reads the client off the reactor client module rather than
|
|
1461
|
+
* through `useReactorClient`: the latter hands back the minimal browser client
|
|
1462
|
+
* contract, which does not carry the preflight, and the plain-GraphQL setup that
|
|
1463
|
+
* implements it sets no module at all. No module therefore reports
|
|
1464
|
+
* `unsupported`.
|
|
1465
|
+
*
|
|
1466
|
+
* Re-evaluated when the document's revision moves, which covers a policy change
|
|
1467
|
+
* written to the document being asked about. Two gaps are known and accepted:
|
|
1468
|
+
*
|
|
1469
|
+
* - A group membership change is a write to the *group* document, so it fires no
|
|
1470
|
+
* change event for this one. A group-gated grant can therefore be stale here
|
|
1471
|
+
* until something else re-evaluates.
|
|
1472
|
+
* - A change event carries no scope, so any write to the document re-evaluates,
|
|
1473
|
+
* including one that cannot affect a verdict.
|
|
1474
|
+
*
|
|
1475
|
+
* @param documentId - The document the candidates target, or null/undefined to stay idle
|
|
1476
|
+
* @param candidates - Operations to predict a verdict for. Read by content, so an inline array is fine
|
|
1477
|
+
* @param branch - Branch to evaluate against, defaulting to main
|
|
1478
|
+
* @param subject - Optional subject to decide for instead of the client's signer
|
|
1479
|
+
*/
|
|
1480
|
+
function useCanExecute(documentId, candidates, branch = "main", subject) {
|
|
1481
|
+
const client = useReactorClientModule()?.client;
|
|
1482
|
+
const loginStatus = useLoginStatus();
|
|
1483
|
+
const user = useUser();
|
|
1484
|
+
const revision = useDocumentSafe(documentId).data?.header.revision;
|
|
1485
|
+
const [nonce, setNonce] = useState(0);
|
|
1486
|
+
const [state, setState] = useState(IDLE);
|
|
1487
|
+
const candidateKey = JSON.stringify(candidates);
|
|
1488
|
+
const subjectKey = JSON.stringify(subject);
|
|
1489
|
+
const stableCandidates = useMemo(() => candidates, [candidateKey]);
|
|
1490
|
+
const stableSubject = useMemo(() => subject, [subjectKey]);
|
|
1491
|
+
const settled = subject !== void 0 || subjectSettled(loginStatus, user);
|
|
1492
|
+
const subjectIdentity = subject !== void 0 ? subjectKey : `${loginStatus ?? ""}:${user?.address ?? ""}`;
|
|
1493
|
+
const revisionKey = JSON.stringify(revision);
|
|
1494
|
+
const refetch = useCallback(() => {
|
|
1495
|
+
setNonce((count) => count + 1);
|
|
1496
|
+
}, []);
|
|
1497
|
+
useEffect(() => {
|
|
1498
|
+
if (client === void 0) {
|
|
1499
|
+
setState(UNSUPPORTED);
|
|
1500
|
+
return;
|
|
1501
|
+
}
|
|
1502
|
+
if (!documentId) {
|
|
1503
|
+
setState(IDLE);
|
|
1504
|
+
return;
|
|
1505
|
+
}
|
|
1506
|
+
if (!settled) {
|
|
1507
|
+
setState(LOADING);
|
|
1508
|
+
return;
|
|
1509
|
+
}
|
|
1510
|
+
let active = true;
|
|
1511
|
+
setState(LOADING);
|
|
1512
|
+
const evaluate = async () => {
|
|
1513
|
+
let next;
|
|
1514
|
+
try {
|
|
1515
|
+
next = readyState(await client.evaluateActions(documentId, branch, stableCandidates, stableSubject));
|
|
1516
|
+
} catch (error) {
|
|
1517
|
+
next = AuthEnforcementDisabledError.isError(error) ? UNSUPPORTED : {
|
|
1518
|
+
status: "error",
|
|
1519
|
+
error: Error.isError(error) ? error : new Error(String(error))
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1522
|
+
if (active) setState(next);
|
|
1523
|
+
};
|
|
1524
|
+
evaluate();
|
|
1525
|
+
return () => {
|
|
1526
|
+
active = false;
|
|
1527
|
+
};
|
|
1528
|
+
}, [
|
|
1529
|
+
client,
|
|
1530
|
+
documentId,
|
|
1531
|
+
branch,
|
|
1532
|
+
stableCandidates,
|
|
1533
|
+
stableSubject,
|
|
1534
|
+
settled,
|
|
1535
|
+
subjectIdentity,
|
|
1536
|
+
revisionKey,
|
|
1537
|
+
nonce
|
|
1538
|
+
]);
|
|
1539
|
+
return {
|
|
1540
|
+
...state,
|
|
1541
|
+
refetch
|
|
1542
|
+
};
|
|
1543
|
+
}
|
|
1544
|
+
//#endregion
|
|
2709
1545
|
//#region src/hooks/use-drive-system-info.ts
|
|
2710
1546
|
function deriveSystemUrl(channelUrl) {
|
|
2711
1547
|
try {
|
|
@@ -2894,8 +1730,134 @@ function getDocumentGraphqlQuery() {
|
|
|
2894
1730
|
if (!loc) throw new Error("GetDocumentWithOperationsDocument is misconfigured, loc is missing.");
|
|
2895
1731
|
return loc.source.body;
|
|
2896
1732
|
}
|
|
2897
|
-
|
|
2898
|
-
|
|
1733
|
+
/**
|
|
1734
|
+
* The base URL of the switchboard that serves a drive's GraphQL channel.
|
|
1735
|
+
*
|
|
1736
|
+
* The channel URL is `<origin>[<proxy-prefix>]/graphql/r`, so stripping the
|
|
1737
|
+
* suffix preserves any proxy prefix (e.g. `/api/reactor`). A URL that does
|
|
1738
|
+
* not end with the suffix is unexpected — fall back to its origin.
|
|
1739
|
+
*/
|
|
1740
|
+
function getSwitchboardBaseFromChannelUrl(channelUrl) {
|
|
1741
|
+
if (channelUrl.endsWith("/graphql/r")) return channelUrl.slice(0, -GQL_CHANNEL_SUFFIX.length);
|
|
1742
|
+
return new URL(channelUrl).origin;
|
|
1743
|
+
}
|
|
1744
|
+
/**
|
|
1745
|
+
* The GraphQL name the switchboard exposes a document model under. Mirrors
|
|
1746
|
+
* `getDocumentModelSchemaName` on the server (`create-schema.ts`): the root
|
|
1747
|
+
* query field and the state type names are all derived from the model's
|
|
1748
|
+
* `global.name`.
|
|
1749
|
+
*/
|
|
1750
|
+
function getDocumentModelSchemaName(model) {
|
|
1751
|
+
return pascalCase(model.documentModel.global.name.replaceAll("/", " "));
|
|
1752
|
+
}
|
|
1753
|
+
function buildStateTypeMap(definitions) {
|
|
1754
|
+
const typeMap = /* @__PURE__ */ new Map();
|
|
1755
|
+
for (const def of definitions) if (def.kind === Kind.OBJECT_TYPE_DEFINITION) typeMap.set(def.name.value, def);
|
|
1756
|
+
return typeMap;
|
|
1757
|
+
}
|
|
1758
|
+
/**
|
|
1759
|
+
* Recursively expands the fields of a state object type into a GraphQL
|
|
1760
|
+
* selection. Objects expand their sub-selection (lists expand their item
|
|
1761
|
+
* type); enums, scalars, and built-ins are leaves.
|
|
1762
|
+
*/
|
|
1763
|
+
function expandStateFields(typeDef, typeMap) {
|
|
1764
|
+
return (typeDef.fields ?? []).map((field) => {
|
|
1765
|
+
const fieldName = field.name.value;
|
|
1766
|
+
let typeNode = field.type;
|
|
1767
|
+
if (typeNode.kind === Kind.NON_NULL_TYPE) typeNode = typeNode.type;
|
|
1768
|
+
if (typeNode.kind === Kind.LIST_TYPE) {
|
|
1769
|
+
let itemType = typeNode.type;
|
|
1770
|
+
if (itemType.kind === Kind.NON_NULL_TYPE) itemType = itemType.type;
|
|
1771
|
+
if (itemType.kind === Kind.LIST_TYPE) throw new Error(`Nested lists are not supported in state selections: ${fieldName}`);
|
|
1772
|
+
if (itemType.kind !== Kind.NAMED_TYPE) return fieldName;
|
|
1773
|
+
const itemTypeDef = typeMap.get(itemType.name.value);
|
|
1774
|
+
if (!itemTypeDef) return fieldName;
|
|
1775
|
+
return `${fieldName} { ${expandStateFields(itemTypeDef, typeMap)} }`;
|
|
1776
|
+
}
|
|
1777
|
+
if (typeNode.kind !== Kind.NAMED_TYPE) return fieldName;
|
|
1778
|
+
const typeDef = typeMap.get(typeNode.name.value);
|
|
1779
|
+
if (!typeDef) return fieldName;
|
|
1780
|
+
return `${fieldName} { ${expandStateFields(typeDef, typeMap)} }`;
|
|
1781
|
+
}).join(" ");
|
|
1782
|
+
}
|
|
1783
|
+
/**
|
|
1784
|
+
* Finds the root state object type in a state SDL. Root state types follow
|
|
1785
|
+
* the `<Name>State` / `<Name>GlobalState` conventions, and are defined last
|
|
1786
|
+
* by convention — the same resolution order the server uses
|
|
1787
|
+
* (`extractRootTypeName` in `create-schema.ts`).
|
|
1788
|
+
*/
|
|
1789
|
+
function findRootStateType(definitions, candidates) {
|
|
1790
|
+
let lastObjectType = null;
|
|
1791
|
+
for (const def of definitions) {
|
|
1792
|
+
if (def.kind !== Kind.OBJECT_TYPE_DEFINITION) continue;
|
|
1793
|
+
if (candidates.includes(def.name.value)) return def;
|
|
1794
|
+
lastObjectType = def;
|
|
1795
|
+
}
|
|
1796
|
+
if (!lastObjectType) throw new Error("No root state type found in the document model schema");
|
|
1797
|
+
return lastObjectType;
|
|
1798
|
+
}
|
|
1799
|
+
/**
|
|
1800
|
+
* Derives the subselection for the document's `global` state scope from the
|
|
1801
|
+
* model's state SDL (e.g. `name total`), expanding object fields
|
|
1802
|
+
* recursively. Throws when the schema is missing, unparseable, or has no
|
|
1803
|
+
* root object type — the caller falls back to the generic document query.
|
|
1804
|
+
*/
|
|
1805
|
+
function getDocumentStateSelection(model) {
|
|
1806
|
+
const schema = model.documentModel.global.specifications.at(-1)?.state.global.schema;
|
|
1807
|
+
if (!schema || !schema.trim()) throw new Error("Document model has no global state schema");
|
|
1808
|
+
const ast = parse(schema);
|
|
1809
|
+
const typeMap = buildStateTypeMap(ast.definitions);
|
|
1810
|
+
const documentName = getDocumentModelSchemaName(model);
|
|
1811
|
+
return expandStateFields(findRootStateType(ast.definitions, [`${documentName}State`, `${documentName}GlobalState`]), typeMap);
|
|
1812
|
+
}
|
|
1813
|
+
function getLocalStateSelection(localSchema, documentName) {
|
|
1814
|
+
const ast = parse(localSchema);
|
|
1815
|
+
const typeMap = buildStateTypeMap(ast.definitions);
|
|
1816
|
+
return expandStateFields(findRootStateType(ast.definitions, [`${documentName}LocalState`]), typeMap);
|
|
1817
|
+
}
|
|
1818
|
+
/**
|
|
1819
|
+
* Builds a query scoped to a document type's own subgraph root field,
|
|
1820
|
+
* selecting the document and its full typed state. The shape mirrors what
|
|
1821
|
+
* the switchboard generates per model (`generateNewApiSchema` in
|
|
1822
|
+
* `create-schema.ts`): `<Name> { document(identifier:) { document { ...
|
|
1823
|
+
* state { auth document global local } } } childIds }`.
|
|
1824
|
+
*/
|
|
1825
|
+
function buildModelScopedQuery(model) {
|
|
1826
|
+
const globalState = model.documentModel.global;
|
|
1827
|
+
const documentName = getDocumentModelSchemaName(model);
|
|
1828
|
+
const globalSelection = getDocumentStateSelection(model);
|
|
1829
|
+
const localSchema = globalState.specifications.at(-1)?.state.local.schema ?? "";
|
|
1830
|
+
const localSelection = localSchema.includes(`type ${documentName}LocalState`) ? getLocalStateSelection(localSchema, documentName) : null;
|
|
1831
|
+
return [
|
|
1832
|
+
"query GetDocument($identifier: String!) {",
|
|
1833
|
+
` ${documentName} {`,
|
|
1834
|
+
" document(identifier: $identifier) {",
|
|
1835
|
+
" document {",
|
|
1836
|
+
" id",
|
|
1837
|
+
" name",
|
|
1838
|
+
" documentType",
|
|
1839
|
+
" state {",
|
|
1840
|
+
" auth",
|
|
1841
|
+
" document { version hash { algorithm encoding } isDeleted deletedAtUtcIso deletedBy deletionReason }",
|
|
1842
|
+
` global { ${globalSelection} }`,
|
|
1843
|
+
` ${localSelection ? `local { ${localSelection} }` : "local"}`,
|
|
1844
|
+
" }",
|
|
1845
|
+
" }",
|
|
1846
|
+
" childIds",
|
|
1847
|
+
" }",
|
|
1848
|
+
" }",
|
|
1849
|
+
"}"
|
|
1850
|
+
].join("\n");
|
|
1851
|
+
}
|
|
1852
|
+
function buildDocumentSubgraphQuery(documentType, identifier, model, authToken) {
|
|
1853
|
+
let query;
|
|
1854
|
+
if (model && model.documentModel.global.id === documentType) try {
|
|
1855
|
+
query = buildModelScopedQuery(model);
|
|
1856
|
+
} catch (error) {
|
|
1857
|
+
console.warn("Could not derive a document-scoped query from the document model, falling back to the generic document query:", error);
|
|
1858
|
+
query = getDocumentGraphqlQuery();
|
|
1859
|
+
}
|
|
1860
|
+
else query = getDocumentGraphqlQuery();
|
|
2899
1861
|
const variables = { identifier };
|
|
2900
1862
|
const headers = authToken ? { Authorization: `Bearer ${authToken}` } : void 0;
|
|
2901
1863
|
const payload = {
|
|
@@ -2905,8 +1867,119 @@ function buildDocumentSubgraphQuery(identifier, authToken) {
|
|
|
2905
1867
|
if (headers) payload.headers = JSON.stringify(headers);
|
|
2906
1868
|
return lzString.compressToEncodedURIComponent(JSON.stringify(payload));
|
|
2907
1869
|
}
|
|
2908
|
-
function buildDocumentSubgraphUrl(
|
|
2909
|
-
|
|
1870
|
+
function buildDocumentSubgraphUrl(channelUrl, documentType, identifier, model, authToken) {
|
|
1871
|
+
const encodedQuery = buildDocumentSubgraphQuery(documentType, identifier, model, authToken);
|
|
1872
|
+
return `${getSwitchboardBaseFromChannelUrl(channelUrl)}/explorer?explorerURLState=${encodedQuery}`;
|
|
1873
|
+
}
|
|
1874
|
+
//#endregion
|
|
1875
|
+
//#region src/utils/upgrade-preview.ts
|
|
1876
|
+
const NON_DOMAIN_SCOPES = new Set(["auth", "document"]);
|
|
1877
|
+
function isPlainObject(value) {
|
|
1878
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1879
|
+
}
|
|
1880
|
+
function walkShapes(before, after, path, added, removed) {
|
|
1881
|
+
if (isPlainObject(before) && isPlainObject(after)) {
|
|
1882
|
+
const beforeKeys = Object.keys(before);
|
|
1883
|
+
const afterKeys = Object.keys(after);
|
|
1884
|
+
for (const key of afterKeys) {
|
|
1885
|
+
const childPath = path ? `${path}.${key}` : key;
|
|
1886
|
+
if (!beforeKeys.includes(key)) {
|
|
1887
|
+
added.push(childPath);
|
|
1888
|
+
continue;
|
|
1889
|
+
}
|
|
1890
|
+
walkShapes(before[key], after[key], childPath, added, removed);
|
|
1891
|
+
}
|
|
1892
|
+
for (const key of beforeKeys) if (!afterKeys.includes(key)) removed.push(path ? `${path}.${key}` : key);
|
|
1893
|
+
return;
|
|
1894
|
+
}
|
|
1895
|
+
if (Array.isArray(before) && Array.isArray(after)) {
|
|
1896
|
+
if (before.length > 0 && after.length > 0) walkShapes(before[0], after[0], `${path}[]`, added, removed);
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
/**
|
|
1900
|
+
* Recursively diffs the structural shape of two values, returning dot-paths
|
|
1901
|
+
* of keys present in `after` but not `before` (added) and vice versa
|
|
1902
|
+
* (removed). Array fields are compared by the shape of a representative
|
|
1903
|
+
* element (the first element on each side, when both sides have one) using
|
|
1904
|
+
* the `path[]` notation, e.g. `todos[].status`. Only key presence is
|
|
1905
|
+
* compared — array length and primitive values are ignored.
|
|
1906
|
+
*/
|
|
1907
|
+
function diffStateShapes(before, after) {
|
|
1908
|
+
const added = [];
|
|
1909
|
+
const removed = [];
|
|
1910
|
+
walkShapes(before, after, "", added, removed);
|
|
1911
|
+
return {
|
|
1912
|
+
added,
|
|
1913
|
+
removed
|
|
1914
|
+
};
|
|
1915
|
+
}
|
|
1916
|
+
/**
|
|
1917
|
+
* Computes a dry-run preview of upgrading `document` to the latest
|
|
1918
|
+
* registered version of its document model: the version jump, the upgrade
|
|
1919
|
+
* steps that will run, and which state fields will be added or removed.
|
|
1920
|
+
* Applies the upgrade reducers against a deep clone of the document, so the
|
|
1921
|
+
* original is left untouched.
|
|
1922
|
+
*
|
|
1923
|
+
* Returns undefined when the registry is unavailable, the document is
|
|
1924
|
+
* already at (or above) the latest registered version, or the upgrade path
|
|
1925
|
+
* cannot be computed.
|
|
1926
|
+
*/
|
|
1927
|
+
function getDocumentUpgradePreview(document, registry) {
|
|
1928
|
+
if (!registry) return;
|
|
1929
|
+
const documentType = document.header.documentType;
|
|
1930
|
+
const fromVersion = document.state.document.version || 1;
|
|
1931
|
+
let latestVersion;
|
|
1932
|
+
try {
|
|
1933
|
+
latestVersion = registry.getLatestVersion(documentType);
|
|
1934
|
+
} catch {
|
|
1935
|
+
return;
|
|
1936
|
+
}
|
|
1937
|
+
if (fromVersion >= latestVersion) return;
|
|
1938
|
+
let transitions;
|
|
1939
|
+
try {
|
|
1940
|
+
transitions = registry.computeUpgradePath(documentType, fromVersion, latestVersion);
|
|
1941
|
+
} catch {
|
|
1942
|
+
return;
|
|
1943
|
+
}
|
|
1944
|
+
const stubAction = {
|
|
1945
|
+
id: "",
|
|
1946
|
+
type: "UPGRADE_DOCUMENT",
|
|
1947
|
+
scope: "document",
|
|
1948
|
+
timestampUtcMs: "",
|
|
1949
|
+
input: {
|
|
1950
|
+
documentId: document.header.id,
|
|
1951
|
+
model: documentType,
|
|
1952
|
+
fromVersion,
|
|
1953
|
+
toVersion: latestVersion
|
|
1954
|
+
}
|
|
1955
|
+
};
|
|
1956
|
+
let upgraded = structuredClone(document);
|
|
1957
|
+
try {
|
|
1958
|
+
for (const transition of transitions) upgraded = transition.upgradeReducer(upgraded, stubAction);
|
|
1959
|
+
} catch {
|
|
1960
|
+
return;
|
|
1961
|
+
}
|
|
1962
|
+
const addedFields = [];
|
|
1963
|
+
const removedFields = [];
|
|
1964
|
+
const scopes = new Set([...Object.keys(document.state), ...Object.keys(upgraded.state)]);
|
|
1965
|
+
for (const scope of scopes) {
|
|
1966
|
+
if (NON_DOMAIN_SCOPES.has(scope)) continue;
|
|
1967
|
+
const beforeScope = document.state[scope];
|
|
1968
|
+
const afterScope = upgraded.state[scope];
|
|
1969
|
+
const { added, removed } = diffStateShapes(beforeScope, afterScope);
|
|
1970
|
+
for (const path of added) addedFields.push(`${scope}.${path}`);
|
|
1971
|
+
for (const path of removed) removedFields.push(`${scope}.${path}`);
|
|
1972
|
+
}
|
|
1973
|
+
return {
|
|
1974
|
+
fromVersion,
|
|
1975
|
+
toVersion: latestVersion,
|
|
1976
|
+
steps: transitions.map((transition) => ({
|
|
1977
|
+
toVersion: transition.toVersion,
|
|
1978
|
+
description: transition.description ?? ""
|
|
1979
|
+
})),
|
|
1980
|
+
addedFields,
|
|
1981
|
+
removedFields
|
|
1982
|
+
};
|
|
2910
1983
|
}
|
|
2911
1984
|
//#endregion
|
|
2912
1985
|
//#region src/hooks/use-get-switchboard-link.ts
|
|
@@ -2924,6 +1997,7 @@ function buildDocumentSubgraphUrl(driveUrl, identifier, authToken) {
|
|
|
2924
1997
|
function useGetSwitchboardLink(document) {
|
|
2925
1998
|
const [drive] = useSelectedDriveSafe();
|
|
2926
1999
|
const remotes = useSyncList();
|
|
2000
|
+
const documentModelModule = useDocumentModelModuleById(document?.header.documentType);
|
|
2927
2001
|
const isRemoteDrive = useMemo(() => {
|
|
2928
2002
|
if (!isDefined(drive)) return false;
|
|
2929
2003
|
return remotes.some((remote) => remote.meta.collectionId.equals(DriveCollectionId$1.forDrive(drive.header.id)));
|
|
@@ -2948,12 +2022,13 @@ function useGetSwitchboardLink(document) {
|
|
|
2948
2022
|
expiresIn: 600,
|
|
2949
2023
|
aud: remoteUrl
|
|
2950
2024
|
}) : void 0;
|
|
2951
|
-
return buildDocumentSubgraphUrl(remoteUrl, document.header.id, token);
|
|
2025
|
+
return buildDocumentSubgraphUrl(remoteUrl, document.header.documentType, document.header.id, documentModelModule, token);
|
|
2952
2026
|
};
|
|
2953
2027
|
}, [
|
|
2954
2028
|
isRemoteDrive,
|
|
2955
2029
|
remoteUrl,
|
|
2956
2030
|
document,
|
|
2031
|
+
documentModelModule,
|
|
2957
2032
|
user,
|
|
2958
2033
|
renown
|
|
2959
2034
|
]);
|
|
@@ -2964,14 +2039,12 @@ const useOnDropFile = (documentTypesOverride) => {
|
|
|
2964
2039
|
const selectedDriveId = useSelectedDriveId();
|
|
2965
2040
|
const selectedFolder = useSelectedFolder();
|
|
2966
2041
|
const documentTypes = useDocumentTypes();
|
|
2967
|
-
const onDropFile = async (file, onProgress, resolveConflict) => {
|
|
2042
|
+
const onDropFile = async (file, targetFolder, onProgress, resolveConflict) => {
|
|
2968
2043
|
if (!selectedDriveId) {
|
|
2969
2044
|
console.warn("No selected drive - upload skipped");
|
|
2970
2045
|
return;
|
|
2971
2046
|
}
|
|
2972
|
-
|
|
2973
|
-
const targetNodeId = selectedFolder?.id;
|
|
2974
|
-
return await addFileWithProgress(file, selectedDriveId, fileName, targetNodeId, onProgress, documentTypesOverride ?? documentTypes, resolveConflict);
|
|
2047
|
+
return await addFileWithProgress(file, selectedDriveId, file.name.replace(/\..+/gim, ""), targetFolder?.id ?? selectedFolder?.id, onProgress, documentTypesOverride ?? documentTypes, resolveConflict);
|
|
2975
2048
|
};
|
|
2976
2049
|
return onDropFile;
|
|
2977
2050
|
};
|
|
@@ -2990,58 +2063,323 @@ function useUserPermissions() {
|
|
|
2990
2063
|
};
|
|
2991
2064
|
}
|
|
2992
2065
|
//#endregion
|
|
2066
|
+
//#region src/hooks/attachment-progress.ts
|
|
2067
|
+
const IDLE_PROGRESS = {
|
|
2068
|
+
percent: 0,
|
|
2069
|
+
loaded: 0,
|
|
2070
|
+
total: void 0,
|
|
2071
|
+
indeterminate: false
|
|
2072
|
+
};
|
|
2073
|
+
function toProgressState(progress) {
|
|
2074
|
+
return {
|
|
2075
|
+
percent: toPercent(progress),
|
|
2076
|
+
loaded: progress.loaded,
|
|
2077
|
+
total: progress.total,
|
|
2078
|
+
indeterminate: progress.indeterminate
|
|
2079
|
+
};
|
|
2080
|
+
}
|
|
2081
|
+
function toPercent(progress) {
|
|
2082
|
+
if (progress.indeterminate) return 0;
|
|
2083
|
+
if (progress.total === void 0) return 0;
|
|
2084
|
+
if (progress.total === 0) return 100;
|
|
2085
|
+
const percent = progress.loaded / progress.total * 100;
|
|
2086
|
+
if (percent < 0) return 0;
|
|
2087
|
+
return percent > 100 ? 100 : percent;
|
|
2088
|
+
}
|
|
2089
|
+
/** Terminal frame for a transfer of `total` bytes, written on resolution. */
|
|
2090
|
+
function doneProgress(total) {
|
|
2091
|
+
return {
|
|
2092
|
+
percent: 100,
|
|
2093
|
+
loaded: total,
|
|
2094
|
+
total,
|
|
2095
|
+
indeterminate: false
|
|
2096
|
+
};
|
|
2097
|
+
}
|
|
2098
|
+
/**
|
|
2099
|
+
* Second coalescer, on top of the client's time throttle, keyed on what
|
|
2100
|
+
* actually changed for a UI rather than on elapsed time:
|
|
2101
|
+
*
|
|
2102
|
+
* - a determinate tick commits only when the whole percent changes, capping
|
|
2103
|
+
* commits at ~101 per transfer no matter how many byte events arrive;
|
|
2104
|
+
* - a tick with no position — indeterminate, or determinate with no
|
|
2105
|
+
* denominator — has no percent to change, so it falls back to a time
|
|
2106
|
+
* budget; otherwise a byte counter with no denominator would never update;
|
|
2107
|
+
* - gaining or losing a position always commits, since the UI switches between
|
|
2108
|
+
* a spinner and a bar. Stage entry is indeterminate at 0%, so without this
|
|
2109
|
+
* the first byte event of a stage reads as "still 0%" and is dropped, and a
|
|
2110
|
+
* 50 MB upload sits on the spinner until it crosses 1%;
|
|
2111
|
+
* - a stage change always commits, because the label changed.
|
|
2112
|
+
*
|
|
2113
|
+
* Uses `Date.now()` so tests can drive it with fake timers.
|
|
2114
|
+
*/
|
|
2115
|
+
function createProgressGate(options) {
|
|
2116
|
+
const budget = options?.indeterminateCommitMs ?? 150;
|
|
2117
|
+
const now = options?.now ?? (() => Date.now());
|
|
2118
|
+
let lastStage;
|
|
2119
|
+
let lastPercent = -1;
|
|
2120
|
+
let lastIndeterminate;
|
|
2121
|
+
let lastTotalKnown;
|
|
2122
|
+
let lastCommitAt = Number.NEGATIVE_INFINITY;
|
|
2123
|
+
return (progress) => {
|
|
2124
|
+
const commit = () => {
|
|
2125
|
+
lastStage = progress.stage;
|
|
2126
|
+
lastPercent = Math.floor(toPercent(progress));
|
|
2127
|
+
lastIndeterminate = progress.indeterminate;
|
|
2128
|
+
lastTotalKnown = progress.total !== void 0;
|
|
2129
|
+
lastCommitAt = now();
|
|
2130
|
+
return true;
|
|
2131
|
+
};
|
|
2132
|
+
if (progress.stage !== lastStage) return commit();
|
|
2133
|
+
if (progress.indeterminate !== lastIndeterminate) return commit();
|
|
2134
|
+
if (progress.total !== void 0 !== lastTotalKnown) return commit();
|
|
2135
|
+
if (progress.indeterminate || progress.total === void 0) return now() - lastCommitAt >= budget ? commit() : false;
|
|
2136
|
+
return Math.floor(toPercent(progress)) !== lastPercent ? commit() : false;
|
|
2137
|
+
};
|
|
2138
|
+
}
|
|
2139
|
+
//#endregion
|
|
2993
2140
|
//#region src/hooks/use-attachments.ts
|
|
2141
|
+
/**
|
|
2142
|
+
* One client per service, shared across every component.
|
|
2143
|
+
*
|
|
2144
|
+
* A per-component `useMemo` handed each caller its own wrapper, so nothing
|
|
2145
|
+
* client-scoped could ever be shared or cached. Keyed weakly so a replaced
|
|
2146
|
+
* service is collectable.
|
|
2147
|
+
*/
|
|
2148
|
+
const clientsByService = /* @__PURE__ */ new WeakMap();
|
|
2149
|
+
function clientFor(service) {
|
|
2150
|
+
const existing = clientsByService.get(service);
|
|
2151
|
+
if (existing) return existing;
|
|
2152
|
+
const created = createAttachmentClient(service);
|
|
2153
|
+
clientsByService.set(service, created);
|
|
2154
|
+
return created;
|
|
2155
|
+
}
|
|
2994
2156
|
/** Returns an IAttachmentClient wrapping the current IAttachmentService, or undefined if none is set. */
|
|
2995
2157
|
function useAttachments() {
|
|
2996
2158
|
const service = useAttachmentService();
|
|
2997
|
-
return
|
|
2998
|
-
}
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
2159
|
+
return service ? clientFor(service) : void 0;
|
|
2160
|
+
}
|
|
2161
|
+
const DEFAULT_PREVIEW_RETRIES = 3;
|
|
2162
|
+
const DEFAULT_PREVIEW_RETRY_DELAY_MS = 3e3;
|
|
2163
|
+
const IDLE_PREVIEW = {
|
|
2164
|
+
url: void 0,
|
|
2165
|
+
header: void 0,
|
|
2166
|
+
loading: false,
|
|
2167
|
+
error: void 0,
|
|
2168
|
+
stage: "idle",
|
|
2169
|
+
progress: IDLE_PROGRESS,
|
|
2170
|
+
attempt: 0,
|
|
2171
|
+
maxAttempts: 1,
|
|
2172
|
+
lastError: void 0
|
|
2173
|
+
};
|
|
2174
|
+
/**
|
|
2175
|
+
* Document-authorized inline preview of an attachment. Downloads the bytes
|
|
2176
|
+
* through the normal authorized flow, exposes them as an object URL, and
|
|
2177
|
+
* revokes it automatically on unmount and whenever documentId/ref change —
|
|
2178
|
+
* editors never touch blobs or URL lifecycles. Failed attempts are retried
|
|
2179
|
+
* (`retries` × `retryDelayMs`) so a preview requested right after attaching
|
|
2180
|
+
* appears as soon as the server's reference index catches up. Progress resets
|
|
2181
|
+
* per attempt; nothing resumes.
|
|
2182
|
+
*/
|
|
2183
|
+
function useAttachmentPreview({ documentId, ref, retries = DEFAULT_PREVIEW_RETRIES, retryDelayMs = DEFAULT_PREVIEW_RETRY_DELAY_MS }) {
|
|
2184
|
+
const client = useAttachments();
|
|
2185
|
+
const [state, setState] = useState(IDLE_PREVIEW);
|
|
2186
|
+
useEffect(() => {
|
|
2187
|
+
if (!client || !ref) {
|
|
2188
|
+
setState(IDLE_PREVIEW);
|
|
2189
|
+
return;
|
|
2190
|
+
}
|
|
2191
|
+
const maxAttempts = retries + 1;
|
|
2192
|
+
let live = true;
|
|
2193
|
+
const controller = new AbortController();
|
|
2194
|
+
let revoke;
|
|
2195
|
+
let timer;
|
|
2196
|
+
let attempt = 0;
|
|
2197
|
+
setState({
|
|
2198
|
+
...IDLE_PREVIEW,
|
|
2199
|
+
loading: true,
|
|
2200
|
+
attempt: 1,
|
|
2201
|
+
maxAttempts
|
|
2202
|
+
});
|
|
2203
|
+
const load = () => {
|
|
2204
|
+
attempt += 1;
|
|
2205
|
+
const gate = createProgressGate();
|
|
2206
|
+
const attemptNumber = attempt;
|
|
2207
|
+
client.downloadObjectUrl({
|
|
2208
|
+
documentId,
|
|
2209
|
+
ref,
|
|
2210
|
+
signal: controller.signal
|
|
2211
|
+
}, { onProgress: (progress) => {
|
|
2212
|
+
if (!live) return;
|
|
2213
|
+
if (progress.stage === "done" || progress.stage === "error") return;
|
|
2214
|
+
if (!gate(progress)) return;
|
|
2215
|
+
setState((prev) => ({
|
|
2216
|
+
...prev,
|
|
2217
|
+
stage: progress.stage,
|
|
2218
|
+
progress: toProgressState(progress)
|
|
2219
|
+
}));
|
|
2220
|
+
} }).then((result) => {
|
|
2221
|
+
if (!live) {
|
|
2222
|
+
result.revoke();
|
|
2223
|
+
return;
|
|
2224
|
+
}
|
|
2225
|
+
revoke = result.revoke;
|
|
2226
|
+
setState((prev) => ({
|
|
2227
|
+
...prev,
|
|
2228
|
+
url: result.url,
|
|
2229
|
+
header: result.header,
|
|
2230
|
+
loading: false,
|
|
2231
|
+
error: void 0,
|
|
2232
|
+
stage: "done",
|
|
2233
|
+
progress: doneProgress(result.header.sizeBytes),
|
|
2234
|
+
attempt: attemptNumber,
|
|
2235
|
+
maxAttempts
|
|
2236
|
+
}));
|
|
2237
|
+
}).catch((err) => {
|
|
2238
|
+
if (!live) return;
|
|
2239
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
2240
|
+
if (attempt < maxAttempts) {
|
|
2241
|
+
setState((prev) => ({
|
|
2242
|
+
...prev,
|
|
2243
|
+
lastError: error,
|
|
2244
|
+
attempt: attempt + 1,
|
|
2245
|
+
progress: IDLE_PROGRESS,
|
|
2246
|
+
stage: "idle"
|
|
2247
|
+
}));
|
|
2248
|
+
timer = setTimeout(load, retryDelayMs);
|
|
2249
|
+
return;
|
|
2250
|
+
}
|
|
2251
|
+
setState((prev) => ({
|
|
2252
|
+
...prev,
|
|
2253
|
+
url: void 0,
|
|
2254
|
+
header: void 0,
|
|
2255
|
+
loading: false,
|
|
2256
|
+
error,
|
|
2257
|
+
lastError: error,
|
|
2258
|
+
stage: "error",
|
|
2259
|
+
attempt: attemptNumber,
|
|
2260
|
+
maxAttempts
|
|
2261
|
+
}));
|
|
2262
|
+
});
|
|
2263
|
+
};
|
|
2264
|
+
load();
|
|
2265
|
+
return () => {
|
|
2266
|
+
live = false;
|
|
2267
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
2268
|
+
controller.abort();
|
|
2269
|
+
revoke?.();
|
|
2270
|
+
};
|
|
2271
|
+
}, [
|
|
2272
|
+
client,
|
|
2273
|
+
documentId,
|
|
2274
|
+
ref,
|
|
2275
|
+
retries,
|
|
2276
|
+
retryDelayMs
|
|
2277
|
+
]);
|
|
2278
|
+
return state;
|
|
2279
|
+
}
|
|
2280
|
+
const IDLE_UPLOAD = {
|
|
2281
|
+
stage: "idle",
|
|
2282
|
+
progress: IDLE_PROGRESS,
|
|
2283
|
+
result: void 0,
|
|
2284
|
+
error: void 0
|
|
2285
|
+
};
|
|
2286
|
+
/**
|
|
2287
|
+
* Full attachment preprocess + upload lifecycle with byte-level progress.
|
|
2288
|
+
*
|
|
2289
|
+
* The two-call split is kept on purpose: the ref must reach the document
|
|
2290
|
+
* before the bytes are committed, so callers preprocess, dispatch the
|
|
2291
|
+
* operation, then upload. The second call routes through `client.upload`
|
|
2292
|
+
* rather than reimplementing the flow, which is what makes progress, dedup
|
|
2293
|
+
* reporting and cancellation identical to the non-React path.
|
|
2294
|
+
*/
|
|
3009
2295
|
function useAttachmentUpload() {
|
|
3010
|
-
const [
|
|
3011
|
-
const [progress, setProgress] = useState(0);
|
|
3012
|
-
const [error, setError] = useState(void 0);
|
|
2296
|
+
const [state, setState] = useState(IDLE_UPLOAD);
|
|
3013
2297
|
const client = useAttachments();
|
|
2298
|
+
const abortRef = useRef(void 0);
|
|
2299
|
+
const mountedRef = useRef(true);
|
|
2300
|
+
const runIdRef = useRef(0);
|
|
2301
|
+
useEffect(() => {
|
|
2302
|
+
mountedRef.current = true;
|
|
2303
|
+
return () => {
|
|
2304
|
+
mountedRef.current = false;
|
|
2305
|
+
};
|
|
2306
|
+
}, []);
|
|
3014
2307
|
return {
|
|
3015
2308
|
preprocess: useCallback(async (file) => {
|
|
3016
2309
|
if (!client) throw new Error("AttachmentClient not available");
|
|
3017
|
-
|
|
3018
|
-
|
|
2310
|
+
const runId = ++runIdRef.current;
|
|
2311
|
+
setState({
|
|
2312
|
+
...IDLE_UPLOAD,
|
|
2313
|
+
stage: "hashing"
|
|
2314
|
+
});
|
|
3019
2315
|
try {
|
|
3020
2316
|
return await client.preprocess(file);
|
|
3021
2317
|
} catch (err) {
|
|
3022
|
-
|
|
3023
|
-
|
|
2318
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
2319
|
+
if (mountedRef.current && runId === runIdRef.current) setState((prev) => ({
|
|
2320
|
+
...prev,
|
|
2321
|
+
stage: "error",
|
|
2322
|
+
error
|
|
2323
|
+
}));
|
|
3024
2324
|
throw err;
|
|
3025
2325
|
}
|
|
3026
2326
|
}, [client]),
|
|
3027
2327
|
upload: useCallback(async (results) => {
|
|
3028
2328
|
if (!client) throw new Error("AttachmentClient not available");
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
2329
|
+
const runId = ++runIdRef.current;
|
|
2330
|
+
const controller = new AbortController();
|
|
2331
|
+
abortRef.current = controller;
|
|
2332
|
+
const gate = createProgressGate();
|
|
2333
|
+
const isCurrent = () => mountedRef.current && runId === runIdRef.current;
|
|
2334
|
+
setState({
|
|
2335
|
+
...IDLE_UPLOAD,
|
|
2336
|
+
stage: "reserving"
|
|
2337
|
+
});
|
|
2338
|
+
let uploadResult;
|
|
3032
2339
|
try {
|
|
3033
|
-
await client.
|
|
2340
|
+
uploadResult = await client.upload({
|
|
2341
|
+
preprocessed: results,
|
|
2342
|
+
signal: controller.signal
|
|
2343
|
+
}, { onProgress: (progress) => {
|
|
2344
|
+
if (!isCurrent()) return;
|
|
2345
|
+
if (progress.stage === "done" || progress.stage === "error") return;
|
|
2346
|
+
if (!gate(progress)) return;
|
|
2347
|
+
setState((prev) => ({
|
|
2348
|
+
...prev,
|
|
2349
|
+
stage: progress.stage,
|
|
2350
|
+
progress: toProgressState(progress)
|
|
2351
|
+
}));
|
|
2352
|
+
} });
|
|
3034
2353
|
} catch (err) {
|
|
3035
|
-
|
|
3036
|
-
|
|
2354
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
2355
|
+
if (isCurrent()) setState((prev) => ({
|
|
2356
|
+
...prev,
|
|
2357
|
+
stage: "error",
|
|
2358
|
+
error
|
|
2359
|
+
}));
|
|
3037
2360
|
throw err;
|
|
3038
2361
|
}
|
|
3039
|
-
|
|
3040
|
-
|
|
2362
|
+
if (isCurrent()) setState((prev) => ({
|
|
2363
|
+
...prev,
|
|
2364
|
+
stage: "done",
|
|
2365
|
+
progress: doneProgress(results.sizeBytes),
|
|
2366
|
+
result: uploadResult,
|
|
2367
|
+
error: void 0
|
|
2368
|
+
}));
|
|
3041
2369
|
}, [client]),
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
2370
|
+
cancel: useCallback(() => {
|
|
2371
|
+
abortRef.current?.abort();
|
|
2372
|
+
}, []),
|
|
2373
|
+
reset: useCallback(() => {
|
|
2374
|
+
runIdRef.current += 1;
|
|
2375
|
+
abortRef.current?.abort();
|
|
2376
|
+
abortRef.current = void 0;
|
|
2377
|
+
setState(IDLE_UPLOAD);
|
|
2378
|
+
}, []),
|
|
2379
|
+
stage: state.stage,
|
|
2380
|
+
progress: state.progress,
|
|
2381
|
+
result: state.result,
|
|
2382
|
+
error: state.error
|
|
3045
2383
|
};
|
|
3046
2384
|
}
|
|
3047
2385
|
//#endregion
|
|
@@ -3340,12 +2678,18 @@ var RemoteClient = class {
|
|
|
3340
2678
|
}
|
|
3341
2679
|
return { operationsByScope };
|
|
3342
2680
|
}
|
|
3343
|
-
/**
|
|
2681
|
+
/**
|
|
2682
|
+
* Push actions to an existing document via MutateDocument.
|
|
2683
|
+
*
|
|
2684
|
+
* Takes the wire shape rather than an in-process `Action`: a signature is a
|
|
2685
|
+
* tuple in one and a string in the other, so the caller projects before it
|
|
2686
|
+
* gets here.
|
|
2687
|
+
*/
|
|
3344
2688
|
async pushActions(documentIdentifier, actions, branch) {
|
|
3345
2689
|
return (await this.client.MutateDocument({
|
|
3346
2690
|
documentIdentifier,
|
|
3347
2691
|
actions,
|
|
3348
|
-
|
|
2692
|
+
branch
|
|
3349
2693
|
})).mutateDocument;
|
|
3350
2694
|
}
|
|
3351
2695
|
/** Create a new document on the remote. */
|
|
@@ -3371,105 +2715,6 @@ var RemoteClient = class {
|
|
|
3371
2715
|
}
|
|
3372
2716
|
};
|
|
3373
2717
|
//#endregion
|
|
3374
|
-
//#region src/remote-controller/utils.ts
|
|
3375
|
-
/** Convert SCREAMING_SNAKE_CASE to camelCase (e.g. "SET_MODEL_NAME" → "setModelName"). */
|
|
3376
|
-
function screamingSnakeToCamel(s) {
|
|
3377
|
-
return s.toLowerCase().replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
|
3378
|
-
}
|
|
3379
|
-
/** Error thrown when a push conflict is detected with the "reject" strategy. */
|
|
3380
|
-
var ConflictError = class extends Error {
|
|
3381
|
-
constructor(conflict) {
|
|
3382
|
-
super("Push conflict: remote has new operations since last pull");
|
|
3383
|
-
this.conflict = conflict;
|
|
3384
|
-
this.name = "ConflictError";
|
|
3385
|
-
}
|
|
3386
|
-
};
|
|
3387
|
-
/** Convert a remote operation to the local Operation type. */
|
|
3388
|
-
function remoteOperationToLocal(remote) {
|
|
3389
|
-
return {
|
|
3390
|
-
id: remote.id ?? "",
|
|
3391
|
-
index: remote.index,
|
|
3392
|
-
skip: remote.skip,
|
|
3393
|
-
timestampUtcMs: remote.timestampUtcMs,
|
|
3394
|
-
hash: remote.hash,
|
|
3395
|
-
error: remote.error ?? void 0,
|
|
3396
|
-
action: {
|
|
3397
|
-
id: remote.action.id,
|
|
3398
|
-
type: remote.action.type,
|
|
3399
|
-
timestampUtcMs: remote.action.timestampUtcMs,
|
|
3400
|
-
input: remote.action.input,
|
|
3401
|
-
scope: remote.action.scope,
|
|
3402
|
-
context: remote.action.context?.signer ? { signer: {
|
|
3403
|
-
user: remote.action.context.signer.user ?? {
|
|
3404
|
-
address: "",
|
|
3405
|
-
networkId: "",
|
|
3406
|
-
chainId: 0
|
|
3407
|
-
},
|
|
3408
|
-
app: remote.action.context.signer.app ?? {
|
|
3409
|
-
name: "",
|
|
3410
|
-
key: ""
|
|
3411
|
-
},
|
|
3412
|
-
signatures: remote.action.context.signer.signatures.map((s) => deserializeSignature(s))
|
|
3413
|
-
} } : void 0
|
|
3414
|
-
}
|
|
3415
|
-
};
|
|
3416
|
-
}
|
|
3417
|
-
/**
|
|
3418
|
-
* Deserialize a signature string back to a 5-element tuple.
|
|
3419
|
-
* The server serializes tuples via `tuple.join(", ")`.
|
|
3420
|
-
*/
|
|
3421
|
-
function deserializeSignature(s) {
|
|
3422
|
-
const parts = s.split(", ");
|
|
3423
|
-
return [
|
|
3424
|
-
parts[0] ?? "",
|
|
3425
|
-
parts[1] ?? "",
|
|
3426
|
-
parts[2] ?? "",
|
|
3427
|
-
parts[3] ?? "",
|
|
3428
|
-
parts[4] ?? ""
|
|
3429
|
-
];
|
|
3430
|
-
}
|
|
3431
|
-
/** Convert remote operations to local DocumentOperations format. */
|
|
3432
|
-
function convertRemoteOperations(operationsByScope) {
|
|
3433
|
-
const operations = {};
|
|
3434
|
-
for (const [scope, remoteOps] of Object.entries(operationsByScope)) operations[scope] = remoteOps.map((op) => remoteOperationToLocal(op));
|
|
3435
|
-
return operations;
|
|
3436
|
-
}
|
|
3437
|
-
/** Reconstruct a PHDocument from remote document data and operations. */
|
|
3438
|
-
function buildPulledDocument(remoteDoc, operations, initialDoc, branch) {
|
|
3439
|
-
return {
|
|
3440
|
-
header: {
|
|
3441
|
-
...initialDoc.header,
|
|
3442
|
-
id: remoteDoc.id,
|
|
3443
|
-
name: remoteDoc.name,
|
|
3444
|
-
slug: remoteDoc.slug ?? "",
|
|
3445
|
-
documentType: remoteDoc.documentType,
|
|
3446
|
-
createdAtUtcIso: typeof remoteDoc.createdAtUtcIso === "string" ? remoteDoc.createdAtUtcIso : remoteDoc.createdAtUtcIso.toISOString(),
|
|
3447
|
-
lastModifiedAtUtcIso: typeof remoteDoc.lastModifiedAtUtcIso === "string" ? remoteDoc.lastModifiedAtUtcIso : remoteDoc.lastModifiedAtUtcIso.toISOString(),
|
|
3448
|
-
revision: Object.fromEntries(remoteDoc.revisionsList.map((r) => [r.scope, r.revision])),
|
|
3449
|
-
branch
|
|
3450
|
-
},
|
|
3451
|
-
state: remoteDoc.state,
|
|
3452
|
-
initialState: initialDoc.initialState,
|
|
3453
|
-
operations,
|
|
3454
|
-
clipboard: []
|
|
3455
|
-
};
|
|
3456
|
-
}
|
|
3457
|
-
/** Extract revision map from a remote document's revisionsList. */
|
|
3458
|
-
function extractRevisionMap(revisionsList) {
|
|
3459
|
-
return Object.fromEntries(revisionsList.map((r) => [r.scope, r.revision]));
|
|
3460
|
-
}
|
|
3461
|
-
/**
|
|
3462
|
-
* Check if any scope in currentRevision is ahead of knownRevision.
|
|
3463
|
-
* When `scopes` is provided, only those scopes are checked.
|
|
3464
|
-
*/
|
|
3465
|
-
function hasRevisionConflict(currentRevision, knownRevision, scopes) {
|
|
3466
|
-
for (const scope in currentRevision) {
|
|
3467
|
-
if (scopes && !scopes.has(scope)) continue;
|
|
3468
|
-
if ((currentRevision[scope] ?? 0) > (knownRevision[scope] ?? 0)) return true;
|
|
3469
|
-
}
|
|
3470
|
-
return false;
|
|
3471
|
-
}
|
|
3472
|
-
//#endregion
|
|
3473
2718
|
//#region src/remote-controller/remote-controller.ts
|
|
3474
2719
|
/**
|
|
3475
2720
|
* A controller that wraps a PHDocumentController with remote push/pull capabilities.
|
|
@@ -3548,7 +2793,7 @@ var RemoteDocumentController = class RemoteDocumentController {
|
|
|
3548
2793
|
if (tracked.length > 0) {
|
|
3549
2794
|
const actions = await this.prepareActionsForPush(tracked);
|
|
3550
2795
|
pushedActions = actions;
|
|
3551
|
-
await this.remoteClient.pushActions(this.documentId, actions, this.options.branch);
|
|
2796
|
+
await this.remoteClient.pushActions(this.documentId, actions.map(toTransportAction), this.options.branch);
|
|
3552
2797
|
}
|
|
3553
2798
|
} catch (error) {
|
|
3554
2799
|
this.tracker.restore(tracked);
|
|
@@ -3860,6 +3105,6 @@ var BrowserLocalStorage = class extends BaseStorage {
|
|
|
3860
3105
|
}
|
|
3861
3106
|
};
|
|
3862
3107
|
//#endregion
|
|
3863
|
-
export { ActionTracker, BaseStorage, BrowserLocalStorage, COMMON_PACKAGE_ID, CREDENTIAL_SCHEMA_EIP712_TYPE, CREDENTIAL_SUBJECT_TYPE, CREDENTIAL_TYPES, ChannelScheme, ChevronDownIcon, ConflictError, CopyIcon, DEFAULT_DRIVE_EDITOR_ID, DEFAULT_DRIVE_ID, DEFAULT_SWITCHBOARD_URL, DOMAIN_TYPE, DRIVE_DOCUMENT_TYPES, DisconnectIcon, DocumentCache, DocumentChangeType, DocumentIntegrityService, DriveCollectionId, EDITOR_FILE_DROP_OPT_OUT_ATTR, GqlRequestChannel, GraphQLClientDocumentCache, ISSUER_TYPE, InMemoryQueue, IntervalPollTimer, PollBehavior, PropagationMode, REACTOR_SCHEMA, RENOWN_CHAIN_ID, RENOWN_NETWORK_ID, RENOWN_URL, ReactorBuilder, ReactorClientBuilder, RegistryClient, RelationalDbProcessor, RemoteClient, RemoteDocumentController, Renown, RenownAuthButton, RenownLoginButton, RenownLogo, RenownUserButton, SpinnerIcon, SyncOperationStatus, UploadStatus, UserIcon, VERIFIABLE_CREDENTIAL_EIP712_TYPE, addAllowListEventHandler, addAllowedDocumentTypesEventHandler, addAnalyticsDatabaseNameEventHandler, addAttachmentServiceEventHandler, addBasePathEventHandler, addCliVersionEventHandler, addDefaultDrivesUrlEventHandler, addDisabledEditorsEventHandler, addDocument, addDocumentCacheEventHandler, addDraggingNodeEventHandler, addDrive, addDrivesEventHandler, addDrivesPreserveStrategyEventHandler, addEnabledEditorsEventHandler, addFeaturesEventHandler, addFileUploadOperationsChunkSizeEventHandler, addFolder, addGaTrackingIdEventHandler, addGraphQLReactorClientEventHandler, addIsAddCloudDrivesEnabledEventHandler, addIsAddDriveEnabledEventHandler, addIsAddLocalDrivesEnabledEventHandler, addIsAddPublicDrivesEnabledEventHandler, addIsAnalyticsDatabaseWorkerEnabledEventHandler, addIsAnalyticsEnabledEventHandler, addIsAnalyticsExternalProcessorsEnabledEventHandler, addIsCloudDrivesEnabledEventHandler, addIsDeleteCloudDrivesEnabledEventHandler, addIsDeleteLocalDrivesEnabledEventHandler, addIsDeletePublicDrivesEnabledEventHandler, addIsDiffAnalyticsEnabledEventHandler, addIsDocumentModelSelectionSettingsEnabledEventHandler, addIsDragAndDropEnabledEventHandler, addIsDriveAnalyticsEnabledEventHandler, addIsEditorDebugModeEnabledEventHandler, addIsEditorReadModeEnabledEventHandler, addIsExternalControlsEnabledEventHandler, addIsExternalPackagesEnabledEventHandler, addIsExternalProcessorsEnabledEventHandler, addIsExternalRelationalProcessorsEnabledEventHandler, addIsLocalDrivesEnabledEventHandler, addIsPublicDrivesEnabledEventHandler, addIsRelationalProcessorsEnabledEventHandler, addIsSentryTracingEnabledEventHandler, addLoadingEventHandler, addLocalDrivesEnabledEventHandler, addLogLevelEventHandler, addModalEventHandler, addPHEventHandlers, addPackageDiscoveryServiceEventHandler, addPromiseState, addReactorClientEventHandler, addReactorClientModuleEventHandler, addRemoteDrive, addRenownChainIdEventHandler, addRenownEventHandler, addRenownNetworkIdEventHandler, addRenownUrlEventHandler, addRequiresHardRefreshEventHandler, addResetSelectedNodeEventHandler, addRevisionHistoryVisibleEventHandler, addRouterBasenameEventHandler, addSelectedDriveIdEventHandler, addSelectedNodeIdEventHandler, addSelectedTimelineItemEventHandler, addSelectedTimelineRevisionEventHandler, addSentryDsnEventHandler, addSentryEnvEventHandler, addSentryReleaseEventHandler, addSetSelectedDriveOnPopStateEventHandler, addSetSelectedNodeOnPopStateEventHandler, addStudioModeEventHandler, addToastEventHandler, addVersionCheckIntervalEventHandler, addVersionEventHandler, addVetraPackageManagerEventHandler, addWarnOutdatedAppEventHandler, baseDocumentModels, baseDocumentModelsMap, buildDocumentSubgraphQuery, buildDocumentSubgraphUrl, callEventHandlerRegisterFunctions, callGlobalSetterForKey, clearGlobal, closePHModal, commonGlobalEventHandlerFunctions, convertRemoteOperations, createAnalyticsStore, createClient, createProcessorQuery, createUrlWithPreservedParams, deleteDrive, deleteNode, deriveSystemUrl, dispatchActions, downloadDocument, driveIdFromUrl, dropAllReactorStorage, exportFile, extractDriveIdFromPath, extractDriveIdFromSlug, extractDriveSlugFromPath, extractNodeIdFromPath, extractNodeIdFromSlug, extractNodeSlugFromPath, findUuid, getAnalyticsStore, getDocumentGraphqlQuery, getDriveIdBySlug, getDrives, getGlobal, getPackages, getPackagesByDocumentType, getPathWithoutBase, getRevisionFromDate, getSlugFromDriveUrl, getSwitchboardGatewayUrlFromDriveUrl, getSyncStatus, getSyncStatusSync, getUserPermissions, graphqlDocumentEvents, graphqlDocumentsEvents, graphqlEventsToSyncDrive, hasPreloadBandwidth, hideRevisionHistory, identifierFromMutateDocumentOperationVariables, initConnectCrypto, initRenownCrypto, initTheme, isDocumentTypeSupported, isDriveAuthError, isExternalControlsEnabledEventFunctions, isFileNodeKind, isFolderNodeKind, loading, login, logout, makeDriveUrlComponent, makeNodeSlug, makePHEventFunctions, openRenown, parseDriveUrl, phAppConfigHooks, phAppConfigSetters, phDocumentEditorConfigHooks, phDocumentEditorConfigSetters, phDocumentFromQuery, phDocumentsFromQuery, phGlobalConfigHooks, phGlobalConfigSetters, preloadEditorModule, reactorGraphqlBatchFetchDocuments, reactorGraphqlCreateDocument, reactorGraphqlDeleteDocument, reactorGraphqlDeleteDocuments, reactorGraphqlFetchDocument, reactorGraphqlMutateDocument, readPromiseState, refreshReactorData, refreshReactorDataClient, renameDrive, renameDriveNode, resolveUrlPathname, setAllowList, setAllowedDocumentTypes, setAnalyticsDatabaseName, setAttachmentService, setBasePath, setCliVersion, setDefaultDrivesUrl, setDefaultPHGlobalConfig, setDisabledEditors, setDocumentCache, setDriveAvailableOffline, setDriveMetadata, setDriveSharingType, setDrives, setDrivesPreserveStrategy, setEnabledEditors, setFeatures, setFileUploadOperationsChunkSize, setGaTrackingId, setGlobal, setGraphQLReactorClient, setIsAddCloudDrivesEnabled, setIsAddDriveEnabled, setIsAddLocalDrivesEnabled, setIsAddPublicDrivesEnabled, setIsAnalyticsDatabaseWorkerEnabled, setIsAnalyticsEnabled, setIsAnalyticsExternalProcessorsEnabled, setIsCloudDrivesEnabled, setIsDeleteCloudDrivesEnabled, setIsDeleteLocalDrivesEnabled, setIsDeletePublicDrivesEnabled, setIsDiffAnalyticsEnabled, setIsDocumentModelSelectionSettingsEnabled, setIsDragAndDropEnabled, setIsDriveAnalyticsEnabled, setIsEditorDebugModeEnabled, setIsEditorReadModeEnabled, setIsExternalControlsEnabled, setIsExternalPackagesEnabled, setIsExternalProcessorsEnabled, setIsExternalRelationalProcessorsEnabled, setIsLocalDrivesEnabled, setIsPublicDrivesEnabled, setIsRelationalProcessorsEnabled, setIsSentryTracingEnabled, setLoading, setLocalDrivesEnabled, setLogLevel, setPGliteDB, setPHAppConfig, setPHAppConfigByKey, setPHDocumentEditorConfig, setPHDocumentEditorConfigByKey, setPHGlobalConfig, setPHGlobalConfigByKey, setPHModal, setPHToast, setPackageDiscoveryService, setReactorClient, setReactorClientModule, setRenown, setRenownChainId, setRenownNetworkId, setRenownUrl, setRequiresHardRefresh, setRevisionHistoryVisible, setRouterBasename, setSelectedDrive, setSelectedDriveId, setSelectedNode, setSelectedTimelineItem, setSelectedTimelineRevision, setSentryDsn, setSentryEnv, setSentryRelease, setStudioMode, setVersion, setVersionCheckInterval, setVetraPackageManager, setWarnOutdatedApp, showCreateDocumentModal, showDeleteNodeModal, showPHModal, showRevisionHistory, sortNodesByName, trimTrailingSlash, truncateAllTables, useAllowList, useAllowedDocumentModelModules, useAllowedDocumentTypes, useAnalyticsDatabaseName, useAppModuleById, useAppModules, useAttachmentService, useAttachmentUpload, useAttachments, useBasePath, useCliVersion, useConnectionState, useConnectionStates, useDatabase, useDefaultAppModule, useDefaultDrivesUrl, useDid, useDisabledEditors, useDispatch, useDocument, useDocumentById, useDocumentCache, useDocumentModelModuleById, useDocumentModelModules, useDocumentOfType, useDocumentOperations, useDocumentSafe, useDocumentTypes, useDocumentTypesInSelectedDrive, useDocuments, useDocumentsByIds, useDocumentsInSelectedDrive, useDocumentsInSelectedFolder, useDownloadDocument, useDragNode, useDriveById, useDriveSystemInfo, useDrives, useDrivesPreserveStrategy, useDropFile, useDropNode, useEditorFileDrop, useEditorModuleById, useEditorModules, useEditorModulesForDocumentType, useEditorPreloader, useEnabledEditors, useFallbackEditorModule, useFeatures, useFileNodesInSelectedDrive, useFileNodesInSelectedFolder, useFileUploadOperationsChunkSize, useFolderById, useFolderNodesInSelectedDrive, useFolderNodesInSelectedFolder, useGaTrackingId, useGetDocument, useGetDocumentAsync, useGetDocuments, useGetSwitchboardLink, useGraphQLReactorClient, useInitReactorGraphqlClient, useIsAddCloudDrivesEnabled, useIsAddDriveEnabled, useIsAddLocalDrivesEnabled, useIsAddPublicDrivesEnabled, useIsAnalyticsDatabaseWorkerEnabled, useIsAnalyticsEnabled, useIsAnalyticsExternalProcessorsEnabled, useIsCloudDrivesEnabled, useIsDeleteCloudDrivesEnabled, useIsDeleteLocalDrivesEnabled, useIsDeletePublicDrivesEnabled, useIsDiffAnalyticsEnabled, useIsDocumentModelSelectionSettingsEnabled, useIsDragAndDropEnabled, useIsDriveAnalyticsEnabled, useIsEditorDebugModeEnabled, useIsEditorReadModeEnabled, useIsExternalControlsEnabled, useIsExternalPackagesEnabled, useIsExternalProcessorsEnabled, useIsExternalRelationalProcessorsEnabled, useIsLocalDrivesEnabled, useIsPublicDrivesEnabled, useIsRelationalProcessorsEnabled, useIsSentryTracingEnabled, useLoading, useLocalDrivesEnabled, useLogLevel, useLoginStatus, useModelRegistry, useNodeActions, useNodeById, useNodeParentFolderById, useNodePathById, useNodesInSelectedDrive, useNodesInSelectedDriveOrFolder, useNodesInSelectedFolder, useOnDropFile, usePGlite, usePHAppConfigByKey, usePHDocumentEditorConfigByKey, usePHGlobalConfigByKey, usePHModal, usePHToast, usePackageDiscoveryService, useParentFolderForSelectedNode, useReactorClient, useReactorClientModule, useRelationalDb, useRelationalQuery, useRenown, useRenownAuth, useRenownChainId, useRenownInit, useRenownNetworkId, useRenownUrl, useRequiresHardRefresh, useResetPHGlobalConfig, useRevisionHistoryVisible, useRouterBasename, useSelectedDocument, useSelectedDocumentId, useSelectedDocumentOfType, useSelectedDocumentSafe, useSelectedDrive, useSelectedDriveId, useSelectedDriveSafe, useSelectedFolder, useSelectedNode, useSelectedNodePath, useSelectedTimelineItem, useSelectedTimelineRevision, useSentryDsn, useSentryEnv, useSentryRelease, useSetDefaultPHGlobalConfig, useSetPHAppConfig, useSetPHDocumentEditorConfig, useSetPHGlobalConfig, useStudioMode, useSubgraphModules, useSupportedDocumentTypesInReactor, useSync, useSyncList, useTheme, useUser, useUserPermissions, useVersion, useVersionCheckInterval, useVetraPackageManager, useVetraPackages, useWarnOutdatedApp, validateDocument, waitForDocumentReady };
|
|
3108
|
+
export { ActionTracker, BaseStorage, BrowserLocalStorage, COMMON_PACKAGE_ID, CREDENTIAL_SCHEMA_EIP712_TYPE, CREDENTIAL_SUBJECT_TYPE, CREDENTIAL_TYPES, ChannelScheme, ChevronDownIcon, ConflictError, CopyIcon, DEFAULT_DRIVE_EDITOR_ID, DEFAULT_DRIVE_ID, DEFAULT_SWITCHBOARD_URL, DOMAIN_TYPE, DRIVE_DOCUMENT_TYPES, DisconnectIcon, DocumentCache, DocumentChangeType, DocumentIntegrityService, DocumentModelNotFoundError, DocumentTypeMismatchError, DriveCollectionId, EDITOR_FILE_DROP_OPT_OUT_ATTR, GqlRequestChannel, GraphQLClientDocumentCache, GraphQLReactorClient, GraphQLReactorProvider, ISSUER_TYPE, InMemoryQueue, IntervalPollTimer, MutateDocumentWithOperationsDocument, NoSelectedDocumentError, PollBehavior, PropagationMode, REACTOR_SCHEMA, RENOWN_CHAIN_ID, RENOWN_INITIAL_ANONYMOUS, RENOWN_INITIAL_UNKNOWN, RENOWN_NETWORK_ID, RENOWN_URL, ReactorBuilder, ReactorClientBuilder, ReactorOperationFieldsFragmentDoc, RegistryClient, RelationalDbProcessor, RemoteClient, RemoteDocumentController, Renown, RenownAuthButton, RenownInitialUserProvider, RenownLoginButton, RenownLogo, RenownProvider, RenownUserButton, RenownWalletProvider, SpinnerIcon, StaticPackageManager, SubgraphSdkRegistry, SyncOperationStatus, UnsupportedDocumentTypeError, UserIcon, VERIFIABLE_CREDENTIAL_EIP712_TYPE, addAllowListEventHandler, addAllowedDocumentTypesEventHandler, addAnalyticsDatabaseNameEventHandler, addAttachmentServiceEventHandler, addBasePathEventHandler, addCliVersionEventHandler, addDefaultDrivesUrlEventHandler, addDisabledEditorsEventHandler, addDocument, addDocumentCacheEventHandler, addDraggingNodeEventHandler, addDrive, addDrivesEventHandler, addDrivesPreserveStrategyEventHandler, addEnabledEditorsEventHandler, addFeaturesEventHandler, addFileUploadOperationsChunkSizeEventHandler, addFileWithProgress, addFolder, addGaTrackingIdEventHandler, addGraphQLReactorClientEventHandler, addIsAddCloudDrivesEnabledEventHandler, addIsAddDriveEnabledEventHandler, addIsAddLocalDrivesEnabledEventHandler, addIsAddPublicDrivesEnabledEventHandler, addIsAnalyticsDatabaseWorkerEnabledEventHandler, addIsAnalyticsEnabledEventHandler, addIsAnalyticsExternalProcessorsEnabledEventHandler, addIsCloudDrivesEnabledEventHandler, addIsDeleteCloudDrivesEnabledEventHandler, addIsDeleteLocalDrivesEnabledEventHandler, addIsDeletePublicDrivesEnabledEventHandler, addIsDiffAnalyticsEnabledEventHandler, addIsDocumentModelSelectionSettingsEnabledEventHandler, addIsDragAndDropEnabledEventHandler, addIsDriveAnalyticsEnabledEventHandler, addIsEditorDebugModeEnabledEventHandler, addIsEditorReadModeEnabledEventHandler, addIsExternalControlsEnabledEventHandler, addIsExternalPackagesEnabledEventHandler, addIsExternalProcessorsEnabledEventHandler, addIsExternalRelationalProcessorsEnabledEventHandler, addIsLocalDrivesEnabledEventHandler, addIsPublicDrivesEnabledEventHandler, addIsRelationalProcessorsEnabledEventHandler, addIsSentryTracingEnabledEventHandler, addLoadingEventHandler, addLocalDrivesEnabledEventHandler, addLogLevelEventHandler, addModalEventHandler, addPHEventHandlers, addPackageDiscoveryServiceEventHandler, addPromiseState, addReactorClientEventHandler, addReactorClientModuleEventHandler, addRemoteDrive, addRenownAdaptersEventHandler, addRenownChainIdEventHandler, addRenownEventHandler, addRenownNetworkIdEventHandler, addRenownUrlEventHandler, addRequiresHardRefreshEventHandler, addResetSelectedNodeEventHandler, addRevisionHistoryVisibleEventHandler, addRouterBasenameEventHandler, addSelectedDriveIdEventHandler, addSelectedNodeIdEventHandler, addSelectedTimelineItemEventHandler, addSelectedTimelineRevisionEventHandler, addSentryDsnEventHandler, addSentryEnvEventHandler, addSentryReleaseEventHandler, addSetSelectedDriveOnPopStateEventHandler, addSetSelectedNodeOnPopStateEventHandler, addStudioModeEventHandler, addSwitchboardUrlEventHandler, addToastEventHandler, addVersionCheckIntervalEventHandler, addVersionEventHandler, addVetraPackageManagerEventHandler, addWarnOutdatedAppEventHandler, ambientRenownTokenProvider, baseDocumentModels, baseDocumentModelsMap, buildDocumentSubgraphQuery, buildDocumentSubgraphUrl, buildFolderZip, callEventHandlerRegisterFunctions, callGlobalSetterForKey, clearGlobal, closePHModal, commonGlobalEventHandlerFunctions, convertRemoteOperations, createAnalyticsStore, createClient, createProcessorQuery, createUrlWithPreservedParams, deleteDrive, deleteNode, deriveSystemUrl, describeGraphQLDocument, diffStateShapes, dispatchActions, downloadDocument, downloadFolderZip, driveIdFromUrl, dropAllReactorStorage, ensurePHEventHandlers, expandBulkArchive, exportFile, extractDriveIdFromPath, extractDriveIdFromSlug, extractDriveSlugFromPath, extractNodeIdFromPath, extractNodeIdFromSlug, extractNodeSlugFromPath, findUuid, getAnalyticsStore, getDocumentExtension, getDocumentGraphqlQuery, getDocumentStateSelection, getDocumentUpgradePreview, getDocumentVersionStatus, getDriveIdBySlug, getDrives, getGlobal, getPackagePage, getPackages, getPackagesByDocumentType, getPackagesForDocumentType, getPathWithoutBase, getRevisionFromDate, getSlugFromDriveUrl, getSwitchboardBaseFromChannelUrl, getSwitchboardGatewayUrlFromDriveUrl, getSyncStatus, getSyncStatusSync, getUserPermissions, graphqlDocumentEvents, graphqlDocumentsEvents, graphqlEventsToSyncDrive, hasPreloadBandwidth, hideRevisionHistory, identifierFromMutateDocumentOperationVariables, initConnectCrypto, initRenownCrypto, initTheme, isDocumentTypeSupported, isDriveAuthError, isExternalControlsEnabledEventFunctions, isFileNodeKind, isFolderNodeKind, isGraphQLReactorClient, loadFile, loading, login, logout, makeAuthConnectionParams, makeAuthMiddleware, makeDriveUrlComponent, makeNodeSlug, makePHEventFunctions, openRenown, packageFromDocumentModels, parseDriveUrl, phAppConfigHooks, phAppConfigSetters, phDocumentEditorConfigHooks, phDocumentEditorConfigSetters, phDocumentFromGetDocument, phDocumentFromMutation, phDocumentFromQuery, phDocumentsFromQuery, phGlobalConfigHooks, phGlobalConfigSetters, preloadEditorModule, prepareSignedActions, reactorGraphqlBatchFetchDocuments, reactorGraphqlCreateDocument, reactorGraphqlDeleteDocument, reactorGraphqlDeleteDocuments, reactorGraphqlFetchDocument, reactorGraphqlMutateDocument, readPromiseState, refreshReactorData, refreshReactorDataClient, renameDrive, renameDriveNode, resolveDocumentModelModule, resolveUrlPathname, revisionMapFromRevisionsList, setAllowList, setAllowedDocumentTypes, setAnalyticsDatabaseName, setAttachmentService, setBasePath, setCliVersion, setDefaultDrivesUrl, setDefaultPHGlobalConfig, setDisabledEditors, setDocumentCache, setDriveAvailableOffline, setDriveMetadata, setDriveSharingType, setDrives, setDrivesPreserveStrategy, setEnabledEditors, setFeatures, setFileUploadOperationsChunkSize, setGaTrackingId, setGlobal, setGraphQLReactorClient, setIsAddCloudDrivesEnabled, setIsAddDriveEnabled, setIsAddLocalDrivesEnabled, setIsAddPublicDrivesEnabled, setIsAnalyticsDatabaseWorkerEnabled, setIsAnalyticsEnabled, setIsAnalyticsExternalProcessorsEnabled, setIsCloudDrivesEnabled, setIsDeleteCloudDrivesEnabled, setIsDeleteLocalDrivesEnabled, setIsDeletePublicDrivesEnabled, setIsDiffAnalyticsEnabled, setIsDocumentModelSelectionSettingsEnabled, setIsDragAndDropEnabled, setIsDriveAnalyticsEnabled, setIsEditorDebugModeEnabled, setIsEditorReadModeEnabled, setIsExternalControlsEnabled, setIsExternalPackagesEnabled, setIsExternalProcessorsEnabled, setIsExternalRelationalProcessorsEnabled, setIsLocalDrivesEnabled, setIsPublicDrivesEnabled, setIsRelationalProcessorsEnabled, setIsSentryTracingEnabled, setLoading, setLocalDrivesEnabled, setLogLevel, setPGliteDB, setPHAppConfig, setPHAppConfigByKey, setPHDocumentEditorConfig, setPHDocumentEditorConfigByKey, setPHGlobalConfig, setPHGlobalConfigByKey, setPHModal, setPHToast, setPackageDiscoveryService, setPreferredEditorOnNode, setReactorClient, setReactorClientModule, setRenown, setRenownAdapters, setRenownChainId, setRenownNetworkId, setRenownUrl, setRequiresHardRefresh, setRevisionHistoryVisible, setRouterBasename, setSelectedDrive, setSelectedDriveId, setSelectedNode, setSelectedTimelineItem, setSelectedTimelineRevision, setSentryDsn, setSentryEnv, setSentryRelease, setStudioMode, setSwitchboardUrl, setVersion, setVersionCheckInterval, setVetraPackageManager, setWarnOutdatedApp, showCreateDocumentModal, showDeleteNodeModal, showPHModal, showRevisionHistory, signStampedAction, sortNodesByName, stampAction, startDocumentChangesSubscription, subgraphUrlFromGraphqlUrl, subscriptionsUrlFromGraphqlUrl, trimTrailingSlash, truncateAllTables, upgradeDocument, useAllowList, useAllowedDocumentModelModules, useAllowedDocumentTypes, useAnalyticsDatabaseName, useAppModuleById, useAppModules, useAttachmentPreview, useAttachmentService, useAttachmentUpload, useAttachments, useBasePath, useCanExecute, useCliVersion, useConnectionState, useConnectionStates, useDatabase, useDefaultAppModule, useDefaultDrivesUrl, useDid, useDisabledEditors, useDispatch, useDocument, useDocumentById, useDocumentCache, useDocumentModelModuleById, useDocumentModelModules, useDocumentOfType, useDocumentOperations, useDocumentSafe, useDocumentTypes, useDocumentTypesInSelectedDrive, useDocumentVersionStatus, useDocuments, useDocumentsByIds, useDocumentsInSelectedDrive, useDocumentsInSelectedFolder, useDownloadDocument, useDownloadFolder, useDragNode, useDriveById, useDriveSystemInfo, useDrives, useDrivesPreserveStrategy, useDropFile, useDropNode, useEditorFileDrop, useEditorModuleById, useEditorModules, useEditorModulesForDocumentType, useEditorPreloader, useEnabledEditors, useFallbackEditorModule, useFeatures, useFileNodesInSelectedDrive, useFileNodesInSelectedFolder, useFileUploadOperationsChunkSize, useFolderById, useFolderNodesInSelectedDrive, useFolderNodesInSelectedFolder, useGaTrackingId, useGetDocument, useGetDocumentAsync, useGetDocuments, useGetSwitchboardLink, useGraphQLReactorClient, useInitReactorGraphqlClient, useIsAddCloudDrivesEnabled, useIsAddDriveEnabled, useIsAddLocalDrivesEnabled, useIsAddPublicDrivesEnabled, useIsAnalyticsDatabaseWorkerEnabled, useIsAnalyticsEnabled, useIsAnalyticsExternalProcessorsEnabled, useIsCloudDrivesEnabled, useIsDeleteCloudDrivesEnabled, useIsDeleteLocalDrivesEnabled, useIsDeletePublicDrivesEnabled, useIsDiffAnalyticsEnabled, useIsDocumentModelSelectionSettingsEnabled, useIsDragAndDropEnabled, useIsDriveAnalyticsEnabled, useIsEditorDebugModeEnabled, useIsEditorReadModeEnabled, useIsExternalControlsEnabled, useIsExternalPackagesEnabled, useIsExternalProcessorsEnabled, useIsExternalRelationalProcessorsEnabled, useIsLocalDrivesEnabled, useIsPublicDrivesEnabled, useIsRelationalProcessorsEnabled, useIsSentryTracingEnabled, useLoading, useLocalDrivesEnabled, useLogLevel, useLoginStatus, useModelRegistry, useNodeActions, useNodeById, useNodeParentFolderById, useNodePathById, useNodesInSelectedDrive, useNodesInSelectedDriveOrFolder, useNodesInSelectedFolder, useOnDropFile, usePGlite, usePHAppConfigByKey, usePHDocumentEditorConfigByKey, usePHGlobalConfigByKey, usePHModal, usePHToast, usePackageDiscoveryService, useParentFolderForSelectedNode, useReactorClient, useReactorClientModule, useRelationalDb, useRelationalQuery, useRenown, useRenownAdapters, useRenownAuth, useRenownAuthAsync, useRenownChainId, useRenownInit, useRenownInitialAuth, useRenownInitialUser, useRenownLoginMethods, useRenownNetworkId, useRenownSessionCookie, useRenownSessionSynced, useRenownUrl, useRenownWalletAdapter, useRequiresHardRefresh, useResetPHGlobalConfig, useRevisionHistoryVisible, useRouterBasename, useSelectedDocument, useSelectedDocumentId, useSelectedDocumentOfType, useSelectedDocumentSafe, useSelectedDrive, useSelectedDriveId, useSelectedDriveSafe, useSelectedFolder, useSelectedNode, useSelectedNodePath, useSelectedTimelineItem, useSelectedTimelineRevision, useSentryDsn, useSentryEnv, useSentryRelease, useSetDefaultPHGlobalConfig, useSetPHAppConfig, useSetPHDocumentEditorConfig, useSetPHGlobalConfig, useStudioMode, useSubgraphModules, useSupportedDocumentTypesInReactor, useSwitchboardClient, useSwitchboardUrl, useSync, useSyncList, useTheme, useUser, useUserPermissions, useVersion, useVersionCheckInterval, useVetraPackageManager, useVetraPackages, useWarnOutdatedApp, validateDocument, viewFilterInputFromViewFilter, waitForDocumentReady };
|
|
3864
3109
|
|
|
3865
3110
|
//# sourceMappingURL=index.js.map
|