@codemem/server 0.32.3 → 0.33.0-alpha.1
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 +238 -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 = "";
|
|
@@ -19528,46 +19416,6 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19528
19416
|
});
|
|
19529
19417
|
}
|
|
19530
19418
|
//#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
19419
|
//#region src/tabs/sync/components/sync-inline-feedback.tsx
|
|
19572
19420
|
function SyncInlineFeedback({ feedback }) {
|
|
19573
19421
|
if (!feedback?.message) return null;
|
|
@@ -19636,42 +19484,27 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19636
19484
|
},
|
|
19637
19485
|
none: null
|
|
19638
19486
|
};
|
|
19639
|
-
function listText(value) {
|
|
19640
|
-
return Array.isArray(value) ? value.map((item) => String(item || "").trim()).filter(Boolean) : [];
|
|
19641
|
-
}
|
|
19642
19487
|
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"}.`;
|
|
19488
|
+
if (!scope) return "Private same-person sync is limited to an allowed personal Space; team or org Spaces do not carry your private memories.";
|
|
19489
|
+
if (scope.authorized) return "Private same-person sync is limited to your personal Space. Team and org Spaces do not carry your private memories.";
|
|
19490
|
+
return "Private same-person sync is blocked until this device is granted an allowed personal Space.";
|
|
19647
19491
|
}
|
|
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 });
|
|
19492
|
+
function openTeamsAccessManagement() {
|
|
19493
|
+
window.location.hash = "coordinator-admin";
|
|
19659
19494
|
}
|
|
19660
|
-
function SyncPeerCard({ peer, onAssignActor, onRemove, onRename,
|
|
19495
|
+
function SyncPeerCard({ peer, onAssignActor, onRemove, onRename, onSync }) {
|
|
19661
19496
|
const peerId = String(peer.peer_device_id || "");
|
|
19662
19497
|
const displayName = peer.name || (peerId ? peerId.slice(0, 8) : "unknown");
|
|
19663
19498
|
const destructiveLabel = peer.name || peerId || displayName;
|
|
19664
|
-
const pendingScopeReview = isPeerScopeReviewPending(peerId);
|
|
19665
19499
|
const trustSummary = derivePeerTrustSummary(peer);
|
|
19666
19500
|
const directionHint = DIRECTION_GLYPH[derivePeerDirection(peer)];
|
|
19667
19501
|
const peerStatus = peer.status || {};
|
|
19668
19502
|
const authorizedDomains = derivePeerAuthorizedDomainsView(peer);
|
|
19503
|
+
const rawPendingScopeReview = isPeerScopeReviewPending(peerId);
|
|
19504
|
+
const pendingScopeReview = rawPendingScopeReview && authorizedDomains.total === 0;
|
|
19669
19505
|
const grantRoleMismatch = derivePeerGrantRoleMismatchView(peer);
|
|
19670
19506
|
const scopeRejections = derivePeerScopeRejectionsView(peer);
|
|
19671
|
-
const
|
|
19672
|
-
const projectNarrowing = derivePeerProjectNarrowingView(scope);
|
|
19673
|
-
const includeList = listText(scope.include);
|
|
19674
|
-
const excludeList = listText(scope.exclude);
|
|
19507
|
+
const projectNarrowing = derivePeerProjectNarrowingView(peer.project_scope || {});
|
|
19675
19508
|
const primaryAddress = pickPrimaryAddress(peer.addresses);
|
|
19676
19509
|
const peerAddresses = Array.isArray(peer.addresses) ? Array.from(new Set(peer.addresses.filter(Boolean).map((value) => String(value)))) : [];
|
|
19677
19510
|
const rawHiddenAddressCount = Number(peer.address_count ?? 0);
|
|
@@ -19680,11 +19513,9 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19680
19513
|
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
19514
|
const lastSyncAt = String(peerStatus.last_sync_at || peerStatus.last_sync_at_utc || "");
|
|
19682
19515
|
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);
|
|
19516
|
+
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
19517
|
const scopeReviewRequested = consumePeerScopeReviewRequest(peerId);
|
|
19686
19518
|
const cardRef = A$1(null);
|
|
19687
|
-
const [scopeHost, setScopeHost] = d$2(null);
|
|
19688
19519
|
const [renameValue, setRenameValue] = d$2(displayName);
|
|
19689
19520
|
const [feedback, setFeedback] = d$2(() => state.syncPeerFeedbackById.get(peerId) ?? null);
|
|
19690
19521
|
const [renameBusy, setRenameBusy] = d$2(false);
|
|
@@ -19695,10 +19526,6 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19695
19526
|
const [selectedActorId, setSelectedActorId] = d$2(String(peer.actor_id || ""));
|
|
19696
19527
|
const [applyActorBusy, setApplyActorBusy] = d$2(false);
|
|
19697
19528
|
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
19529
|
const actorSelectOptions = T$1(() => {
|
|
19703
19530
|
const options = buildActorSelectOptions(selectedActorId);
|
|
19704
19531
|
const hasSelected = options.some((option) => option.value === selectedActorId);
|
|
@@ -19715,15 +19542,12 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19715
19542
|
state.lastSyncPeers,
|
|
19716
19543
|
state.lastSyncViewModel
|
|
19717
19544
|
]);
|
|
19718
|
-
|
|
19719
|
-
peerId
|
|
19720
|
-
|
|
19721
|
-
|
|
19722
|
-
]);
|
|
19723
|
-
const excludeEditor = T$1(() => createChipEditor(excludeList, "Add project", "No exclusions", state.knownProjects), [
|
|
19545
|
+
y$2(() => {
|
|
19546
|
+
if (rawPendingScopeReview && authorizedDomains.total > 0) clearPeerScopeReview(peerId);
|
|
19547
|
+
}, [
|
|
19548
|
+
authorizedDomains.total,
|
|
19724
19549
|
peerId,
|
|
19725
|
-
|
|
19726
|
-
state.knownProjects.join("|")
|
|
19550
|
+
rawPendingScopeReview
|
|
19727
19551
|
]);
|
|
19728
19552
|
y$2(() => {
|
|
19729
19553
|
setRenameValue(displayName);
|
|
@@ -19736,16 +19560,10 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19736
19560
|
setSelectedActorId(String(peer.actor_id || ""));
|
|
19737
19561
|
setApplyActorBusy(false);
|
|
19738
19562
|
setApplyActorLabel("Save assignment");
|
|
19739
|
-
setSaveScopeBusy(false);
|
|
19740
|
-
setSaveScopeLabel("Save scope");
|
|
19741
|
-
setResetScopeBusy(false);
|
|
19742
|
-
setResetScopeLabel("Reset to global scope");
|
|
19743
19563
|
}, [
|
|
19744
19564
|
displayName,
|
|
19745
19565
|
peer.actor_id,
|
|
19746
|
-
peerId
|
|
19747
|
-
includeList.join("|"),
|
|
19748
|
-
excludeList.join("|")
|
|
19566
|
+
peerId
|
|
19749
19567
|
]);
|
|
19750
19568
|
y$2(() => {
|
|
19751
19569
|
if (!scopeReviewRequested || !cardRef.current) return;
|
|
@@ -19783,10 +19601,10 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19783
19601
|
async function sync() {
|
|
19784
19602
|
if (pendingScopeReview) {
|
|
19785
19603
|
if (!await openSyncConfirmDialog({
|
|
19786
|
-
title: `Sync ${displayName} before
|
|
19787
|
-
description: "This manual sync will use the current
|
|
19604
|
+
title: `Sync ${displayName} before advanced rule review?`,
|
|
19605
|
+
description: "This manual sync will use the current Space access and advanced filters until you review them in Teams.",
|
|
19788
19606
|
confirmLabel: "Sync anyway",
|
|
19789
|
-
cancelLabel: "Review
|
|
19607
|
+
cancelLabel: "Review in Teams first"
|
|
19790
19608
|
})) return;
|
|
19791
19609
|
}
|
|
19792
19610
|
setSyncBusy(true);
|
|
@@ -19835,36 +19653,6 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19835
19653
|
setApplyActorBusy(false);
|
|
19836
19654
|
}
|
|
19837
19655
|
}
|
|
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
19656
|
const isExpanded = useExpandedPeer() === peerId && peerId !== "";
|
|
19869
19657
|
const drawerId = `device-drawer-${peerId || "unknown"}`;
|
|
19870
19658
|
const presenceState = presenceForPeer(peer);
|
|
@@ -19911,11 +19699,11 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19911
19699
|
}),
|
|
19912
19700
|
pendingScopeReview ? /* @__PURE__ */ u("span", {
|
|
19913
19701
|
className: "badge actor-badge",
|
|
19914
|
-
children: "
|
|
19702
|
+
children: "Review advanced rules"
|
|
19915
19703
|
}) : null,
|
|
19916
19704
|
/* @__PURE__ */ u("span", {
|
|
19917
19705
|
className: `badge ${authorizedDomains.isWarning ? "badge-offline" : "actor-badge"}`,
|
|
19918
|
-
title: "
|
|
19706
|
+
title: "Spaces are the hard access boundary; advanced filters only narrow inside them.",
|
|
19919
19707
|
children: authorizedDomains.badgeLabel
|
|
19920
19708
|
}),
|
|
19921
19709
|
scopeRejections.badgeLabel ? /* @__PURE__ */ u("span", {
|
|
@@ -19925,7 +19713,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19925
19713
|
}) : null,
|
|
19926
19714
|
grantRoleMismatch.badgeLabel ? /* @__PURE__ */ u("span", {
|
|
19927
19715
|
className: "badge badge-offline",
|
|
19928
|
-
title: "Review whether explicit
|
|
19716
|
+
title: "Review whether explicit Space access matches this device's intended role.",
|
|
19929
19717
|
children: grantRoleMismatch.badgeLabel
|
|
19930
19718
|
}) : null,
|
|
19931
19719
|
peer.discovered_via_group_id ? /* @__PURE__ */ u("span", {
|
|
@@ -19999,10 +19787,10 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
19999
19787
|
children: [
|
|
20000
19788
|
scopeReviewRequested ? /* @__PURE__ */ u("div", {
|
|
20001
19789
|
className: "peer-meta",
|
|
20002
|
-
children: "Review this device's
|
|
19790
|
+
children: "Review this device's Space access and advanced rules in Teams if the defaults are too broad."
|
|
20003
19791
|
}) : pendingScopeReview ? /* @__PURE__ */ u("div", {
|
|
20004
19792
|
className: "peer-meta",
|
|
20005
|
-
children: "
|
|
19793
|
+
children: "Advanced rule review is still pending for this device."
|
|
20006
19794
|
}) : null,
|
|
20007
19795
|
/* @__PURE__ */ u("div", {
|
|
20008
19796
|
className: "peer-scope-summary",
|
|
@@ -20022,15 +19810,15 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
20022
19810
|
}),
|
|
20023
19811
|
/* @__PURE__ */ u("div", {
|
|
20024
19812
|
className: "peer-scope-summary",
|
|
20025
|
-
children: "
|
|
19813
|
+
children: "Space access"
|
|
20026
19814
|
}),
|
|
20027
19815
|
/* @__PURE__ */ u("div", {
|
|
20028
19816
|
className: "peer-meta",
|
|
20029
|
-
children: authorizedDomains.total > 0 ? "These
|
|
19817
|
+
children: authorizedDomains.total > 0 ? "These Spaces are the hard access boundary for this device." : authorizedDomains.emptyMessage
|
|
20030
19818
|
}),
|
|
20031
19819
|
authorizedDomains.domains.length > 0 ? /* @__PURE__ */ u("ul", {
|
|
20032
19820
|
className: "peer-scope-chips",
|
|
20033
|
-
"aria-label": "Authorized
|
|
19821
|
+
"aria-label": "Authorized Spaces",
|
|
20034
19822
|
children: authorizedDomains.domains.map((domain) => /* @__PURE__ */ u("li", {
|
|
20035
19823
|
className: "peer-scope-chip",
|
|
20036
19824
|
title: domain.detail,
|
|
@@ -20116,41 +19904,28 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
20116
19904
|
}),
|
|
20117
19905
|
/* @__PURE__ */ u("div", {
|
|
20118
19906
|
className: "peer-scope-summary",
|
|
20119
|
-
children: "
|
|
19907
|
+
children: "Advanced sharing rules"
|
|
20120
19908
|
}),
|
|
20121
19909
|
/* @__PURE__ */ u("div", {
|
|
20122
19910
|
className: "peer-meta",
|
|
20123
|
-
children: [
|
|
19911
|
+
children: [
|
|
19912
|
+
projectNarrowing.statusLabel,
|
|
19913
|
+
". ",
|
|
19914
|
+
projectNarrowing.summary,
|
|
19915
|
+
" ",
|
|
19916
|
+
projectNarrowing.note
|
|
19917
|
+
]
|
|
20124
19918
|
}),
|
|
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
|
-
})] })
|
|
19919
|
+
/* @__PURE__ */ u("div", {
|
|
19920
|
+
className: "peer-actions",
|
|
19921
|
+
children: /* @__PURE__ */ u("button", {
|
|
19922
|
+
type: "button",
|
|
19923
|
+
className: "settings-button",
|
|
19924
|
+
onClick: openTeamsAccessManagement,
|
|
19925
|
+
children: "Manage Spaces in Teams"
|
|
19926
|
+
})
|
|
20151
19927
|
}),
|
|
20152
|
-
/* @__PURE__ */ u(SyncInlineFeedback, { feedback })
|
|
20153
|
-
/* @__PURE__ */ u("div", { ref: setScopeHost })
|
|
19928
|
+
/* @__PURE__ */ u(SyncInlineFeedback, { feedback })
|
|
20154
19929
|
]
|
|
20155
19930
|
})]
|
|
20156
19931
|
})]
|
|
@@ -20249,8 +20024,10 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
20249
20024
|
if (!syncPeers) return;
|
|
20250
20025
|
hideSkeleton("syncPeersSkeleton");
|
|
20251
20026
|
const peers = state.lastSyncPeers;
|
|
20027
|
+
const peersArray = Array.isArray(peers) ? peers : [];
|
|
20028
|
+
if (shouldClearStalePeersFeedback(state.syncPeersSectionFeedback, peersArray)) state.syncPeersSectionFeedback = null;
|
|
20252
20029
|
renderSyncPeersList(syncPeers, {
|
|
20253
|
-
peers:
|
|
20030
|
+
peers: peersArray,
|
|
20254
20031
|
onRename: async (peerId, nextName) => {
|
|
20255
20032
|
try {
|
|
20256
20033
|
await renamePeer(peerId, nextName);
|
|
@@ -20279,7 +20056,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
20279
20056
|
tone: "warning"
|
|
20280
20057
|
};
|
|
20281
20058
|
else if (peerId && isPeerScopeReviewPending(peerId)) feedback = {
|
|
20282
|
-
message: `Triggered sync for ${peer?.name || (peerId ? peerId.slice(0, 8) : "unknown")}. Review
|
|
20059
|
+
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
20060
|
tone: "warning"
|
|
20284
20061
|
};
|
|
20285
20062
|
else feedback = {
|
|
@@ -20310,7 +20087,10 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
20310
20087
|
tone: "success"
|
|
20311
20088
|
};
|
|
20312
20089
|
state.syncPeerFeedbackById.delete(peerId);
|
|
20313
|
-
state.syncPeersSectionFeedback =
|
|
20090
|
+
state.syncPeersSectionFeedback = {
|
|
20091
|
+
...feedback,
|
|
20092
|
+
relatedPeerDeviceId: peerId
|
|
20093
|
+
};
|
|
20314
20094
|
await _loadSyncData();
|
|
20315
20095
|
return feedback;
|
|
20316
20096
|
} catch (error) {
|
|
@@ -20334,38 +20114,6 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
20334
20114
|
tone: "warning"
|
|
20335
20115
|
};
|
|
20336
20116
|
}
|
|
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
20117
|
}
|
|
20370
20118
|
});
|
|
20371
20119
|
}
|
|
@@ -21366,7 +21114,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21366
21114
|
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
21115
|
mode = "ambiguous";
|
|
21368
21116
|
} else if (pairedPeer && isPeerScopeReviewPending(deviceId)) {
|
|
21369
|
-
actionMessage =
|
|
21117
|
+
actionMessage = "Review this device's Space access and advanced rules in Teams before you sync it.";
|
|
21370
21118
|
mode = "scope-pending";
|
|
21371
21119
|
} else if (pairedPeer?.last_error) {
|
|
21372
21120
|
noteParts.push(`error: ${String(pairedPeer.last_error)}`);
|
|
@@ -21554,14 +21302,41 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21554
21302
|
const label = group.displayProject.toLowerCase();
|
|
21555
21303
|
return label.includes("fatal:") || label.includes("not a git repository") || label === "unknown project" || group.identitySource === "unmapped";
|
|
21556
21304
|
}
|
|
21305
|
+
function displayProjectTitle(group) {
|
|
21306
|
+
return needsProjectCleanup(group) ? "Unclear project identity" : group.displayProject;
|
|
21307
|
+
}
|
|
21557
21308
|
function canReassignLegacyGroup(group) {
|
|
21558
21309
|
return (group.reassignableMemoryCount ?? group.memoryCount) > 0;
|
|
21559
21310
|
}
|
|
21560
|
-
function
|
|
21311
|
+
function suggestedScopeText(group, targetScopes) {
|
|
21312
|
+
if (!group.suggestedScopeId) return "";
|
|
21313
|
+
return ` · suggested ${targetScopes.find((scope) => scope.scopeId === group.suggestedScopeId)?.label || "Space"}`;
|
|
21314
|
+
}
|
|
21315
|
+
function escapeRegExp(value) {
|
|
21316
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
21317
|
+
}
|
|
21318
|
+
function targetScopeLabel(scopeId, targetScopes) {
|
|
21319
|
+
return targetScopes.find((scope) => scope.scopeId === scopeId)?.label || "selected Space";
|
|
21320
|
+
}
|
|
21321
|
+
function authorityLabel(authorityType) {
|
|
21322
|
+
switch (authorityType) {
|
|
21323
|
+
case "coordinator": return "Team Space";
|
|
21324
|
+
case "local": return "Local Space";
|
|
21325
|
+
default: return "Other Space";
|
|
21326
|
+
}
|
|
21327
|
+
}
|
|
21328
|
+
function formatLegacyReviewError(error, scopeId, targetScopes) {
|
|
21329
|
+
let result = (error instanceof Error ? error.message : "Unable to reassign legacy review memories.").replace(/sharing domain/gi, "Space");
|
|
21330
|
+
if (scopeId) result = result.replace(new RegExp(`\\b${escapeRegExp(scopeId)}\\b`, "g"), targetScopeLabel(scopeId, targetScopes));
|
|
21331
|
+
return result;
|
|
21332
|
+
}
|
|
21333
|
+
function groupSearchText(group, targetScopes) {
|
|
21334
|
+
const suggestedScopeLabel = group.suggestedScopeId ? targetScopes.find((scope) => scope.scopeId === group.suggestedScopeId)?.label : "";
|
|
21561
21335
|
return [
|
|
21562
21336
|
group.displayProject,
|
|
21563
21337
|
group.identitySource,
|
|
21564
21338
|
group.suggestedScopeId ?? "",
|
|
21339
|
+
suggestedScopeLabel ?? "",
|
|
21565
21340
|
group.suggestionReason ?? "",
|
|
21566
21341
|
group.workspaceIdentity
|
|
21567
21342
|
].join(" ").toLowerCase();
|
|
@@ -21622,7 +21397,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21622
21397
|
if (filter === "cleanup" && !cleanup) return false;
|
|
21623
21398
|
if (filter === "no-suggestion" && (group.suggestedScopeId || cleanup)) return false;
|
|
21624
21399
|
if (filter === "selected" && !selectedGroups[group.workspaceIdentity]) return false;
|
|
21625
|
-
return !query.trim() || groupSearchText(group).includes(query.trim().toLowerCase());
|
|
21400
|
+
return !query.trim() || groupSearchText(group, targetScopes).includes(query.trim().toLowerCase());
|
|
21626
21401
|
});
|
|
21627
21402
|
async function applyGroup(group) {
|
|
21628
21403
|
const selectedScopeId = selectedScopes[group.workspaceIdentity] || group.suggestedScopeId || "";
|
|
@@ -21647,7 +21422,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21647
21422
|
} catch (error) {
|
|
21648
21423
|
setErrors((current) => ({
|
|
21649
21424
|
...current,
|
|
21650
|
-
[group.workspaceIdentity]: error
|
|
21425
|
+
[group.workspaceIdentity]: formatLegacyReviewError(error, selectedScopeId, targetScopes)
|
|
21651
21426
|
}));
|
|
21652
21427
|
} finally {
|
|
21653
21428
|
setBusyIdentity(null);
|
|
@@ -21711,7 +21486,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21711
21486
|
} catch (error) {
|
|
21712
21487
|
setErrors((current) => ({
|
|
21713
21488
|
...current,
|
|
21714
|
-
[group.workspaceIdentity]: error
|
|
21489
|
+
[group.workspaceIdentity]: formatLegacyReviewError(error, selectedScopeId, targetScopes)
|
|
21715
21490
|
}));
|
|
21716
21491
|
}
|
|
21717
21492
|
}
|
|
@@ -21739,7 +21514,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21739
21514
|
" older",
|
|
21740
21515
|
" ",
|
|
21741
21516
|
groupCount === 1 ? "project needs" : "projects need",
|
|
21742
|
-
" a
|
|
21517
|
+
" a Space. They contain",
|
|
21743
21518
|
" ",
|
|
21744
21519
|
item.memoryCount.toLocaleString(),
|
|
21745
21520
|
" older shared memories total; review the projects, not individual memories.",
|
|
@@ -21812,7 +21587,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21812
21587
|
children: busyIdentity === "bulk" ? "Previewing…" : `Preview ${selectedCount.toLocaleString()} selected`
|
|
21813
21588
|
}) : onReassign && selectedReassignableCount > 0 ? /* @__PURE__ */ u("span", {
|
|
21814
21589
|
className: "legacy-review-cleanup-note",
|
|
21815
|
-
children: "Add or join a
|
|
21590
|
+
children: "Add or join a Space before bulk reassignment."
|
|
21816
21591
|
}) : null,
|
|
21817
21592
|
selectedCount > 0 && groups.filter((group) => selectedGroups[group.workspaceIdentity] && canReassignLegacyGroup(group) && Boolean(selectedScopes[group.workspaceIdentity])).every((group) => pending[group.workspaceIdentity]) ? /* @__PURE__ */ u("span", {
|
|
21818
21593
|
className: "legacy-review-cleanup-note",
|
|
@@ -21832,7 +21607,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21832
21607
|
children: [/* @__PURE__ */ u("div", {
|
|
21833
21608
|
className: "legacy-review-title-wrap",
|
|
21834
21609
|
children: [/* @__PURE__ */ u("input", {
|
|
21835
|
-
"aria-label": `Select ${group
|
|
21610
|
+
"aria-label": `Select ${displayProjectTitle(group)}`,
|
|
21836
21611
|
checked: Boolean(selectedGroups[group.workspaceIdentity]),
|
|
21837
21612
|
className: "cm-checkbox",
|
|
21838
21613
|
disabled: !canReassignLegacyGroup(group),
|
|
@@ -21841,15 +21616,15 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21841
21616
|
}), /* @__PURE__ */ u("div", { children: [
|
|
21842
21617
|
/* @__PURE__ */ u("div", {
|
|
21843
21618
|
className: "legacy-review-group-title",
|
|
21844
|
-
children: group
|
|
21619
|
+
children: displayProjectTitle(group)
|
|
21845
21620
|
}),
|
|
21846
21621
|
/* @__PURE__ */ u("div", {
|
|
21847
21622
|
className: "legacy-review-group-meta",
|
|
21848
|
-
children: [formatIdentitySource(group.identitySource), group
|
|
21623
|
+
children: [formatIdentitySource(group.identitySource), suggestedScopeText(group, targetScopes)]
|
|
21849
21624
|
}),
|
|
21850
21625
|
!canReassignLegacyGroup(group) ? /* @__PURE__ */ u("div", {
|
|
21851
21626
|
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
|
|
21627
|
+
children: "Peer-owned only. These older memories were received from another device, so this device cannot reassign them to a Space."
|
|
21853
21628
|
}) : group.peerOwnedMemoryCount ? /* @__PURE__ */ u("div", {
|
|
21854
21629
|
className: "legacy-review-cleanup-note",
|
|
21855
21630
|
children: [
|
|
@@ -21867,7 +21642,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21867
21642
|
}) : null,
|
|
21868
21643
|
needsProjectCleanup(group) ? /* @__PURE__ */ u("div", {
|
|
21869
21644
|
className: "legacy-review-cleanup-note",
|
|
21870
|
-
children: "
|
|
21645
|
+
children: "Inspect or correct the project identity before assigning old shared data to a Space."
|
|
21871
21646
|
}) : null
|
|
21872
21647
|
] })]
|
|
21873
21648
|
}), /* @__PURE__ */ u("span", {
|
|
@@ -21906,20 +21681,20 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21906
21681
|
}) : null,
|
|
21907
21682
|
targetScopes.length > 0 && onReassign && canReassignLegacyGroup(group) ? /* @__PURE__ */ u("label", {
|
|
21908
21683
|
className: "legacy-review-target",
|
|
21909
|
-
children: [/* @__PURE__ */ u("span", { children: "Destination
|
|
21684
|
+
children: [/* @__PURE__ */ u("span", { children: "Destination Space" }), /* @__PURE__ */ u("select", {
|
|
21910
21685
|
className: "peer-scope-input",
|
|
21911
21686
|
disabled: busyIdentity != null,
|
|
21912
21687
|
onChange: (event) => updateSelectedScope(group, event.currentTarget.value),
|
|
21913
21688
|
value: selectedScopes[group.workspaceIdentity] || "",
|
|
21914
21689
|
children: [/* @__PURE__ */ u("option", {
|
|
21915
21690
|
value: "",
|
|
21916
|
-
children: "Choose
|
|
21691
|
+
children: "Choose Space…"
|
|
21917
21692
|
}), targetScopes.map((scope) => /* @__PURE__ */ u("option", {
|
|
21918
21693
|
value: scope.scopeId,
|
|
21919
21694
|
children: [
|
|
21920
21695
|
scope.label,
|
|
21921
21696
|
" · ",
|
|
21922
|
-
scope.authorityType,
|
|
21697
|
+
authorityLabel(scope.authorityType),
|
|
21923
21698
|
scope.scopeId === group.suggestedScopeId ? " · suggested" : ""
|
|
21924
21699
|
]
|
|
21925
21700
|
}, scope.scopeId))]
|
|
@@ -22222,7 +21997,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
22222
21997
|
try {
|
|
22223
21998
|
const runtime = await loadRuntimeInfo();
|
|
22224
21999
|
if (!runtime?.version) return;
|
|
22225
|
-
setRuntimeLabel(runtime.version, "
|
|
22000
|
+
setRuntimeLabel(runtime.version, "2eab49c");
|
|
22226
22001
|
} catch {}
|
|
22227
22002
|
}
|
|
22228
22003
|
var lastAnnouncedRefreshState = null;
|