@calimero-network/mero-react 2.4.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +255 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +79 -3
- package/dist/index.d.ts +79 -3
- package/dist/index.js +251 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -2294,6 +2294,256 @@ function useDetachContextFromGroup() {
|
|
|
2294
2294
|
);
|
|
2295
2295
|
return { detachContextFromGroup, loading, error };
|
|
2296
2296
|
}
|
|
2297
|
+
function useMigrationStatus(namespaceId, options) {
|
|
2298
|
+
const { mero } = useMero();
|
|
2299
|
+
const [status, setStatus] = react.useState(null);
|
|
2300
|
+
const [loading, setLoading] = react.useState(false);
|
|
2301
|
+
const [error, setError] = react.useState(null);
|
|
2302
|
+
const mountedRef = useMountedRef();
|
|
2303
|
+
const reqRef = react.useRef(0);
|
|
2304
|
+
const refetch = react.useCallback(async () => {
|
|
2305
|
+
if (!mero || !namespaceId) {
|
|
2306
|
+
if (mountedRef.current) {
|
|
2307
|
+
setStatus(null);
|
|
2308
|
+
setError(null);
|
|
2309
|
+
setLoading(false);
|
|
2310
|
+
}
|
|
2311
|
+
return;
|
|
2312
|
+
}
|
|
2313
|
+
const seq = ++reqRef.current;
|
|
2314
|
+
if (mountedRef.current) {
|
|
2315
|
+
setLoading(true);
|
|
2316
|
+
setError(null);
|
|
2317
|
+
}
|
|
2318
|
+
try {
|
|
2319
|
+
const result = await mero.admin.getMigrationStatus(namespaceId);
|
|
2320
|
+
if (mountedRef.current && seq === reqRef.current) {
|
|
2321
|
+
setStatus(result);
|
|
2322
|
+
}
|
|
2323
|
+
} catch (err) {
|
|
2324
|
+
const errorValue = toError(err);
|
|
2325
|
+
if (mountedRef.current && seq === reqRef.current) {
|
|
2326
|
+
setError(errorValue);
|
|
2327
|
+
}
|
|
2328
|
+
} finally {
|
|
2329
|
+
if (mountedRef.current && seq === reqRef.current) {
|
|
2330
|
+
setLoading(false);
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
}, [namespaceId, mero, mountedRef]);
|
|
2334
|
+
react.useEffect(() => {
|
|
2335
|
+
setStatus(null);
|
|
2336
|
+
setError(null);
|
|
2337
|
+
}, [namespaceId]);
|
|
2338
|
+
react.useEffect(() => {
|
|
2339
|
+
void refetch();
|
|
2340
|
+
}, [refetch]);
|
|
2341
|
+
const pollIntervalMs = options?.pollIntervalMs;
|
|
2342
|
+
react.useEffect(() => {
|
|
2343
|
+
if (!pollIntervalMs || !mero || !namespaceId) return;
|
|
2344
|
+
const handle = setInterval(() => void refetch(), pollIntervalMs);
|
|
2345
|
+
return () => clearInterval(handle);
|
|
2346
|
+
}, [pollIntervalMs, mero, namespaceId, refetch]);
|
|
2347
|
+
const rollup = status?.rollup ?? null;
|
|
2348
|
+
const members = status?.members ?? [];
|
|
2349
|
+
return {
|
|
2350
|
+
status,
|
|
2351
|
+
rollup,
|
|
2352
|
+
members,
|
|
2353
|
+
allMigrated: rollup?.allMigrated ?? false,
|
|
2354
|
+
membersPendingSignature: rollup?.membersPendingSignature ?? 0,
|
|
2355
|
+
loading,
|
|
2356
|
+
error,
|
|
2357
|
+
refetch
|
|
2358
|
+
};
|
|
2359
|
+
}
|
|
2360
|
+
function useAppVersion(contextId, expected) {
|
|
2361
|
+
const { mero } = useMero();
|
|
2362
|
+
const [appVersion, setAppVersion] = react.useState(void 0);
|
|
2363
|
+
const [loading, setLoading] = react.useState(false);
|
|
2364
|
+
const [error, setError] = react.useState(null);
|
|
2365
|
+
const mountedRef = useMountedRef();
|
|
2366
|
+
const reqRef = react.useRef(0);
|
|
2367
|
+
const refetch = react.useCallback(async () => {
|
|
2368
|
+
if (!mero || !contextId) {
|
|
2369
|
+
if (mountedRef.current) {
|
|
2370
|
+
setAppVersion(void 0);
|
|
2371
|
+
setError(null);
|
|
2372
|
+
setLoading(false);
|
|
2373
|
+
}
|
|
2374
|
+
return;
|
|
2375
|
+
}
|
|
2376
|
+
const seq = ++reqRef.current;
|
|
2377
|
+
if (mountedRef.current) {
|
|
2378
|
+
setLoading(true);
|
|
2379
|
+
setError(null);
|
|
2380
|
+
}
|
|
2381
|
+
try {
|
|
2382
|
+
const context = await mero.admin.getContext(contextId);
|
|
2383
|
+
if (mountedRef.current && seq === reqRef.current) {
|
|
2384
|
+
setAppVersion(context.applicationVersion);
|
|
2385
|
+
}
|
|
2386
|
+
} catch (err) {
|
|
2387
|
+
const errorValue = toError(err);
|
|
2388
|
+
if (mountedRef.current && seq === reqRef.current) {
|
|
2389
|
+
setError(errorValue);
|
|
2390
|
+
}
|
|
2391
|
+
} finally {
|
|
2392
|
+
if (mountedRef.current && seq === reqRef.current) {
|
|
2393
|
+
setLoading(false);
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
}, [contextId, mero, mountedRef]);
|
|
2397
|
+
react.useEffect(() => {
|
|
2398
|
+
setAppVersion(void 0);
|
|
2399
|
+
setError(null);
|
|
2400
|
+
}, [contextId]);
|
|
2401
|
+
react.useEffect(() => {
|
|
2402
|
+
void refetch();
|
|
2403
|
+
}, [refetch]);
|
|
2404
|
+
react.useEffect(() => {
|
|
2405
|
+
if (!mero?.events || !contextId) return;
|
|
2406
|
+
const off = mero.events.onAppVersionChanged((event) => {
|
|
2407
|
+
if (event.contextId !== contextId) return;
|
|
2408
|
+
if (mountedRef.current && event.toVersion) {
|
|
2409
|
+
reqRef.current += 1;
|
|
2410
|
+
setAppVersion(event.toVersion);
|
|
2411
|
+
}
|
|
2412
|
+
});
|
|
2413
|
+
return off;
|
|
2414
|
+
}, [mero, contextId, mountedRef]);
|
|
2415
|
+
const isStale = appVersion != null && expected != null && appVersion !== expected;
|
|
2416
|
+
return { appVersion, expected, isStale, loading, error, refetch };
|
|
2417
|
+
}
|
|
2418
|
+
function useMyAuthoredMigration(contextId) {
|
|
2419
|
+
const { mero } = useMero();
|
|
2420
|
+
const [summary, setSummary] = react.useState(null);
|
|
2421
|
+
const [pendingCount, setPendingCount] = react.useState(0);
|
|
2422
|
+
const mountedRef = useMountedRef();
|
|
2423
|
+
const { loading, error, run } = useAsyncMutation();
|
|
2424
|
+
const reqRef = react.useRef(0);
|
|
2425
|
+
const refresh = react.useCallback(async () => {
|
|
2426
|
+
if (!mero || !contextId) {
|
|
2427
|
+
if (mountedRef.current) setPendingCount(0);
|
|
2428
|
+
return;
|
|
2429
|
+
}
|
|
2430
|
+
const seq = ++reqRef.current;
|
|
2431
|
+
try {
|
|
2432
|
+
const count = await mero.rpc.countMyPending(contextId);
|
|
2433
|
+
if (mountedRef.current && seq === reqRef.current) setPendingCount(count);
|
|
2434
|
+
} catch {
|
|
2435
|
+
}
|
|
2436
|
+
}, [mero, contextId, mountedRef]);
|
|
2437
|
+
react.useEffect(() => {
|
|
2438
|
+
void refresh();
|
|
2439
|
+
}, [refresh]);
|
|
2440
|
+
const authorize = react.useCallback(async () => {
|
|
2441
|
+
if (!mero || !contextId) return null;
|
|
2442
|
+
const result = await run(() => mero.rpc.migrateMyEntries(contextId));
|
|
2443
|
+
if (result && mountedRef.current) {
|
|
2444
|
+
reqRef.current += 1;
|
|
2445
|
+
setSummary(result);
|
|
2446
|
+
setPendingCount(result.remaining);
|
|
2447
|
+
}
|
|
2448
|
+
return result;
|
|
2449
|
+
}, [mero, contextId, run, mountedRef]);
|
|
2450
|
+
return {
|
|
2451
|
+
summary,
|
|
2452
|
+
pendingCount,
|
|
2453
|
+
pending: pendingCount > 0,
|
|
2454
|
+
authorize,
|
|
2455
|
+
loading,
|
|
2456
|
+
error,
|
|
2457
|
+
refresh
|
|
2458
|
+
};
|
|
2459
|
+
}
|
|
2460
|
+
function MigrationPendingBanner({
|
|
2461
|
+
contextId,
|
|
2462
|
+
className,
|
|
2463
|
+
children,
|
|
2464
|
+
onMigrated
|
|
2465
|
+
}) {
|
|
2466
|
+
const { pending, pendingCount, authorize, loading } = useMyAuthoredMigration(contextId);
|
|
2467
|
+
if (!pending) return null;
|
|
2468
|
+
const handleClick = async () => {
|
|
2469
|
+
const result = await authorize();
|
|
2470
|
+
if (result && result.remaining === 0) {
|
|
2471
|
+
onMigrated?.();
|
|
2472
|
+
}
|
|
2473
|
+
};
|
|
2474
|
+
const message = children ?? `You have ${pendingCount} ${pendingCount === 1 ? "entry" : "entries"} to re-sign after a recent upgrade.`;
|
|
2475
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, "data-testid": "migration-pending-banner", role: "status", children: [
|
|
2476
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: message }),
|
|
2477
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: handleClick, disabled: loading, children: loading ? "Migrating\u2026" : "Migrate my data" })
|
|
2478
|
+
] });
|
|
2479
|
+
}
|
|
2480
|
+
function MigrationAdminPanel({ namespaceId, pollIntervalMs, className }) {
|
|
2481
|
+
const { status, rollup, members, membersPendingSignature, error } = useMigrationStatus(
|
|
2482
|
+
namespaceId,
|
|
2483
|
+
{ pollIntervalMs }
|
|
2484
|
+
);
|
|
2485
|
+
if (error && !status) {
|
|
2486
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, "data-testid": "migration-admin-panel", children: [
|
|
2487
|
+
"Failed to load migration status: ",
|
|
2488
|
+
error.message
|
|
2489
|
+
] });
|
|
2490
|
+
}
|
|
2491
|
+
if (!status || !rollup) {
|
|
2492
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, "data-testid": "migration-admin-panel", children: "Loading migration status\u2026" });
|
|
2493
|
+
}
|
|
2494
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, "data-testid": "migration-admin-panel", children: [
|
|
2495
|
+
error && // A poll failed after data was already loaded — keep showing the last
|
|
2496
|
+
// good rollup but flag that it may be stale.
|
|
2497
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { "data-testid": "migration-status-error", role: "alert", children: [
|
|
2498
|
+
"Could not refresh migration status: ",
|
|
2499
|
+
error.message
|
|
2500
|
+
] }),
|
|
2501
|
+
/* @__PURE__ */ jsxRuntime.jsxs("dl", { children: [
|
|
2502
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2503
|
+
/* @__PURE__ */ jsxRuntime.jsx("dt", { children: "Target version" }),
|
|
2504
|
+
/* @__PURE__ */ jsxRuntime.jsx("dd", { children: status.targetVersion })
|
|
2505
|
+
] }),
|
|
2506
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2507
|
+
/* @__PURE__ */ jsxRuntime.jsx("dt", { children: "Migrated" }),
|
|
2508
|
+
/* @__PURE__ */ jsxRuntime.jsx("dd", { children: rollup.migrated })
|
|
2509
|
+
] }),
|
|
2510
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2511
|
+
/* @__PURE__ */ jsxRuntime.jsx("dt", { children: "In progress" }),
|
|
2512
|
+
/* @__PURE__ */ jsxRuntime.jsx("dd", { children: rollup.inProgress })
|
|
2513
|
+
] }),
|
|
2514
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2515
|
+
/* @__PURE__ */ jsxRuntime.jsx("dt", { children: "Unknown" }),
|
|
2516
|
+
/* @__PURE__ */ jsxRuntime.jsx("dd", { children: rollup.unknown })
|
|
2517
|
+
] }),
|
|
2518
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2519
|
+
/* @__PURE__ */ jsxRuntime.jsx("dt", { children: "Total" }),
|
|
2520
|
+
/* @__PURE__ */ jsxRuntime.jsx("dd", { children: rollup.total })
|
|
2521
|
+
] }),
|
|
2522
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2523
|
+
/* @__PURE__ */ jsxRuntime.jsx("dt", { children: "All migrated" }),
|
|
2524
|
+
/* @__PURE__ */ jsxRuntime.jsx("dd", { children: rollup.allMigrated ? "yes" : "no" })
|
|
2525
|
+
] }),
|
|
2526
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2527
|
+
/* @__PURE__ */ jsxRuntime.jsx("dt", { children: "Members pending signature" }),
|
|
2528
|
+
/* @__PURE__ */ jsxRuntime.jsx("dd", { "data-testid": "members-pending-signature", children: membersPendingSignature })
|
|
2529
|
+
] })
|
|
2530
|
+
] }),
|
|
2531
|
+
/* @__PURE__ */ jsxRuntime.jsxs("table", { children: [
|
|
2532
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
2533
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { children: "Peer" }),
|
|
2534
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { children: "State" }),
|
|
2535
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { children: "Schema" }),
|
|
2536
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { children: "Pending" })
|
|
2537
|
+
] }) }),
|
|
2538
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { children: members.map((m) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { "data-testid": "migration-member-row", children: [
|
|
2539
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { children: m.peer }),
|
|
2540
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { children: m.state }),
|
|
2541
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { children: m.report?.schemaVersion ?? "\u2014" }),
|
|
2542
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { children: m.report?.authoredRemaining ?? "\u2014" })
|
|
2543
|
+
] }, m.peer)) })
|
|
2544
|
+
] })
|
|
2545
|
+
] });
|
|
2546
|
+
}
|
|
2297
2547
|
|
|
2298
2548
|
Object.defineProperty(exports, "CAPABILITIES", {
|
|
2299
2549
|
enumerable: true,
|
|
@@ -2319,6 +2569,8 @@ exports.LoginModal = LoginModal;
|
|
|
2319
2569
|
exports.MERO_CSS_VARS = MERO_CSS_VARS;
|
|
2320
2570
|
exports.MeroContext = MeroContext;
|
|
2321
2571
|
exports.MeroProvider = MeroProvider;
|
|
2572
|
+
exports.MigrationAdminPanel = MigrationAdminPanel;
|
|
2573
|
+
exports.MigrationPendingBanner = MigrationPendingBanner;
|
|
2322
2574
|
exports.clearAllStorage = clearAllStorage;
|
|
2323
2575
|
exports.clearApplicationId = clearApplicationId;
|
|
2324
2576
|
exports.clearContextId = clearContextId;
|
|
@@ -2338,6 +2590,7 @@ exports.setContextIdentity = setContextIdentity;
|
|
|
2338
2590
|
exports.setNodeUrl = setNodeUrl;
|
|
2339
2591
|
exports.themeToCssVars = themeToCssVars;
|
|
2340
2592
|
exports.useAddGroupMembers = useAddGroupMembers;
|
|
2593
|
+
exports.useAppVersion = useAppVersion;
|
|
2341
2594
|
exports.useApplicationContexts = useApplicationContexts;
|
|
2342
2595
|
exports.useContextDiscovery = useContextDiscovery;
|
|
2343
2596
|
exports.useContextGroup = useContextGroup;
|
|
@@ -2365,6 +2618,8 @@ exports.useJoinNamespace = useJoinNamespace;
|
|
|
2365
2618
|
exports.useJoinSubgroupInheritance = useJoinSubgroupInheritance;
|
|
2366
2619
|
exports.useMemberMetadata = useMemberMetadata;
|
|
2367
2620
|
exports.useMero = useMero;
|
|
2621
|
+
exports.useMigrationStatus = useMigrationStatus;
|
|
2622
|
+
exports.useMyAuthoredMigration = useMyAuthoredMigration;
|
|
2368
2623
|
exports.useNamespace = useNamespace;
|
|
2369
2624
|
exports.useNamespaceGroups = useNamespaceGroups;
|
|
2370
2625
|
exports.useNamespaceIdentity = useNamespaceIdentity;
|