fix(web): explain why older connections cannot update servers#23374
0 / 4 viewed4 files changedLine totals unavailable
apps/web/src/components/ServerUpdateAction.browser.test.tsx Β· Earlier revision d6055961 Β· right 285
Original diff
@@ -228,4 +268,66 @@ describe("ServerUpdatesAction", () => {
);
expect(button(screen, "Update all")!.disabled).toBe(false);
});
+
+ it("does not offer Update all when no target grants environment:maintain", async () => {
+ using _state = setup();
+ setSession(AsyncResult.success(legacyPairedSession));
+ await using screen = await mount(targets.slice(0, 2));
+
+ expect(button(screen, "Update all")!.disabled).toBe(true);
+ expect(explanation(screen)).toMatch(/pair/i);
+ });
+
+ it("does not ask to pair again when a mixed batch is pending", async () => {
+ using _state = setup();
+ const denied = Atom.make<SessionResult>(AsyncResult.success(legacyPairedSession));
+ testState.sessionAtoms.set("batch-b" as EnvironmentId, denied);
+ const update = Promise.withResolvers<ReturnType<typeof success>>();apps/server/scripts/issue-17034-fixture.mjs Β· Earlier revision d6055961 Β· right 1β25
Original diff
@@ -0,0 +1,234 @@ +/** + * Actual-app update-permission evidence fixture; never starts a server or browser. + * Run from any directory with Node 26: + * node apps/server/scripts/issue-17034-fixture.mjs init /tmp/t3-issue-17034-proof + * node apps/server/scripts/issue-17034-fixture.mjs sessions /tmp/t3-issue-17034-private HOME_A HOME_B HOME_C + * node apps/server/scripts/issue-17034-fixture.mjs projects /tmp/t3-issue-17034-project HOME_A HOME_B HOME_C + * node apps/server/scripts/issue-17034-fixture.mjs descriptor-apply /tmp/t3-issue-17034-descriptor.json 16471 16472 16473 16474 + * node apps/server/scripts/issue-17034-fixture.mjs descriptor-restore /tmp/t3-issue-17034-descriptor.json 16471 16472 16473 16474 + * + * Coordinate ALL servers sharing this checkout with their owner before apply/restore. + * Ports must include every such server. Both commands refuse listening ports and + * live runtime PIDs in this worktree's .t3. Apply requires the committed source; + * restore requires the exact patched source. Never stage the descriptor or backup. + * Metadata advertises an update; it does not install a boot service. Do not infer + * successful updates from it. Pending/races/desktop branches still need a harness. + * + * init is for NEW homes only; existing lead-owned homes can go directly to sessions + * or projects. Sessions are minted privately by the supported auth CLI (not fixed + * tokens). Re-running sessions creates new credentials, so revoke old sessions via + * the auth CLI when finished. Output is private mode-0600 JSON; never publish it. + * projects uses the real project CLI and an empty Git repository shared by all homes. + * Select its new draft and Auto balance in the real client; no draft/catalog writes. + * Labels below are capture inputs, NOT a server-label override: the server descriptor + * derives its label from the OS. No supported server-label setting exists here. + */
apps/server/scripts/issue-17034-fixture.mjs Β· right 1β25
apps/web/src/components/ServerUpdateAction.tsx Β· Earlier revision d6055961 Β· right 191
Original diff
@@ -133,12 +185,30 @@ export function ServerUpdatesAction({
target.selfUpdate !== null &&
(target.selfUpdate !== "desktop-managed" || target.desktopAppUpdate),
);
+ const sessionStates = useAtomValue(
+ environmentSessionStatesAtom(environmentIdsKey(eligible.map((target) => target.environmentId))),
+ );
+ const permitted = eligible.filter((_, index) => !isUpdatePermissionDenied(sessionStates[index]!));