@codemem/server 0.32.3 → 0.33.0-alpha.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/dist/index.js +93 -23
- package/dist/index.js.map +1 -1
- package/dist/routes/sync.d.ts.map +1 -1
- package/package.json +2 -2
- package/static/app.js +247 -463
package/static/app.js
CHANGED
|
@@ -3200,21 +3200,6 @@
|
|
|
3200
3200
|
async function loadPairing(includeDiagnostics = false) {
|
|
3201
3201
|
return fetchJson(`/api/sync/pairing${includeDiagnostics ? "?includeDiagnostics=1" : ""}`);
|
|
3202
3202
|
}
|
|
3203
|
-
async function updatePeerScope(peerDeviceId, include, exclude, inheritGlobal = false) {
|
|
3204
|
-
const resp = await fetch("/api/sync/peers/scope", {
|
|
3205
|
-
method: "POST",
|
|
3206
|
-
headers: { "Content-Type": "application/json" },
|
|
3207
|
-
body: JSON.stringify({
|
|
3208
|
-
peer_device_id: peerDeviceId,
|
|
3209
|
-
include,
|
|
3210
|
-
exclude,
|
|
3211
|
-
inherit_global: inheritGlobal
|
|
3212
|
-
})
|
|
3213
|
-
});
|
|
3214
|
-
const { text, payload } = await readJsonPayload(resp);
|
|
3215
|
-
if (!resp.ok) throw new Error(payloadError(payload) || text || "request failed");
|
|
3216
|
-
return payload;
|
|
3217
|
-
}
|
|
3218
3203
|
async function assignPeerActor(peerDeviceId, actorId) {
|
|
3219
3204
|
const resp = await fetch("/api/sync/peers/identity", {
|
|
3220
3205
|
method: "POST",
|
|
@@ -3497,7 +3482,7 @@
|
|
|
3497
3482
|
function escapeHtml(value) {
|
|
3498
3483
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
3499
3484
|
}
|
|
3500
|
-
function escapeRegExp(value) {
|
|
3485
|
+
function escapeRegExp$1(value) {
|
|
3501
3486
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3502
3487
|
}
|
|
3503
3488
|
function highlightText(text, query) {
|
|
@@ -3505,7 +3490,7 @@
|
|
|
3505
3490
|
if (!q) return escapeHtml(text);
|
|
3506
3491
|
const safe = escapeHtml(text);
|
|
3507
3492
|
try {
|
|
3508
|
-
const re = new RegExp(`(${escapeRegExp(q)})`, "ig");
|
|
3493
|
+
const re = new RegExp(`(${escapeRegExp$1(q)})`, "ig");
|
|
3509
3494
|
return safe.replace(re, "<mark class=\"match\">$1</mark>");
|
|
3510
3495
|
} catch {
|
|
3511
3496
|
return safe;
|
|
@@ -4103,6 +4088,23 @@
|
|
|
4103
4088
|
return /* @__PURE__ */ u("input", { ...props });
|
|
4104
4089
|
}
|
|
4105
4090
|
//#endregion
|
|
4091
|
+
//#region src/tabs/coordinator-admin/data/device-card.ts
|
|
4092
|
+
function coordinatorAdminDeviceCardCopy(device, fallbackTeamId) {
|
|
4093
|
+
const deviceId = String(device.device_id || "").trim();
|
|
4094
|
+
const teamId = String(device.group_id || fallbackTeamId || "").trim();
|
|
4095
|
+
const displayName = String(device.display_name || deviceId || "Unnamed device");
|
|
4096
|
+
const enabled = device.enabled !== false && device.enabled !== 0;
|
|
4097
|
+
const advancedParts = [`Device ID ${deviceId || "unknown"}`];
|
|
4098
|
+
if (teamId) advancedParts.push(`Team ID ${teamId}`);
|
|
4099
|
+
return {
|
|
4100
|
+
advancedDetail: `Advanced: ${advancedParts.join(" · ")}`,
|
|
4101
|
+
deviceId,
|
|
4102
|
+
displayName,
|
|
4103
|
+
statusLabel: enabled ? "Enabled in this Team" : "Disabled in this Team",
|
|
4104
|
+
teamId
|
|
4105
|
+
};
|
|
4106
|
+
}
|
|
4107
|
+
//#endregion
|
|
4106
4108
|
//#region src/tabs/coordinator-admin/data/state.ts
|
|
4107
4109
|
var ADMIN_TARGET_GROUP_KEY = "codemem-coordinator-admin-target-group";
|
|
4108
4110
|
var coordinatorAdminState = {
|
|
@@ -4138,17 +4140,16 @@
|
|
|
4138
4140
|
return _$3(RadixTabsContent, {
|
|
4139
4141
|
className: "coordinator-admin-panel",
|
|
4140
4142
|
value: "devices"
|
|
4141
|
-
}, _$3("h3", null, "Enrolled devices"), _$3("p", { class: "peer-submeta" }, summary.readiness === "ready" ? "Rename, disable, re-enable, or remove
|
|
4142
|
-
const
|
|
4143
|
-
const
|
|
4144
|
-
const displayName = String(item.display_name || deviceId || "Unnamed device");
|
|
4143
|
+
}, _$3("h3", null, "Enrolled devices"), _$3("p", { class: "peer-submeta" }, summary.readiness === "ready" ? "Rename, disable, re-enable, or remove Team devices here. Space access is granted from Spaces below; Team membership alone does not share memories." : "Finish setup first. Device administration stays disabled until coordinator admin is ready."), !items.length ? _$3("div", { class: "peer-meta" }, summary.readiness === "ready" ? "No enrolled devices found for the active coordinator group." : "Device administration will appear here once setup is complete.") : _$3("div", { class: "peer-list" }, items.map((item) => {
|
|
4144
|
+
const copy = coordinatorAdminDeviceCardCopy(item, String(state.lastCoordinatorAdminStatus?.active_group || ""));
|
|
4145
|
+
const { deviceId, displayName, teamId } = copy;
|
|
4145
4146
|
const pending = coordinatorAdminState.deviceActionPendingId === deviceId;
|
|
4146
4147
|
const draft = coordinatorAdminState.deviceRenameDrafts.get(deviceId) ?? String(item.display_name || "");
|
|
4147
4148
|
const enabled = item.enabled !== false && item.enabled !== 0;
|
|
4148
4149
|
return _$3("div", {
|
|
4149
4150
|
class: "peer-card peer-card--padded",
|
|
4150
4151
|
key: deviceId || String(item.fingerprint || "unknown")
|
|
4151
|
-
}, _$3("div", { class: "peer-title" }, _$3("strong", null, draft || displayName)), _$3("div", { class: "peer-
|
|
4152
|
+
}, _$3("div", { class: "peer-title" }, _$3("strong", null, draft || displayName)), _$3("div", { class: "peer-submeta" }, copy.statusLabel), _$3("div", { class: "peer-meta" }, copy.advancedDetail), _$3("div", { class: "coordinator-admin-form-grid" }, _$3("label", { class: "coordinator-admin-field" }, _$3("span", null, "Display name"), _$3(TextInput, {
|
|
4152
4153
|
class: "peer-scope-input",
|
|
4153
4154
|
disabled: summary.readiness !== "ready" || pending,
|
|
4154
4155
|
onInput: (event) => {
|
|
@@ -4159,22 +4160,22 @@
|
|
|
4159
4160
|
}))), _$3("div", { class: "peer-actions" }, _$3("button", {
|
|
4160
4161
|
class: "settings-button",
|
|
4161
4162
|
disabled: !deviceId || pending || summary.readiness !== "ready",
|
|
4162
|
-
onClick: () => runDevice(deviceId,
|
|
4163
|
+
onClick: () => runDevice(deviceId, teamId, displayName, "rename"),
|
|
4163
4164
|
type: "button"
|
|
4164
4165
|
}, pending && coordinatorAdminState.deviceActionPendingKind === "rename" ? "Renaming…" : "Rename"), enabled ? _$3("button", {
|
|
4165
4166
|
class: "settings-button danger",
|
|
4166
4167
|
disabled: !deviceId || pending || summary.readiness !== "ready",
|
|
4167
|
-
onClick: () => runDevice(deviceId,
|
|
4168
|
+
onClick: () => runDevice(deviceId, teamId, displayName, "disable"),
|
|
4168
4169
|
type: "button"
|
|
4169
4170
|
}, pending && coordinatorAdminState.deviceActionPendingKind === "disable" ? "Disabling…" : "Disable") : _$3("button", {
|
|
4170
4171
|
class: "settings-button",
|
|
4171
4172
|
disabled: !deviceId || pending || summary.readiness !== "ready",
|
|
4172
|
-
onClick: () => runDevice(deviceId,
|
|
4173
|
+
onClick: () => runDevice(deviceId, teamId, displayName, "enable"),
|
|
4173
4174
|
type: "button"
|
|
4174
4175
|
}, pending && coordinatorAdminState.deviceActionPendingKind === "enable" ? "Enabling…" : "Enable"), _$3("button", {
|
|
4175
4176
|
class: "settings-button danger",
|
|
4176
4177
|
disabled: !deviceId || pending || summary.readiness !== "ready",
|
|
4177
|
-
onClick: () => runDevice(deviceId,
|
|
4178
|
+
onClick: () => runDevice(deviceId, teamId, displayName, "remove"),
|
|
4178
4179
|
type: "button"
|
|
4179
4180
|
}, pending && coordinatorAdminState.deviceActionPendingKind === "remove" ? "Removing…" : "Remove")));
|
|
4180
4181
|
})));
|
|
@@ -10057,6 +10058,36 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
10057
10058
|
const value = String(status || "active").trim();
|
|
10058
10059
|
return value ? value.replaceAll("_", " ") : "active";
|
|
10059
10060
|
}
|
|
10061
|
+
function spaceCardCopy(scope) {
|
|
10062
|
+
const title = String(scope.label || "").trim() || "Untitled Space";
|
|
10063
|
+
const status = scopeStatusLabel(scope.status);
|
|
10064
|
+
const kind = String(scope.kind || "user").replaceAll("_", " ");
|
|
10065
|
+
const scopeId = String(scope.scope_id || "").trim() || "unknown";
|
|
10066
|
+
const epoch = scope.membership_epoch == null ? "—" : String(scope.membership_epoch);
|
|
10067
|
+
return {
|
|
10068
|
+
title,
|
|
10069
|
+
summary: `${status} Space · ${kind}`,
|
|
10070
|
+
advancedDetail: `Advanced: Space ID ${scopeId} · Membership epoch ${epoch}`
|
|
10071
|
+
};
|
|
10072
|
+
}
|
|
10073
|
+
function spaceAccessDeviceCopy(row) {
|
|
10074
|
+
const statusLabel = {
|
|
10075
|
+
active: "Space access active",
|
|
10076
|
+
revoked: "Space access revoked",
|
|
10077
|
+
not_member: "No Space access"
|
|
10078
|
+
};
|
|
10079
|
+
const role = row.role.replaceAll("_", " ");
|
|
10080
|
+
const detail = row.status === "not_member" ? statusLabel[row.status] : `${statusLabel[row.status]} · ${role}`;
|
|
10081
|
+
const epoch = row.membershipEpoch == null ? "—" : String(row.membershipEpoch);
|
|
10082
|
+
return {
|
|
10083
|
+
statusLabel: statusLabel[row.status],
|
|
10084
|
+
detail,
|
|
10085
|
+
advancedDetail: `Advanced: membership epoch ${epoch}`
|
|
10086
|
+
};
|
|
10087
|
+
}
|
|
10088
|
+
function spaceRevokeMemberTitle(scope, displayName, deviceId) {
|
|
10089
|
+
return `Revoke ${displayName || deviceId || "this device"} from ${spaceCardCopy(scope).title}?`;
|
|
10090
|
+
}
|
|
10060
10091
|
function deriveScopeMembershipDeviceRows(devices, members) {
|
|
10061
10092
|
const memberByDevice = new Map(members.map((member) => [String(member.device_id || "").trim(), member]).filter(([deviceId]) => deviceId.length > 0));
|
|
10062
10093
|
return devices.map((device) => {
|
|
@@ -10251,7 +10282,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
10251
10282
|
const scopeId = String(scope.scope_id || "").trim();
|
|
10252
10283
|
if (!scopeId) return;
|
|
10253
10284
|
if (!await openSyncConfirmDialog({
|
|
10254
|
-
title:
|
|
10285
|
+
title: spaceRevokeMemberTitle(scope, displayName, deviceId),
|
|
10255
10286
|
description: "Revocation only blocks future sync for this Space. Data already copied to that device can remain there.",
|
|
10256
10287
|
confirmLabel: "Revoke membership",
|
|
10257
10288
|
cancelLabel: "Keep membership",
|
|
@@ -10290,31 +10321,30 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
10290
10321
|
const pending = draft.actionPendingKey === pendingKey;
|
|
10291
10322
|
const canGrant = row.enabled && row.status !== "active";
|
|
10292
10323
|
const canRevoke = row.status === "active";
|
|
10293
|
-
const
|
|
10294
|
-
const epochCopy = row.membershipEpoch == null ? "epoch —" : `epoch ${row.membershipEpoch}`;
|
|
10324
|
+
const copy = spaceAccessDeviceCopy(row);
|
|
10295
10325
|
return _$3("div", {
|
|
10296
10326
|
class: "coordinator-admin-scope-member-row",
|
|
10297
10327
|
key: row.deviceId
|
|
10298
|
-
}, _$3("div", { class: "coordinator-admin-scope-member-copy" }, _$3("strong", null, row.displayName), _$3("span", null,
|
|
10328
|
+
}, _$3("div", { class: "coordinator-admin-scope-member-copy" }, _$3("strong", null, row.displayName), _$3("span", null, copy.detail), _$3("span", { class: "peer-meta" }, copy.advancedDetail), row.enabled ? null : _$3("span", null, "Device is disabled in this Team.")), _$3("div", { class: "peer-actions" }, canGrant ? _$3("button", {
|
|
10299
10329
|
class: "settings-button",
|
|
10300
10330
|
disabled: !ready || Boolean(draft.actionPendingKey),
|
|
10301
10331
|
onClick: () => void grantMember(groupId, scopeId, row.deviceId, renderShell),
|
|
10302
10332
|
type: "button"
|
|
10303
|
-
}, pending && draft.actionPendingKind === "grant" ? "Granting…" : "Grant") : null, canRevoke ? _$3("button", {
|
|
10333
|
+
}, pending && draft.actionPendingKind === "grant" ? "Granting…" : "Grant access") : null, canRevoke ? _$3("button", {
|
|
10304
10334
|
class: "settings-button danger",
|
|
10305
10335
|
disabled: !ready || Boolean(draft.actionPendingKey),
|
|
10306
10336
|
onClick: () => void revokeMember(groupId, scope, row.deviceId, row.displayName, renderShell),
|
|
10307
10337
|
type: "button"
|
|
10308
|
-
}, pending && draft.actionPendingKind === "revoke" ? "Revoking…" : "Revoke") : null));
|
|
10338
|
+
}, pending && draft.actionPendingKind === "revoke" ? "Revoking…" : "Revoke access") : null));
|
|
10309
10339
|
}));
|
|
10310
10340
|
}
|
|
10311
10341
|
function renderScopeCard(groupId, scope, draft, ready, renderShell) {
|
|
10312
10342
|
const scopeId = String(scope.scope_id || "").trim();
|
|
10313
|
-
const
|
|
10343
|
+
const copy = spaceCardCopy(scope);
|
|
10314
10344
|
return _$3("div", {
|
|
10315
10345
|
class: "peer-card peer-card--padded coordinator-admin-scope-card",
|
|
10316
|
-
key: scopeId ||
|
|
10317
|
-
}, _$3("div", { class: "peer-title" }, _$3("strong", null,
|
|
10346
|
+
key: scopeId || copy.title
|
|
10347
|
+
}, _$3("div", { class: "peer-title" }, _$3("strong", null, copy.title)), _$3("div", { class: "peer-submeta" }, copy.summary), _$3("div", { class: "peer-meta" }, copy.advancedDetail), _$3("div", { class: "peer-submeta" }, "Devices below are enrolled in the Team; only active Space members can sync this data boundary."), renderMembershipRows(groupId, scope, draft, ready, renderShell));
|
|
10318
10348
|
}
|
|
10319
10349
|
function renderGroupScopeManagementPanel(deps) {
|
|
10320
10350
|
const { groupId, ready, summary, renderShell } = deps;
|
|
@@ -10482,10 +10512,10 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
10482
10512
|
const includeLabelId = `coord-admin-scope-include-${groupId}`;
|
|
10483
10513
|
const excludeLabelId = `coord-admin-scope-exclude-${groupId}`;
|
|
10484
10514
|
const fieldsDisabled = !ready || draft.saving || !draft.auto_seed_scope;
|
|
10485
|
-
return _$3(k$3, null, _$3("h4", { class: "coordinator-admin-drawer-title" }, "Team defaults"), _$3("div", { class: "peer-submeta" }, "
|
|
10515
|
+
return _$3(k$3, null, _$3("h4", { class: "coordinator-admin-drawer-title" }, "Team defaults"), _$3("div", { class: "peer-submeta" }, "Space access grants decide what new devices can sync. Advanced sharing rules only narrow future writes after Space access already exists."), _$3("label", { class: "coordinator-admin-inline-filter" }, _$3("span", {
|
|
10486
10516
|
class: "section-meta",
|
|
10487
10517
|
id: autoSeedLabelId
|
|
10488
|
-
}, "Auto-
|
|
10518
|
+
}, "Auto-apply advanced rules to new devices"), _$3(RadixSwitch, {
|
|
10489
10519
|
"aria-labelledby": autoSeedLabelId,
|
|
10490
10520
|
checked: draft.auto_seed_scope,
|
|
10491
10521
|
className: "coordinator-admin-switch",
|
|
@@ -10516,7 +10546,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
10516
10546
|
renderShell();
|
|
10517
10547
|
},
|
|
10518
10548
|
thumbClassName: "coordinator-admin-switch-thumb"
|
|
10519
|
-
})), draft.default_space_scope_id ? _$3("div", { class: "peer-submeta" }, "Default Space configured.") : _$3("div", { class: "peer-submeta" }, "No default Space has been created yet."), _$3("div", { class: "coordinator-admin-field" }, _$3("span", { id: includeLabelId }, "Include
|
|
10549
|
+
})), draft.default_space_scope_id ? _$3("div", { class: "peer-submeta" }, "Default Space configured.") : _$3("div", { class: "peer-submeta" }, "No default Space has been created yet."), _$3("div", { class: "coordinator-admin-field" }, _$3("span", { id: includeLabelId }, "Include template"), _$3(ProjectScopePicker, {
|
|
10520
10550
|
"aria-labelledby": includeLabelId,
|
|
10521
10551
|
availableProjects: coordinatorAdminState.availableProjects,
|
|
10522
10552
|
disabled: fieldsDisabled,
|
|
@@ -10531,7 +10561,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
10531
10561
|
},
|
|
10532
10562
|
placeholder: "Add project",
|
|
10533
10563
|
values: draft.projects_include
|
|
10534
|
-
}), _$3("span", { class: "peer-submeta" }, "Leave empty to allow every project. Type to search or create a new name.")), _$3("div", { class: "coordinator-admin-field" }, _$3("span", { id: excludeLabelId }, "Exclude
|
|
10564
|
+
}), _$3("span", { class: "peer-submeta" }, "Leave empty to allow every project inside the granted Space. Type to search or create a new name.")), _$3("div", { class: "coordinator-admin-field" }, _$3("span", { id: excludeLabelId }, "Exclude template"), _$3(ProjectScopePicker, {
|
|
10535
10565
|
"aria-labelledby": excludeLabelId,
|
|
10536
10566
|
availableProjects: coordinatorAdminState.availableProjects,
|
|
10537
10567
|
disabled: fieldsDisabled,
|
|
@@ -10837,7 +10867,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
10837
10867
|
return _$3(RadixTabsContent, {
|
|
10838
10868
|
className: "coordinator-admin-panel",
|
|
10839
10869
|
value: "join-requests"
|
|
10840
|
-
}, _$3("h3", null, "Pending join requests"), _$3("p", { class: "peer-submeta" }, summary.readiness === "ready" ? "Approve or deny
|
|
10870
|
+
}, _$3("h3", null, "Pending join requests"), _$3("p", { class: "peer-submeta" }, summary.readiness === "ready" ? "Approve or deny devices that want to join this Team. Default Space access is handled by Team defaults and can be reviewed in Spaces." : "Finish setup first. Join request review stays disabled until coordinator admin is ready."), !items.length ? _$3("div", { class: "peer-meta" }, summary.readiness === "ready" ? "No pending join requests right now." : "Join request review will appear here once setup is complete.") : _$3("div", { class: "peer-list" }, items.map((item) => {
|
|
10841
10871
|
const requestId = String(item.request_id || "").trim();
|
|
10842
10872
|
const deviceId = String(item.device_id || "unknown-device");
|
|
10843
10873
|
const displayName = String(item.display_name || deviceId);
|
|
@@ -10845,7 +10875,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
10845
10875
|
return _$3("div", {
|
|
10846
10876
|
class: "peer-card peer-card--padded",
|
|
10847
10877
|
key: requestId || deviceId
|
|
10848
|
-
}, _$3("div", { class: "peer-title" }, _$3("strong", null, displayName)), _$3("div", { class: "peer-meta" }, `
|
|
10878
|
+
}, _$3("div", { class: "peer-title" }, _$3("strong", null, displayName)), _$3("div", { class: "peer-meta" }, `Advanced: Device ID ${deviceId}`), _$3("div", { class: "peer-actions" }, _$3("button", {
|
|
10849
10879
|
class: "settings-button",
|
|
10850
10880
|
disabled: !requestId || pending,
|
|
10851
10881
|
onClick: () => reviewJoinRequest(requestId, "approve"),
|
|
@@ -10963,7 +10993,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
10963
10993
|
state.lastTeamInvite = result;
|
|
10964
10994
|
coordinatorAdminState.inviteGroup = groupId;
|
|
10965
10995
|
const warnings = Array.isArray(result.warnings) ? result.warnings : [];
|
|
10966
|
-
showGlobalNotice(warnings.length ? `Invite created. Review ${warnings.length === 1 ? "the warning" : `${warnings.length} warnings`} before sharing it.` : "Invite created. Copy it from
|
|
10996
|
+
showGlobalNotice(warnings.length ? `Invite created. Review ${warnings.length === 1 ? "the warning" : `${warnings.length} warnings`} before sharing it.` : "Invite created. Copy it from Teams and share it with your teammate.", warnings.length ? "warning" : "success");
|
|
10967
10997
|
} catch (error) {
|
|
10968
10998
|
showGlobalNotice(error instanceof Error ? error.message : "Failed to create invite.", "warning");
|
|
10969
10999
|
} finally {
|
|
@@ -18095,11 +18125,16 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
18095
18125
|
warning: false
|
|
18096
18126
|
};
|
|
18097
18127
|
}
|
|
18098
|
-
if (failedItems.filter((item) =>
|
|
18128
|
+
if (failedItems.filter((item) => isTrustFailureError(cleanText(item.error))).length === failedItems.length) return {
|
|
18099
18129
|
ok: false,
|
|
18100
18130
|
message: "This device no longer has two-way trust with the peer. Pair it again from the other device, or remove the stale local record if it should be gone.",
|
|
18101
18131
|
warning: true
|
|
18102
18132
|
};
|
|
18133
|
+
if (failedItems.filter((item) => isScopeMembershipFailureError(cleanText(item.error))).length === failedItems.length) return {
|
|
18134
|
+
ok: false,
|
|
18135
|
+
message: "Sync ran, but the peer is not authorized for one or more Spaces. Review Space access for this device in Teams, then sync again.",
|
|
18136
|
+
warning: true
|
|
18137
|
+
};
|
|
18103
18138
|
if (failedItems.length < items.length) return {
|
|
18104
18139
|
ok: false,
|
|
18105
18140
|
message: `${failedItems.length} of ${items.length} device sync attempts failed. Open the affected device cards for the specific errors.`,
|
|
@@ -18111,6 +18146,41 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
18111
18146
|
warning: true
|
|
18112
18147
|
};
|
|
18113
18148
|
}
|
|
18149
|
+
/**
|
|
18150
|
+
* True when a sync-failure error string looks like a two-way-trust failure
|
|
18151
|
+
* (401 unauthorized on the peer's /v1/status), which is the only class of
|
|
18152
|
+
* failure that should trigger the "no longer has two-way trust" toast. Any
|
|
18153
|
+
* other class — connectivity, scope/membership, generation mismatch — flows
|
|
18154
|
+
* through the generic mixed-failure or scoped paths so users do not get
|
|
18155
|
+
* pointed at re-pairing for problems that re-pairing will not fix.
|
|
18156
|
+
*/
|
|
18157
|
+
function isTrustFailureError(error) {
|
|
18158
|
+
const lower = error.toLowerCase();
|
|
18159
|
+
return lower.includes("401") && lower.includes("unauthorized");
|
|
18160
|
+
}
|
|
18161
|
+
/**
|
|
18162
|
+
* True when a sync-failure error string indicates the peer is not authorized
|
|
18163
|
+
* for a Space (or is authorized at a stale epoch). These failures map to the
|
|
18164
|
+
* scoped-sync protocol classes documented in
|
|
18165
|
+
* docs/plans/2026-05-25-scoped-sync-protocol.md:
|
|
18166
|
+
*
|
|
18167
|
+
* - `403: scope_rejected` from POST /v1/ops outbound scope filter.
|
|
18168
|
+
* - `409: reset_required` with `reason=missing_scope` or `stale_epoch`
|
|
18169
|
+
* from GET /v1/ops or GET /v1/snapshot.
|
|
18170
|
+
* - syncOneScope's aggregate string only when it includes one of those wire
|
|
18171
|
+
* reasons. Other scoped-sync failures remain generic sync failures.
|
|
18172
|
+
*
|
|
18173
|
+
* Detection is intentionally substring-based because the wire reason can
|
|
18174
|
+
* arrive embedded in a longer error string from the address-fallback loop.
|
|
18175
|
+
*/
|
|
18176
|
+
function isScopeMembershipFailureError(error) {
|
|
18177
|
+
const lower = error.toLowerCase();
|
|
18178
|
+
if (lower.includes("scope_rejected")) return true;
|
|
18179
|
+
if (lower.includes("missing_scope")) return true;
|
|
18180
|
+
if (lower.includes("stale_epoch")) return true;
|
|
18181
|
+
if (lower.includes("scope_inactive")) return true;
|
|
18182
|
+
return false;
|
|
18183
|
+
}
|
|
18114
18184
|
function outboundFilterLabel(detail) {
|
|
18115
18185
|
const reason = cleanText(detail?.reason);
|
|
18116
18186
|
return OUTBOUND_FILTER_LABELS[reason] ?? (reason.replaceAll("_", " ") || "sync filters");
|
|
@@ -18261,8 +18331,9 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
18261
18331
|
function derivePeerAuthorizedDomainsView(peer) {
|
|
18262
18332
|
const domains = (Array.isArray(peer.authorized_scopes) ? peer.authorized_scopes : []).map((scope) => {
|
|
18263
18333
|
const scopeId = cleanText(scope.scope_id);
|
|
18264
|
-
const
|
|
18265
|
-
if (!scopeId && !
|
|
18334
|
+
const rawLabel = cleanText(scope.label);
|
|
18335
|
+
if (!scopeId && !rawLabel) return null;
|
|
18336
|
+
const label = rawLabel || "Untitled Space";
|
|
18266
18337
|
const detail = [
|
|
18267
18338
|
labelPart(cleanText(scope.kind), "user"),
|
|
18268
18339
|
labelPart(cleanText(scope.authority_type), "local"),
|
|
@@ -18270,17 +18341,17 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
18270
18341
|
].filter(Boolean).join(" · ");
|
|
18271
18342
|
return {
|
|
18272
18343
|
scopeId: scopeId || label,
|
|
18273
|
-
label
|
|
18344
|
+
label,
|
|
18274
18345
|
detail
|
|
18275
18346
|
};
|
|
18276
18347
|
}).filter((item) => item != null);
|
|
18277
18348
|
const total = domains.length;
|
|
18278
18349
|
return {
|
|
18279
18350
|
total,
|
|
18280
|
-
badgeLabel: total === 1 ? "1
|
|
18351
|
+
badgeLabel: total === 1 ? "1 Space" : total > 1 ? `${total} Spaces` : "No Space access",
|
|
18281
18352
|
isWarning: total === 0,
|
|
18282
18353
|
domains,
|
|
18283
|
-
emptyMessage: "No
|
|
18354
|
+
emptyMessage: "No Space access grants exist for this device yet. Advanced project filters cannot send data by themselves."
|
|
18284
18355
|
};
|
|
18285
18356
|
}
|
|
18286
18357
|
var PERSONAL_SCOPE_WORDS = [
|
|
@@ -18360,25 +18431,32 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
18360
18431
|
title: ""
|
|
18361
18432
|
};
|
|
18362
18433
|
return {
|
|
18363
|
-
badgeLabel: "Review
|
|
18364
|
-
detail: "
|
|
18434
|
+
badgeLabel: "Review Space fit",
|
|
18435
|
+
detail: "Team discovery helps find the device, and advanced project filters only narrow already-authorized Spaces. Neither one grants missing work/client Space access.",
|
|
18365
18436
|
isVisible: true,
|
|
18366
|
-
message: "This
|
|
18367
|
-
title: "Check this device's
|
|
18437
|
+
message: "This Team-discovered device has personal or OSS Space access, but no separate work/client-like Space access. If this device is meant for work/client sync, grant that Space explicitly before treating sync as validated.",
|
|
18438
|
+
title: "Check this device's Space access"
|
|
18368
18439
|
};
|
|
18369
18440
|
}
|
|
18441
|
+
function hasActiveProjectNarrowing(include, exclude) {
|
|
18442
|
+
const normalizedInclude = include.map((item) => item.trim()).filter(Boolean);
|
|
18443
|
+
return normalizedInclude.length > 0 && !normalizedInclude.includes("*") || exclude.length > 0;
|
|
18444
|
+
}
|
|
18370
18445
|
function derivePeerProjectNarrowingView(scope) {
|
|
18371
18446
|
const effectiveInclude = cleanList(scope?.effective_include);
|
|
18372
18447
|
const effectiveExclude = cleanList(scope?.effective_exclude);
|
|
18373
18448
|
const sourceLabel = scope?.inherits_global ? "Global defaults" : "Device override";
|
|
18374
18449
|
const includeLabel = `Include filter: ${shortList(effectiveInclude, "all projects")}`;
|
|
18375
18450
|
const excludeLabel = `Exclude filter: ${shortList(effectiveExclude, "no exclusions")}`;
|
|
18451
|
+
const hasAdvancedFilters = hasActiveProjectNarrowing(effectiveInclude, effectiveExclude);
|
|
18376
18452
|
return {
|
|
18453
|
+
hasAdvancedFilters,
|
|
18454
|
+
statusLabel: hasAdvancedFilters ? "Advanced filters active" : "No advanced filters",
|
|
18377
18455
|
sourceLabel,
|
|
18378
18456
|
includeLabel,
|
|
18379
18457
|
excludeLabel,
|
|
18380
18458
|
summary: `${sourceLabel}. ${includeLabel}; ${excludeLabel}.`,
|
|
18381
|
-
note: "
|
|
18459
|
+
note: "Advanced filters only narrow data after Space access; they never grant access to another Space."
|
|
18382
18460
|
};
|
|
18383
18461
|
}
|
|
18384
18462
|
//#endregion
|
|
@@ -18685,6 +18763,18 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
18685
18763
|
const unique = Array.from(new Set(addresses.filter(Boolean)));
|
|
18686
18764
|
return typeof unique[0] === "string" ? unique[0] : "";
|
|
18687
18765
|
}
|
|
18766
|
+
/**
|
|
18767
|
+
* Returns true when a "Removed peer X" style feedback message is stale
|
|
18768
|
+
* because the related peer has reappeared in the loaded peers list (e.g.
|
|
18769
|
+
* the user re-paired the same device they just removed). Used by
|
|
18770
|
+
* renderSyncPeers to clear the persistent banner once the user's view
|
|
18771
|
+
* of reality contradicts it.
|
|
18772
|
+
*/
|
|
18773
|
+
function shouldClearStalePeersFeedback(feedback, peers) {
|
|
18774
|
+
const id = String(feedback?.relatedPeerDeviceId ?? "").trim();
|
|
18775
|
+
if (!id) return false;
|
|
18776
|
+
return peers.some((peer) => String(peer?.peer_device_id ?? "").trim() === id);
|
|
18777
|
+
}
|
|
18688
18778
|
function actorLabel(actor) {
|
|
18689
18779
|
if (!actor || typeof actor !== "object") return "Unknown person";
|
|
18690
18780
|
const displayName = String(actor.display_name || "").trim();
|
|
@@ -18730,208 +18820,6 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
18730
18820
|
if (!targetActorId || !target) return "Choose which person should keep these devices.";
|
|
18731
18821
|
return `Merge into ${actorDisplayLabel(target)}. Assigned devices move now; existing memories keep their current provenance.`;
|
|
18732
18822
|
}
|
|
18733
|
-
function createChipEditor(initialValues, placeholder, emptyLabel, availableProjects = []) {
|
|
18734
|
-
let values = [...initialValues];
|
|
18735
|
-
let query = "";
|
|
18736
|
-
let activeIndex = 0;
|
|
18737
|
-
let popoverOpen = false;
|
|
18738
|
-
const container = el$1("div", "project-scope-picker");
|
|
18739
|
-
const selectedList = el$1("ul", "project-scope-picker-selected");
|
|
18740
|
-
const trigger = el$1("button", "project-scope-picker-trigger settings-button");
|
|
18741
|
-
trigger.type = "button";
|
|
18742
|
-
const triggerLabel = el$1("span", null, placeholder || "Add project");
|
|
18743
|
-
const triggerPlus = el$1("span", null, "+");
|
|
18744
|
-
triggerPlus.setAttribute("aria-hidden", "true");
|
|
18745
|
-
trigger.append(triggerPlus, triggerLabel);
|
|
18746
|
-
trigger.setAttribute("aria-haspopup", "listbox");
|
|
18747
|
-
trigger.setAttribute("aria-expanded", "false");
|
|
18748
|
-
const popover = el$1("div", "project-scope-picker-popover project-scope-picker-popover--inline");
|
|
18749
|
-
popover.hidden = true;
|
|
18750
|
-
const search = el$1("input", "project-scope-picker-search");
|
|
18751
|
-
search.type = "text";
|
|
18752
|
-
search.placeholder = "Search or create…";
|
|
18753
|
-
search.setAttribute("aria-label", "Search projects");
|
|
18754
|
-
const results = el$1("div", "project-scope-picker-results");
|
|
18755
|
-
results.setAttribute("role", "listbox");
|
|
18756
|
-
popover.append(search, results);
|
|
18757
|
-
const knownPool = () => {
|
|
18758
|
-
const seen = /* @__PURE__ */ new Set();
|
|
18759
|
-
const out = [];
|
|
18760
|
-
for (const item of [...availableProjects, ...values]) {
|
|
18761
|
-
const trimmed = item.trim();
|
|
18762
|
-
if (!trimmed || seen.has(trimmed)) continue;
|
|
18763
|
-
seen.add(trimmed);
|
|
18764
|
-
out.push(trimmed);
|
|
18765
|
-
}
|
|
18766
|
-
return out.sort((a, b) => a.localeCompare(b));
|
|
18767
|
-
};
|
|
18768
|
-
const filteredRows = () => {
|
|
18769
|
-
const all = knownPool();
|
|
18770
|
-
const q = query.trim().toLowerCase();
|
|
18771
|
-
if (!q) return all;
|
|
18772
|
-
return all.filter((project) => project.toLowerCase().includes(q));
|
|
18773
|
-
};
|
|
18774
|
-
const shouldShowCreateRow = () => {
|
|
18775
|
-
const q = query.trim();
|
|
18776
|
-
if (!q) return false;
|
|
18777
|
-
return !knownPool().some((project) => project.toLowerCase() === q.toLowerCase());
|
|
18778
|
-
};
|
|
18779
|
-
const toggleValue = (project) => {
|
|
18780
|
-
if (values.includes(project)) values = values.filter((value) => value !== project);
|
|
18781
|
-
else values = Array.from(new Set([...values, project]));
|
|
18782
|
-
renderSelected();
|
|
18783
|
-
renderResults();
|
|
18784
|
-
};
|
|
18785
|
-
const createFromQuery = () => {
|
|
18786
|
-
const trimmed = query.trim();
|
|
18787
|
-
if (!trimmed) return;
|
|
18788
|
-
values = Array.from(new Set([...values, trimmed]));
|
|
18789
|
-
query = "";
|
|
18790
|
-
search.value = "";
|
|
18791
|
-
activeIndex = 0;
|
|
18792
|
-
renderSelected();
|
|
18793
|
-
renderResults();
|
|
18794
|
-
};
|
|
18795
|
-
const activateRow = (index) => {
|
|
18796
|
-
const rows = filteredRows();
|
|
18797
|
-
if (index < rows.length) {
|
|
18798
|
-
const project = rows[index];
|
|
18799
|
-
if (project) toggleValue(project);
|
|
18800
|
-
return;
|
|
18801
|
-
}
|
|
18802
|
-
if (shouldShowCreateRow()) createFromQuery();
|
|
18803
|
-
};
|
|
18804
|
-
const renderSelected = () => {
|
|
18805
|
-
selectedList.textContent = "";
|
|
18806
|
-
if (!values.length) {
|
|
18807
|
-
const note = el$1("li", "project-scope-picker-selected-empty", emptyLabel);
|
|
18808
|
-
selectedList.appendChild(note);
|
|
18809
|
-
return;
|
|
18810
|
-
}
|
|
18811
|
-
values.forEach((value) => {
|
|
18812
|
-
const chip = el$1("li", "project-scope-picker-selected-chip");
|
|
18813
|
-
const label = el$1("span", null, value);
|
|
18814
|
-
const remove = el$1("button", "project-scope-picker-selected-remove", "×");
|
|
18815
|
-
remove.type = "button";
|
|
18816
|
-
remove.setAttribute("aria-label", `Remove ${value}`);
|
|
18817
|
-
remove.addEventListener("click", () => {
|
|
18818
|
-
values = values.filter((existing) => existing !== value);
|
|
18819
|
-
renderSelected();
|
|
18820
|
-
renderResults();
|
|
18821
|
-
});
|
|
18822
|
-
chip.append(label, remove);
|
|
18823
|
-
selectedList.appendChild(chip);
|
|
18824
|
-
});
|
|
18825
|
-
};
|
|
18826
|
-
const renderResults = () => {
|
|
18827
|
-
results.textContent = "";
|
|
18828
|
-
const rows = filteredRows();
|
|
18829
|
-
const withCreate = shouldShowCreateRow();
|
|
18830
|
-
const rowCount = rows.length + (withCreate ? 1 : 0);
|
|
18831
|
-
if (activeIndex >= rowCount) activeIndex = Math.max(0, rowCount - 1);
|
|
18832
|
-
if (!rows.length && !withCreate) {
|
|
18833
|
-
const empty = el$1("div", "project-scope-picker-empty-row", "No projects yet. Type a name to create one.");
|
|
18834
|
-
results.appendChild(empty);
|
|
18835
|
-
return;
|
|
18836
|
-
}
|
|
18837
|
-
rows.forEach((project, index) => {
|
|
18838
|
-
const selected = values.includes(project);
|
|
18839
|
-
const row = el$1("button", index === activeIndex ? "project-scope-picker-row project-scope-picker-row--active" : "project-scope-picker-row");
|
|
18840
|
-
row.type = "button";
|
|
18841
|
-
row.setAttribute("role", "option");
|
|
18842
|
-
row.setAttribute("aria-selected", selected ? "true" : "false");
|
|
18843
|
-
const check = el$1("span", "project-scope-picker-row-check", selected ? "✓" : "");
|
|
18844
|
-
check.setAttribute("aria-hidden", "true");
|
|
18845
|
-
const labelEl = el$1("span", "project-scope-picker-row-label", project);
|
|
18846
|
-
row.append(check, labelEl);
|
|
18847
|
-
row.addEventListener("click", () => {
|
|
18848
|
-
activeIndex = index;
|
|
18849
|
-
toggleValue(project);
|
|
18850
|
-
});
|
|
18851
|
-
row.addEventListener("mouseenter", () => {
|
|
18852
|
-
activeIndex = index;
|
|
18853
|
-
renderResults();
|
|
18854
|
-
});
|
|
18855
|
-
results.appendChild(row);
|
|
18856
|
-
});
|
|
18857
|
-
if (withCreate) {
|
|
18858
|
-
const index = rows.length;
|
|
18859
|
-
const row = el$1("button", index === activeIndex ? "project-scope-picker-row project-scope-picker-row--create project-scope-picker-row--active" : "project-scope-picker-row project-scope-picker-row--create");
|
|
18860
|
-
row.type = "button";
|
|
18861
|
-
row.setAttribute("role", "option");
|
|
18862
|
-
const check = el$1("span", "project-scope-picker-row-check", "+");
|
|
18863
|
-
check.setAttribute("aria-hidden", "true");
|
|
18864
|
-
const labelEl = el$1("span", "project-scope-picker-row-label", `Create "${query.trim()}"`);
|
|
18865
|
-
row.append(check, labelEl);
|
|
18866
|
-
row.addEventListener("click", () => createFromQuery());
|
|
18867
|
-
row.addEventListener("mouseenter", () => {
|
|
18868
|
-
activeIndex = index;
|
|
18869
|
-
renderResults();
|
|
18870
|
-
});
|
|
18871
|
-
results.appendChild(row);
|
|
18872
|
-
}
|
|
18873
|
-
};
|
|
18874
|
-
const setOpen = (next) => {
|
|
18875
|
-
popoverOpen = next;
|
|
18876
|
-
popover.hidden = !next;
|
|
18877
|
-
trigger.setAttribute("aria-expanded", next ? "true" : "false");
|
|
18878
|
-
if (next) {
|
|
18879
|
-
query = "";
|
|
18880
|
-
search.value = "";
|
|
18881
|
-
activeIndex = 0;
|
|
18882
|
-
renderResults();
|
|
18883
|
-
requestAnimationFrame(() => search.focus());
|
|
18884
|
-
}
|
|
18885
|
-
};
|
|
18886
|
-
trigger.addEventListener("click", (event) => {
|
|
18887
|
-
event.stopPropagation();
|
|
18888
|
-
setOpen(!popoverOpen);
|
|
18889
|
-
});
|
|
18890
|
-
search.addEventListener("input", () => {
|
|
18891
|
-
query = search.value;
|
|
18892
|
-
activeIndex = 0;
|
|
18893
|
-
renderResults();
|
|
18894
|
-
});
|
|
18895
|
-
search.addEventListener("keydown", (event) => {
|
|
18896
|
-
const rowCount = filteredRows().length + (shouldShowCreateRow() ? 1 : 0);
|
|
18897
|
-
if (event.key === "ArrowDown") {
|
|
18898
|
-
event.preventDefault();
|
|
18899
|
-
activeIndex = Math.min(rowCount - 1, activeIndex + 1);
|
|
18900
|
-
renderResults();
|
|
18901
|
-
return;
|
|
18902
|
-
}
|
|
18903
|
-
if (event.key === "ArrowUp") {
|
|
18904
|
-
event.preventDefault();
|
|
18905
|
-
activeIndex = Math.max(0, activeIndex - 1);
|
|
18906
|
-
renderResults();
|
|
18907
|
-
return;
|
|
18908
|
-
}
|
|
18909
|
-
if (event.key === "Enter") {
|
|
18910
|
-
event.preventDefault();
|
|
18911
|
-
activateRow(activeIndex);
|
|
18912
|
-
return;
|
|
18913
|
-
}
|
|
18914
|
-
if (event.key === "Escape") {
|
|
18915
|
-
event.preventDefault();
|
|
18916
|
-
setOpen(false);
|
|
18917
|
-
}
|
|
18918
|
-
});
|
|
18919
|
-
const onDocumentClick = (event) => {
|
|
18920
|
-
if (!popoverOpen) return;
|
|
18921
|
-
const target = event.target;
|
|
18922
|
-
if (!target) return;
|
|
18923
|
-
if (container.contains(target)) return;
|
|
18924
|
-
setOpen(false);
|
|
18925
|
-
};
|
|
18926
|
-
document.addEventListener("click", onDocumentClick);
|
|
18927
|
-
container.append(selectedList, trigger, popover);
|
|
18928
|
-
renderSelected();
|
|
18929
|
-
renderResults();
|
|
18930
|
-
return {
|
|
18931
|
-
element: container,
|
|
18932
|
-
values: () => [...values]
|
|
18933
|
-
};
|
|
18934
|
-
}
|
|
18935
18823
|
function renderActionList(container, actions) {
|
|
18936
18824
|
if (!container) return;
|
|
18937
18825
|
container.textContent = "";
|
|
@@ -18974,6 +18862,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
18974
18862
|
if (isError && attempt.error) {
|
|
18975
18863
|
const errText = String(attempt.error);
|
|
18976
18864
|
detailParts.push(redact ? redactIpOctets(errText) : errText);
|
|
18865
|
+
if (redact && /enable diagnostics for details/i.test(errText)) detailParts.push("Turn off Redact in Advanced diagnostics to reveal the full error.");
|
|
18977
18866
|
}
|
|
18978
18867
|
if (!isError && (attempt.ops_in || attempt.ops_out)) detailParts.push(`${attempt.ops_in ?? 0} in · ${attempt.ops_out ?? 0} out`);
|
|
18979
18868
|
if (!redact && attempt.address) detailParts.push(attempt.address);
|
|
@@ -19528,46 +19417,6 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19528
19417
|
});
|
|
19529
19418
|
}
|
|
19530
19419
|
//#endregion
|
|
19531
|
-
//#region src/tabs/sync/peer-scope-collapsible.tsx
|
|
19532
|
-
function PeerScopeCollapsible({ contentHost, initialOpen, onOpenChange, children }) {
|
|
19533
|
-
const [open, setOpen] = d$2(initialOpen);
|
|
19534
|
-
const contentRef = A$1(null);
|
|
19535
|
-
y$2(() => {
|
|
19536
|
-
setOpen(initialOpen);
|
|
19537
|
-
}, [initialOpen]);
|
|
19538
|
-
_$2(() => {
|
|
19539
|
-
onOpenChange(open);
|
|
19540
|
-
}, [onOpenChange, open]);
|
|
19541
|
-
y$2(() => {
|
|
19542
|
-
if (!open) return;
|
|
19543
|
-
queueMicrotask(() => {
|
|
19544
|
-
(contentRef.current?.querySelector("button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex=\"-1\"])"))?.focus();
|
|
19545
|
-
});
|
|
19546
|
-
}, [open]);
|
|
19547
|
-
return /* @__PURE__ */ u(Root$3, {
|
|
19548
|
-
open,
|
|
19549
|
-
onOpenChange: setOpen,
|
|
19550
|
-
children: [/* @__PURE__ */ u(Trigger$4, {
|
|
19551
|
-
asChild: true,
|
|
19552
|
-
children: /* @__PURE__ */ u("button", {
|
|
19553
|
-
type: "button",
|
|
19554
|
-
className: "settings-button",
|
|
19555
|
-
children: open ? "Hide sharing scope" : "Show sharing scope"
|
|
19556
|
-
})
|
|
19557
|
-
}), contentHost ? $$1(/* @__PURE__ */ u(Content$2, {
|
|
19558
|
-
forceMount: true,
|
|
19559
|
-
ref: contentRef,
|
|
19560
|
-
className: `peer-scope-editor-wrap${open ? "" : " collapsed"}`,
|
|
19561
|
-
hidden: !open,
|
|
19562
|
-
inert: !open,
|
|
19563
|
-
children: /* @__PURE__ */ u(ScopeEditorContent, { children })
|
|
19564
|
-
}), contentHost) : null]
|
|
19565
|
-
});
|
|
19566
|
-
}
|
|
19567
|
-
function ScopeEditorContent({ children }) {
|
|
19568
|
-
return /* @__PURE__ */ u("div", { children });
|
|
19569
|
-
}
|
|
19570
|
-
//#endregion
|
|
19571
19420
|
//#region src/tabs/sync/components/sync-inline-feedback.tsx
|
|
19572
19421
|
function SyncInlineFeedback({ feedback }) {
|
|
19573
19422
|
if (!feedback?.message) return null;
|
|
@@ -19636,42 +19485,27 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19636
19485
|
},
|
|
19637
19486
|
none: null
|
|
19638
19487
|
};
|
|
19639
|
-
function listText(value) {
|
|
19640
|
-
return Array.isArray(value) ? value.map((item) => String(item || "").trim()).filter(Boolean) : [];
|
|
19641
|
-
}
|
|
19642
19488
|
function claimedLocalActorScopeMessage(scope) {
|
|
19643
|
-
|
|
19644
|
-
if (
|
|
19645
|
-
|
|
19646
|
-
return `Private same-person sync is blocked until this device is granted ${scopeId || "its personal Sharing domain"}.`;
|
|
19489
|
+
if (!scope) return "Private same-person sync is limited to an allowed personal Space; team or org Spaces do not carry your private memories.";
|
|
19490
|
+
if (scope.authorized) return "Private same-person sync is limited to your personal Space. Team and org Spaces do not carry your private memories.";
|
|
19491
|
+
return "Private same-person sync is blocked until this device is granted an allowed personal Space.";
|
|
19647
19492
|
}
|
|
19648
|
-
function
|
|
19649
|
-
|
|
19650
|
-
_$2(() => {
|
|
19651
|
-
const host = hostRef.current;
|
|
19652
|
-
if (!host) return;
|
|
19653
|
-
if (element.parentElement !== host) host.appendChild(element);
|
|
19654
|
-
return () => {
|
|
19655
|
-
if (element.parentElement === host) host.removeChild(element);
|
|
19656
|
-
};
|
|
19657
|
-
}, [element]);
|
|
19658
|
-
return /* @__PURE__ */ u("div", { ref: hostRef });
|
|
19493
|
+
function openTeamsAccessManagement() {
|
|
19494
|
+
window.location.hash = "coordinator-admin";
|
|
19659
19495
|
}
|
|
19660
|
-
function SyncPeerCard({ peer, onAssignActor, onRemove, onRename,
|
|
19496
|
+
function SyncPeerCard({ peer, onAssignActor, onRemove, onRename, onSync }) {
|
|
19661
19497
|
const peerId = String(peer.peer_device_id || "");
|
|
19662
19498
|
const displayName = peer.name || (peerId ? peerId.slice(0, 8) : "unknown");
|
|
19663
19499
|
const destructiveLabel = peer.name || peerId || displayName;
|
|
19664
|
-
const pendingScopeReview = isPeerScopeReviewPending(peerId);
|
|
19665
19500
|
const trustSummary = derivePeerTrustSummary(peer);
|
|
19666
19501
|
const directionHint = DIRECTION_GLYPH[derivePeerDirection(peer)];
|
|
19667
19502
|
const peerStatus = peer.status || {};
|
|
19668
19503
|
const authorizedDomains = derivePeerAuthorizedDomainsView(peer);
|
|
19504
|
+
const rawPendingScopeReview = isPeerScopeReviewPending(peerId);
|
|
19505
|
+
const pendingScopeReview = rawPendingScopeReview && authorizedDomains.total === 0;
|
|
19669
19506
|
const grantRoleMismatch = derivePeerGrantRoleMismatchView(peer);
|
|
19670
19507
|
const scopeRejections = derivePeerScopeRejectionsView(peer);
|
|
19671
|
-
const
|
|
19672
|
-
const projectNarrowing = derivePeerProjectNarrowingView(scope);
|
|
19673
|
-
const includeList = listText(scope.include);
|
|
19674
|
-
const excludeList = listText(scope.exclude);
|
|
19508
|
+
const projectNarrowing = derivePeerProjectNarrowingView(peer.project_scope || {});
|
|
19675
19509
|
const primaryAddress = pickPrimaryAddress(peer.addresses);
|
|
19676
19510
|
const peerAddresses = Array.isArray(peer.addresses) ? Array.from(new Set(peer.addresses.filter(Boolean).map((value) => String(value)))) : [];
|
|
19677
19511
|
const rawHiddenAddressCount = Number(peer.address_count ?? 0);
|
|
@@ -19680,11 +19514,9 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19680
19514
|
const assignmentSummary = peer.actor_display_name ? `This device belongs to ${peer.claimed_local_actor ? "you" : String(peer.actor_display_name)}.` : "This device is not assigned to anyone yet.";
|
|
19681
19515
|
const lastSyncAt = String(peerStatus.last_sync_at || peerStatus.last_sync_at_utc || "");
|
|
19682
19516
|
const lastPingAt = String(peerStatus.last_ping_at || peerStatus.last_ping_at_utc || "");
|
|
19683
|
-
const discoverySummary = peer.discovered_via_group_id ? `Discovery: seen through
|
|
19684
|
-
const scopeEditorOpen = openPeerScopeEditors.has(peerId);
|
|
19517
|
+
const discoverySummary = peer.discovered_via_group_id ? `Discovery: seen through Team ${peer.discovered_via_group_id}. Discovery helps find devices; Space access above decides data access.` : peer.discovered_via_coordinator_id ? `Discovery: seen through coordinator ${peer.discovered_via_coordinator_id}. Discovery helps find devices; Space access above decides data access.` : null;
|
|
19685
19518
|
const scopeReviewRequested = consumePeerScopeReviewRequest(peerId);
|
|
19686
19519
|
const cardRef = A$1(null);
|
|
19687
|
-
const [scopeHost, setScopeHost] = d$2(null);
|
|
19688
19520
|
const [renameValue, setRenameValue] = d$2(displayName);
|
|
19689
19521
|
const [feedback, setFeedback] = d$2(() => state.syncPeerFeedbackById.get(peerId) ?? null);
|
|
19690
19522
|
const [renameBusy, setRenameBusy] = d$2(false);
|
|
@@ -19695,10 +19527,6 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19695
19527
|
const [selectedActorId, setSelectedActorId] = d$2(String(peer.actor_id || ""));
|
|
19696
19528
|
const [applyActorBusy, setApplyActorBusy] = d$2(false);
|
|
19697
19529
|
const [applyActorLabel, setApplyActorLabel] = d$2("Save assignment");
|
|
19698
|
-
const [saveScopeBusy, setSaveScopeBusy] = d$2(false);
|
|
19699
|
-
const [saveScopeLabel, setSaveScopeLabel] = d$2("Save scope");
|
|
19700
|
-
const [resetScopeBusy, setResetScopeBusy] = d$2(false);
|
|
19701
|
-
const [resetScopeLabel, setResetScopeLabel] = d$2("Reset to global scope");
|
|
19702
19530
|
const actorSelectOptions = T$1(() => {
|
|
19703
19531
|
const options = buildActorSelectOptions(selectedActorId);
|
|
19704
19532
|
const hasSelected = options.some((option) => option.value === selectedActorId);
|
|
@@ -19715,15 +19543,12 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19715
19543
|
state.lastSyncPeers,
|
|
19716
19544
|
state.lastSyncViewModel
|
|
19717
19545
|
]);
|
|
19718
|
-
|
|
19719
|
-
peerId
|
|
19720
|
-
|
|
19721
|
-
|
|
19722
|
-
]);
|
|
19723
|
-
const excludeEditor = T$1(() => createChipEditor(excludeList, "Add project", "No exclusions", state.knownProjects), [
|
|
19546
|
+
y$2(() => {
|
|
19547
|
+
if (rawPendingScopeReview && authorizedDomains.total > 0) clearPeerScopeReview(peerId);
|
|
19548
|
+
}, [
|
|
19549
|
+
authorizedDomains.total,
|
|
19724
19550
|
peerId,
|
|
19725
|
-
|
|
19726
|
-
state.knownProjects.join("|")
|
|
19551
|
+
rawPendingScopeReview
|
|
19727
19552
|
]);
|
|
19728
19553
|
y$2(() => {
|
|
19729
19554
|
setRenameValue(displayName);
|
|
@@ -19736,16 +19561,10 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19736
19561
|
setSelectedActorId(String(peer.actor_id || ""));
|
|
19737
19562
|
setApplyActorBusy(false);
|
|
19738
19563
|
setApplyActorLabel("Save assignment");
|
|
19739
|
-
setSaveScopeBusy(false);
|
|
19740
|
-
setSaveScopeLabel("Save scope");
|
|
19741
|
-
setResetScopeBusy(false);
|
|
19742
|
-
setResetScopeLabel("Reset to global scope");
|
|
19743
19564
|
}, [
|
|
19744
19565
|
displayName,
|
|
19745
19566
|
peer.actor_id,
|
|
19746
|
-
peerId
|
|
19747
|
-
includeList.join("|"),
|
|
19748
|
-
excludeList.join("|")
|
|
19567
|
+
peerId
|
|
19749
19568
|
]);
|
|
19750
19569
|
y$2(() => {
|
|
19751
19570
|
if (!scopeReviewRequested || !cardRef.current) return;
|
|
@@ -19783,10 +19602,10 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19783
19602
|
async function sync() {
|
|
19784
19603
|
if (pendingScopeReview) {
|
|
19785
19604
|
if (!await openSyncConfirmDialog({
|
|
19786
|
-
title: `Sync ${displayName} before
|
|
19787
|
-
description: "This manual sync will use the current
|
|
19605
|
+
title: `Sync ${displayName} before advanced rule review?`,
|
|
19606
|
+
description: "This manual sync will use the current Space access and advanced filters until you review them in Teams.",
|
|
19788
19607
|
confirmLabel: "Sync anyway",
|
|
19789
|
-
cancelLabel: "Review
|
|
19608
|
+
cancelLabel: "Review in Teams first"
|
|
19790
19609
|
})) return;
|
|
19791
19610
|
}
|
|
19792
19611
|
setSyncBusy(true);
|
|
@@ -19835,36 +19654,6 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19835
19654
|
setApplyActorBusy(false);
|
|
19836
19655
|
}
|
|
19837
19656
|
}
|
|
19838
|
-
async function saveScope() {
|
|
19839
|
-
if (!peerId) return;
|
|
19840
|
-
setSaveScopeBusy(true);
|
|
19841
|
-
setSaveScopeLabel("Saving…");
|
|
19842
|
-
try {
|
|
19843
|
-
const nextFeedback = await onSaveScope(peerId, includeEditor.values(), excludeEditor.values());
|
|
19844
|
-
setFeedback(nextFeedback);
|
|
19845
|
-
state.syncPeerFeedbackById.set(peerId, nextFeedback);
|
|
19846
|
-
setSaveScopeLabel("Save scope");
|
|
19847
|
-
} catch {
|
|
19848
|
-
setSaveScopeLabel("Retry");
|
|
19849
|
-
} finally {
|
|
19850
|
-
setSaveScopeBusy(false);
|
|
19851
|
-
}
|
|
19852
|
-
}
|
|
19853
|
-
async function resetScope() {
|
|
19854
|
-
if (!peerId) return;
|
|
19855
|
-
setResetScopeBusy(true);
|
|
19856
|
-
setResetScopeLabel("Resetting…");
|
|
19857
|
-
try {
|
|
19858
|
-
const nextFeedback = await onResetScope(peerId);
|
|
19859
|
-
setFeedback(nextFeedback);
|
|
19860
|
-
state.syncPeerFeedbackById.set(peerId, nextFeedback);
|
|
19861
|
-
setResetScopeLabel("Reset to global scope");
|
|
19862
|
-
} catch {
|
|
19863
|
-
setResetScopeLabel("Retry");
|
|
19864
|
-
} finally {
|
|
19865
|
-
setResetScopeBusy(false);
|
|
19866
|
-
}
|
|
19867
|
-
}
|
|
19868
19657
|
const isExpanded = useExpandedPeer() === peerId && peerId !== "";
|
|
19869
19658
|
const drawerId = `device-drawer-${peerId || "unknown"}`;
|
|
19870
19659
|
const presenceState = presenceForPeer(peer);
|
|
@@ -19911,11 +19700,11 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19911
19700
|
}),
|
|
19912
19701
|
pendingScopeReview ? /* @__PURE__ */ u("span", {
|
|
19913
19702
|
className: "badge actor-badge",
|
|
19914
|
-
children: "
|
|
19703
|
+
children: "Review advanced rules"
|
|
19915
19704
|
}) : null,
|
|
19916
19705
|
/* @__PURE__ */ u("span", {
|
|
19917
19706
|
className: `badge ${authorizedDomains.isWarning ? "badge-offline" : "actor-badge"}`,
|
|
19918
|
-
title: "
|
|
19707
|
+
title: "Spaces are the hard access boundary; advanced filters only narrow inside them.",
|
|
19919
19708
|
children: authorizedDomains.badgeLabel
|
|
19920
19709
|
}),
|
|
19921
19710
|
scopeRejections.badgeLabel ? /* @__PURE__ */ u("span", {
|
|
@@ -19925,7 +19714,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19925
19714
|
}) : null,
|
|
19926
19715
|
grantRoleMismatch.badgeLabel ? /* @__PURE__ */ u("span", {
|
|
19927
19716
|
className: "badge badge-offline",
|
|
19928
|
-
title: "Review whether explicit
|
|
19717
|
+
title: "Review whether explicit Space access matches this device's intended role.",
|
|
19929
19718
|
children: grantRoleMismatch.badgeLabel
|
|
19930
19719
|
}) : null,
|
|
19931
19720
|
peer.discovered_via_group_id ? /* @__PURE__ */ u("span", {
|
|
@@ -19999,10 +19788,10 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19999
19788
|
children: [
|
|
20000
19789
|
scopeReviewRequested ? /* @__PURE__ */ u("div", {
|
|
20001
19790
|
className: "peer-meta",
|
|
20002
|
-
children: "Review this device's
|
|
19791
|
+
children: "Review this device's Space access and advanced rules in Teams if the defaults are too broad."
|
|
20003
19792
|
}) : pendingScopeReview ? /* @__PURE__ */ u("div", {
|
|
20004
19793
|
className: "peer-meta",
|
|
20005
|
-
children: "
|
|
19794
|
+
children: "Advanced rule review is still pending for this device."
|
|
20006
19795
|
}) : null,
|
|
20007
19796
|
/* @__PURE__ */ u("div", {
|
|
20008
19797
|
className: "peer-scope-summary",
|
|
@@ -20022,15 +19811,15 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
20022
19811
|
}),
|
|
20023
19812
|
/* @__PURE__ */ u("div", {
|
|
20024
19813
|
className: "peer-scope-summary",
|
|
20025
|
-
children: "
|
|
19814
|
+
children: "Space access"
|
|
20026
19815
|
}),
|
|
20027
19816
|
/* @__PURE__ */ u("div", {
|
|
20028
19817
|
className: "peer-meta",
|
|
20029
|
-
children: authorizedDomains.total > 0 ? "These
|
|
19818
|
+
children: authorizedDomains.total > 0 ? "These Spaces are the hard access boundary for this device." : authorizedDomains.emptyMessage
|
|
20030
19819
|
}),
|
|
20031
19820
|
authorizedDomains.domains.length > 0 ? /* @__PURE__ */ u("ul", {
|
|
20032
19821
|
className: "peer-scope-chips",
|
|
20033
|
-
"aria-label": "Authorized
|
|
19822
|
+
"aria-label": "Authorized Spaces",
|
|
20034
19823
|
children: authorizedDomains.domains.map((domain) => /* @__PURE__ */ u("li", {
|
|
20035
19824
|
className: "peer-scope-chip",
|
|
20036
19825
|
title: domain.detail,
|
|
@@ -20116,41 +19905,28 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
20116
19905
|
}),
|
|
20117
19906
|
/* @__PURE__ */ u("div", {
|
|
20118
19907
|
className: "peer-scope-summary",
|
|
20119
|
-
children: "
|
|
19908
|
+
children: "Advanced sharing rules"
|
|
20120
19909
|
}),
|
|
20121
19910
|
/* @__PURE__ */ u("div", {
|
|
20122
19911
|
className: "peer-meta",
|
|
20123
|
-
children: [
|
|
19912
|
+
children: [
|
|
19913
|
+
projectNarrowing.statusLabel,
|
|
19914
|
+
". ",
|
|
19915
|
+
projectNarrowing.summary,
|
|
19916
|
+
" ",
|
|
19917
|
+
projectNarrowing.note
|
|
19918
|
+
]
|
|
20124
19919
|
}),
|
|
20125
|
-
/* @__PURE__ */ u(
|
|
20126
|
-
|
|
20127
|
-
|
|
20128
|
-
|
|
20129
|
-
|
|
20130
|
-
|
|
20131
|
-
|
|
20132
|
-
|
|
20133
|
-
className: "peer-scope-row",
|
|
20134
|
-
children: [/* @__PURE__ */ u(ExistingElementSlot$1, { element: includeEditor.element }), /* @__PURE__ */ u(ExistingElementSlot$1, { element: excludeEditor.element })]
|
|
20135
|
-
}), /* @__PURE__ */ u("div", {
|
|
20136
|
-
className: "peer-scope-actions",
|
|
20137
|
-
children: [/* @__PURE__ */ u("button", {
|
|
20138
|
-
type: "button",
|
|
20139
|
-
className: "settings-button",
|
|
20140
|
-
disabled: saveScopeBusy,
|
|
20141
|
-
onClick: () => void saveScope(),
|
|
20142
|
-
children: saveScopeLabel
|
|
20143
|
-
}), /* @__PURE__ */ u("button", {
|
|
20144
|
-
type: "button",
|
|
20145
|
-
className: "settings-button",
|
|
20146
|
-
disabled: resetScopeBusy,
|
|
20147
|
-
onClick: () => void resetScope(),
|
|
20148
|
-
children: resetScopeLabel
|
|
20149
|
-
})]
|
|
20150
|
-
})] })
|
|
19920
|
+
/* @__PURE__ */ u("div", {
|
|
19921
|
+
className: "peer-actions",
|
|
19922
|
+
children: /* @__PURE__ */ u("button", {
|
|
19923
|
+
type: "button",
|
|
19924
|
+
className: "settings-button",
|
|
19925
|
+
onClick: openTeamsAccessManagement,
|
|
19926
|
+
children: "Manage Spaces in Teams"
|
|
19927
|
+
})
|
|
20151
19928
|
}),
|
|
20152
|
-
/* @__PURE__ */ u(SyncInlineFeedback, { feedback })
|
|
20153
|
-
/* @__PURE__ */ u("div", { ref: setScopeHost })
|
|
19929
|
+
/* @__PURE__ */ u(SyncInlineFeedback, { feedback })
|
|
20154
19930
|
]
|
|
20155
19931
|
})]
|
|
20156
19932
|
})]
|
|
@@ -20249,8 +20025,10 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
20249
20025
|
if (!syncPeers) return;
|
|
20250
20026
|
hideSkeleton("syncPeersSkeleton");
|
|
20251
20027
|
const peers = state.lastSyncPeers;
|
|
20028
|
+
const peersArray = Array.isArray(peers) ? peers : [];
|
|
20029
|
+
if (shouldClearStalePeersFeedback(state.syncPeersSectionFeedback, peersArray)) state.syncPeersSectionFeedback = null;
|
|
20252
20030
|
renderSyncPeersList(syncPeers, {
|
|
20253
|
-
peers:
|
|
20031
|
+
peers: peersArray,
|
|
20254
20032
|
onRename: async (peerId, nextName) => {
|
|
20255
20033
|
try {
|
|
20256
20034
|
await renamePeer(peerId, nextName);
|
|
@@ -20279,7 +20057,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
20279
20057
|
tone: "warning"
|
|
20280
20058
|
};
|
|
20281
20059
|
else if (peerId && isPeerScopeReviewPending(peerId)) feedback = {
|
|
20282
|
-
message: `Triggered sync for ${peer?.name || (peerId ? peerId.slice(0, 8) : "unknown")}. Review
|
|
20060
|
+
message: `Triggered sync for ${peer?.name || (peerId ? peerId.slice(0, 8) : "unknown")}. Review Space access and advanced rules in Teams if this device needs tighter sharing.`,
|
|
20283
20061
|
tone: "warning"
|
|
20284
20062
|
};
|
|
20285
20063
|
else feedback = {
|
|
@@ -20310,7 +20088,10 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
20310
20088
|
tone: "success"
|
|
20311
20089
|
};
|
|
20312
20090
|
state.syncPeerFeedbackById.delete(peerId);
|
|
20313
|
-
state.syncPeersSectionFeedback =
|
|
20091
|
+
state.syncPeersSectionFeedback = {
|
|
20092
|
+
...feedback,
|
|
20093
|
+
relatedPeerDeviceId: peerId
|
|
20094
|
+
};
|
|
20314
20095
|
await _loadSyncData();
|
|
20315
20096
|
return feedback;
|
|
20316
20097
|
} catch (error) {
|
|
@@ -20334,38 +20115,6 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
20334
20115
|
tone: "warning"
|
|
20335
20116
|
};
|
|
20336
20117
|
}
|
|
20337
|
-
},
|
|
20338
|
-
onSaveScope: async (peerId, include, exclude) => {
|
|
20339
|
-
try {
|
|
20340
|
-
await updatePeerScope(peerId, include, exclude);
|
|
20341
|
-
clearPeerScopeReview(peerId);
|
|
20342
|
-
await _loadSyncData();
|
|
20343
|
-
return {
|
|
20344
|
-
message: "Device sync scope saved.",
|
|
20345
|
-
tone: "success"
|
|
20346
|
-
};
|
|
20347
|
-
} catch (error) {
|
|
20348
|
-
return {
|
|
20349
|
-
message: friendlyError(error, "Failed to save device scope. The current sharing rules are still active."),
|
|
20350
|
-
tone: "warning"
|
|
20351
|
-
};
|
|
20352
|
-
}
|
|
20353
|
-
},
|
|
20354
|
-
onResetScope: async (peerId) => {
|
|
20355
|
-
try {
|
|
20356
|
-
await updatePeerScope(peerId, null, null, true);
|
|
20357
|
-
clearPeerScopeReview(peerId);
|
|
20358
|
-
await _loadSyncData();
|
|
20359
|
-
return {
|
|
20360
|
-
message: "Device sync scope reset to global defaults.",
|
|
20361
|
-
tone: "success"
|
|
20362
|
-
};
|
|
20363
|
-
} catch (error) {
|
|
20364
|
-
return {
|
|
20365
|
-
message: friendlyError(error, "Failed to reset device scope. The current sharing rules are still active."),
|
|
20366
|
-
tone: "warning"
|
|
20367
|
-
};
|
|
20368
|
-
}
|
|
20369
20118
|
}
|
|
20370
20119
|
});
|
|
20371
20120
|
}
|
|
@@ -20988,10 +20737,18 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
20988
20737
|
onClick: async () => {
|
|
20989
20738
|
setBusy("review");
|
|
20990
20739
|
setReviewLabel("Pairing…");
|
|
20740
|
+
setFeedback({
|
|
20741
|
+
message: `Pairing ${row.displayName}. Keep this page open while the device is approved and refreshed.`,
|
|
20742
|
+
tone: "success"
|
|
20743
|
+
});
|
|
20991
20744
|
try {
|
|
20992
20745
|
setFeedback(await onReview(row) || null);
|
|
20993
20746
|
setReviewLabel(row.actionLabel || defaultReviewLabel);
|
|
20994
20747
|
} catch {
|
|
20748
|
+
setFeedback({
|
|
20749
|
+
message: `Pairing ${row.displayName} failed. Try again.`,
|
|
20750
|
+
tone: "warning"
|
|
20751
|
+
});
|
|
20995
20752
|
setReviewLabel("Retry");
|
|
20996
20753
|
} finally {
|
|
20997
20754
|
setBusy(null);
|
|
@@ -21366,7 +21123,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21366
21123
|
actionMessage = "This device appears in multiple coordinator groups. Review team setup first or ask an admin to clean up the duplicate enrollment before approving it here.";
|
|
21367
21124
|
mode = "ambiguous";
|
|
21368
21125
|
} else if (pairedPeer && isPeerScopeReviewPending(deviceId)) {
|
|
21369
|
-
actionMessage =
|
|
21126
|
+
actionMessage = "Review this device's Space access and advanced rules in Teams before you sync it.";
|
|
21370
21127
|
mode = "scope-pending";
|
|
21371
21128
|
} else if (pairedPeer?.last_error) {
|
|
21372
21129
|
noteParts.push(`error: ${String(pairedPeer.last_error)}`);
|
|
@@ -21554,14 +21311,41 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21554
21311
|
const label = group.displayProject.toLowerCase();
|
|
21555
21312
|
return label.includes("fatal:") || label.includes("not a git repository") || label === "unknown project" || group.identitySource === "unmapped";
|
|
21556
21313
|
}
|
|
21314
|
+
function displayProjectTitle(group) {
|
|
21315
|
+
return needsProjectCleanup(group) ? "Unclear project identity" : group.displayProject;
|
|
21316
|
+
}
|
|
21557
21317
|
function canReassignLegacyGroup(group) {
|
|
21558
21318
|
return (group.reassignableMemoryCount ?? group.memoryCount) > 0;
|
|
21559
21319
|
}
|
|
21560
|
-
function
|
|
21320
|
+
function suggestedScopeText(group, targetScopes) {
|
|
21321
|
+
if (!group.suggestedScopeId) return "";
|
|
21322
|
+
return ` · suggested ${targetScopes.find((scope) => scope.scopeId === group.suggestedScopeId)?.label || "Space"}`;
|
|
21323
|
+
}
|
|
21324
|
+
function escapeRegExp(value) {
|
|
21325
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
21326
|
+
}
|
|
21327
|
+
function targetScopeLabel(scopeId, targetScopes) {
|
|
21328
|
+
return targetScopes.find((scope) => scope.scopeId === scopeId)?.label || "selected Space";
|
|
21329
|
+
}
|
|
21330
|
+
function authorityLabel(authorityType) {
|
|
21331
|
+
switch (authorityType) {
|
|
21332
|
+
case "coordinator": return "Team Space";
|
|
21333
|
+
case "local": return "Local Space";
|
|
21334
|
+
default: return "Other Space";
|
|
21335
|
+
}
|
|
21336
|
+
}
|
|
21337
|
+
function formatLegacyReviewError(error, scopeId, targetScopes) {
|
|
21338
|
+
let result = (error instanceof Error ? error.message : "Unable to reassign legacy review memories.").replace(/sharing domain/gi, "Space");
|
|
21339
|
+
if (scopeId) result = result.replace(new RegExp(`\\b${escapeRegExp(scopeId)}\\b`, "g"), targetScopeLabel(scopeId, targetScopes));
|
|
21340
|
+
return result;
|
|
21341
|
+
}
|
|
21342
|
+
function groupSearchText(group, targetScopes) {
|
|
21343
|
+
const suggestedScopeLabel = group.suggestedScopeId ? targetScopes.find((scope) => scope.scopeId === group.suggestedScopeId)?.label : "";
|
|
21561
21344
|
return [
|
|
21562
21345
|
group.displayProject,
|
|
21563
21346
|
group.identitySource,
|
|
21564
21347
|
group.suggestedScopeId ?? "",
|
|
21348
|
+
suggestedScopeLabel ?? "",
|
|
21565
21349
|
group.suggestionReason ?? "",
|
|
21566
21350
|
group.workspaceIdentity
|
|
21567
21351
|
].join(" ").toLowerCase();
|
|
@@ -21622,7 +21406,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21622
21406
|
if (filter === "cleanup" && !cleanup) return false;
|
|
21623
21407
|
if (filter === "no-suggestion" && (group.suggestedScopeId || cleanup)) return false;
|
|
21624
21408
|
if (filter === "selected" && !selectedGroups[group.workspaceIdentity]) return false;
|
|
21625
|
-
return !query.trim() || groupSearchText(group).includes(query.trim().toLowerCase());
|
|
21409
|
+
return !query.trim() || groupSearchText(group, targetScopes).includes(query.trim().toLowerCase());
|
|
21626
21410
|
});
|
|
21627
21411
|
async function applyGroup(group) {
|
|
21628
21412
|
const selectedScopeId = selectedScopes[group.workspaceIdentity] || group.suggestedScopeId || "";
|
|
@@ -21647,7 +21431,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21647
21431
|
} catch (error) {
|
|
21648
21432
|
setErrors((current) => ({
|
|
21649
21433
|
...current,
|
|
21650
|
-
[group.workspaceIdentity]: error
|
|
21434
|
+
[group.workspaceIdentity]: formatLegacyReviewError(error, selectedScopeId, targetScopes)
|
|
21651
21435
|
}));
|
|
21652
21436
|
} finally {
|
|
21653
21437
|
setBusyIdentity(null);
|
|
@@ -21711,7 +21495,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21711
21495
|
} catch (error) {
|
|
21712
21496
|
setErrors((current) => ({
|
|
21713
21497
|
...current,
|
|
21714
|
-
[group.workspaceIdentity]: error
|
|
21498
|
+
[group.workspaceIdentity]: formatLegacyReviewError(error, selectedScopeId, targetScopes)
|
|
21715
21499
|
}));
|
|
21716
21500
|
}
|
|
21717
21501
|
}
|
|
@@ -21739,7 +21523,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21739
21523
|
" older",
|
|
21740
21524
|
" ",
|
|
21741
21525
|
groupCount === 1 ? "project needs" : "projects need",
|
|
21742
|
-
" a
|
|
21526
|
+
" a Space. They contain",
|
|
21743
21527
|
" ",
|
|
21744
21528
|
item.memoryCount.toLocaleString(),
|
|
21745
21529
|
" older shared memories total; review the projects, not individual memories.",
|
|
@@ -21812,7 +21596,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21812
21596
|
children: busyIdentity === "bulk" ? "Previewing…" : `Preview ${selectedCount.toLocaleString()} selected`
|
|
21813
21597
|
}) : onReassign && selectedReassignableCount > 0 ? /* @__PURE__ */ u("span", {
|
|
21814
21598
|
className: "legacy-review-cleanup-note",
|
|
21815
|
-
children: "Add or join a
|
|
21599
|
+
children: "Add or join a Space before bulk reassignment."
|
|
21816
21600
|
}) : null,
|
|
21817
21601
|
selectedCount > 0 && groups.filter((group) => selectedGroups[group.workspaceIdentity] && canReassignLegacyGroup(group) && Boolean(selectedScopes[group.workspaceIdentity])).every((group) => pending[group.workspaceIdentity]) ? /* @__PURE__ */ u("span", {
|
|
21818
21602
|
className: "legacy-review-cleanup-note",
|
|
@@ -21832,7 +21616,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21832
21616
|
children: [/* @__PURE__ */ u("div", {
|
|
21833
21617
|
className: "legacy-review-title-wrap",
|
|
21834
21618
|
children: [/* @__PURE__ */ u("input", {
|
|
21835
|
-
"aria-label": `Select ${group
|
|
21619
|
+
"aria-label": `Select ${displayProjectTitle(group)}`,
|
|
21836
21620
|
checked: Boolean(selectedGroups[group.workspaceIdentity]),
|
|
21837
21621
|
className: "cm-checkbox",
|
|
21838
21622
|
disabled: !canReassignLegacyGroup(group),
|
|
@@ -21841,15 +21625,15 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21841
21625
|
}), /* @__PURE__ */ u("div", { children: [
|
|
21842
21626
|
/* @__PURE__ */ u("div", {
|
|
21843
21627
|
className: "legacy-review-group-title",
|
|
21844
|
-
children: group
|
|
21628
|
+
children: displayProjectTitle(group)
|
|
21845
21629
|
}),
|
|
21846
21630
|
/* @__PURE__ */ u("div", {
|
|
21847
21631
|
className: "legacy-review-group-meta",
|
|
21848
|
-
children: [formatIdentitySource(group.identitySource), group
|
|
21632
|
+
children: [formatIdentitySource(group.identitySource), suggestedScopeText(group, targetScopes)]
|
|
21849
21633
|
}),
|
|
21850
21634
|
!canReassignLegacyGroup(group) ? /* @__PURE__ */ u("div", {
|
|
21851
21635
|
className: "legacy-review-cleanup-note",
|
|
21852
|
-
children: "Peer-owned only. These older memories were received from another device, so this device cannot reassign them to a
|
|
21636
|
+
children: "Peer-owned only. These older memories were received from another device, so this device cannot reassign them to a Space."
|
|
21853
21637
|
}) : group.peerOwnedMemoryCount ? /* @__PURE__ */ u("div", {
|
|
21854
21638
|
className: "legacy-review-cleanup-note",
|
|
21855
21639
|
children: [
|
|
@@ -21867,7 +21651,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21867
21651
|
}) : null,
|
|
21868
21652
|
needsProjectCleanup(group) ? /* @__PURE__ */ u("div", {
|
|
21869
21653
|
className: "legacy-review-cleanup-note",
|
|
21870
|
-
children: "
|
|
21654
|
+
children: "Inspect or correct the project identity before assigning old shared data to a Space."
|
|
21871
21655
|
}) : null
|
|
21872
21656
|
] })]
|
|
21873
21657
|
}), /* @__PURE__ */ u("span", {
|
|
@@ -21906,20 +21690,20 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21906
21690
|
}) : null,
|
|
21907
21691
|
targetScopes.length > 0 && onReassign && canReassignLegacyGroup(group) ? /* @__PURE__ */ u("label", {
|
|
21908
21692
|
className: "legacy-review-target",
|
|
21909
|
-
children: [/* @__PURE__ */ u("span", { children: "Destination
|
|
21693
|
+
children: [/* @__PURE__ */ u("span", { children: "Destination Space" }), /* @__PURE__ */ u("select", {
|
|
21910
21694
|
className: "peer-scope-input",
|
|
21911
21695
|
disabled: busyIdentity != null,
|
|
21912
21696
|
onChange: (event) => updateSelectedScope(group, event.currentTarget.value),
|
|
21913
21697
|
value: selectedScopes[group.workspaceIdentity] || "",
|
|
21914
21698
|
children: [/* @__PURE__ */ u("option", {
|
|
21915
21699
|
value: "",
|
|
21916
|
-
children: "Choose
|
|
21700
|
+
children: "Choose Space…"
|
|
21917
21701
|
}), targetScopes.map((scope) => /* @__PURE__ */ u("option", {
|
|
21918
21702
|
value: scope.scopeId,
|
|
21919
21703
|
children: [
|
|
21920
21704
|
scope.label,
|
|
21921
21705
|
" · ",
|
|
21922
|
-
scope.authorityType,
|
|
21706
|
+
authorityLabel(scope.authorityType),
|
|
21923
21707
|
scope.scopeId === group.suggestedScopeId ? " · suggested" : ""
|
|
21924
21708
|
]
|
|
21925
21709
|
}, scope.scopeId))]
|
|
@@ -22222,7 +22006,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
22222
22006
|
try {
|
|
22223
22007
|
const runtime = await loadRuntimeInfo();
|
|
22224
22008
|
if (!runtime?.version) return;
|
|
22225
|
-
setRuntimeLabel(runtime.version, "
|
|
22009
|
+
setRuntimeLabel(runtime.version, "c8fe0f7");
|
|
22226
22010
|
} catch {}
|
|
22227
22011
|
}
|
|
22228
22012
|
var lastAnnouncedRefreshState = null;
|