Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ anchor: function App
created: 2026-10-15T03:38:04Z
norm: '1'
sig: 063d0f00fea02511
body_hash: cf62711c75c66568
raw_hash: 38568af4c890e786
vouched: 2026-10-22T20:27:44Z
body_hash: b0a39d06b7ed2900
raw_hash: 2b2e4ccf7e3ee6f2
vouched: 2026-10-22T20:29:47Z
lines: 235-824
---

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
id: 01M5JMVG9G87F31FGVV571Y6BJ
anchor: function App
created: 2026-10-22T20:29:16Z
norm: '1'
sig: 063d0f00fea02511
body_hash: b0a39d06b7ed2900
raw_hash: 2b2e4ccf7e3ee6f2
vouched: 2026-10-22T20:29:47Z
lines: 330-1237
---

the project list is built only once hello names this host and its projects frame arrives; earlier, its own channels read as a teammate's
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ anchor: class GatewayClient
created: 2026-10-15T02:55:20Z
norm: '1'
sig: 41366b9e88f0e890
body_hash: 37f27c37825b3457
raw_hash: c990e819f8c5c8e5
vouched: 2026-10-22T14:33:27Z
body_hash: f327ecd85b1a1ced
raw_hash: eb40263f67d2ffcb
vouched: 2026-10-22T20:29:22Z
lines: 33-240
---

Expand Down
26 changes: 14 additions & 12 deletions apps/app/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -444,11 +444,12 @@ export function App() {
host.request<Hello>({ op: "hello" }).then(setHello, () => {});
}, [status]);

const available = useMemo(() => projects(opened, channels, hello.host), [
opened,
channels,
hello.host,
]);
// Until this host names itself and lists its projects, its own channels read as a teammate's.
const loaded = !!opened && !!hello.host;
const available = useMemo(
() => opened && hello.host ? projects(opened, channels, hello.host) : [],
[opened, channels, hello.host],
);
useGithubRefresh(available);
const listings = new Map(channels.map((channel) => [channel.id, channel]));
const byId = useMemo(() => {
Expand All @@ -464,9 +465,10 @@ export function App() {
const repo = useGithub<string | null>(
current && { op: "project-repo", project: current.path, host: current.host },
);
// Only a definite answer hides GitHub, so the lists can still say why a lookup failed.
const linked = repo.value !== null;
const page = !linked && (saved === "issues" || saved === "prs") ? "channels" : saved;
// Only a definite answer hides GitHub, so the lists can still say why a lookup failed; Issues and
// PRs appear once the lookup answers either way, so they never show and then vanish.
const linked = !!repo.value || (status === "open" && !!repo.error);
const page = repo.value === null && (saved === "issues" || saved === "prs") ? "channels" : saved;
function go(next: Page) {
if (linked || (next !== "issues" && next !== "prs")) setPage(next);
}
Expand Down Expand Up @@ -613,7 +615,7 @@ export function App() {

// Declared, not a const: the picker and All Projects groups above call it during render.
function removable(value: AppProject) {
return connected && opened.some((checkout) => isLocal(checkout, value));
return connected && !!opened?.some((checkout) => isLocal(checkout, value));
}

function remove(value: AppProject) {
Expand All @@ -623,7 +625,7 @@ export function App() {

async function forget(value: AppProject) {
try {
for (const checkout of opened.filter((checkout) => isLocal(checkout, value))) {
for (const checkout of opened?.filter((checkout) => isLocal(checkout, value)) || []) {
await host.request({ op: "project-remove", path: checkout.path });
}
} catch (error) {
Expand Down Expand Up @@ -872,7 +874,7 @@ export function App() {
page={page}
user={hello.user}
github={people[hello.user]}
repo={linked}
repo={linked || page === "issues" || page === "prs"}
onPage={go}
onSettings={() => setSettings(true)}
/>
Expand Down Expand Up @@ -999,7 +1001,7 @@ export function App() {
<Disconnected />
</p>
)}
{!current && !connected
{!current && (!connected || !loaded)
? null
: !current
? (
Expand Down
3 changes: 2 additions & 1 deletion apps/host/src/gateway-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ export class GatewayClient {
*/
stalled = false;
channels: Listing[] = [];
projects: Project[] = [];
/** Undefined until the host first sends them, so an app can tell loading from having none. */
projects?: Project[];
people: People = {};
/** Asks to join the team waiting for this host's owner; only the local app receives them. */
asks: TeamAsk[] = [];
Expand Down