diff --git a/apps/app/src/directory-settings.tsx b/apps/app/src/directory-settings.tsx index d0a949d3..0f2035a4 100644 --- a/apps/app/src/directory-settings.tsx +++ b/apps/app/src/directory-settings.tsx @@ -1,7 +1,7 @@ import { type ReactNode, useState } from "react"; import { Button, Input } from "@ace/ui"; -import type { Diagnostics } from "@ace/host/protocol"; +import { type Diagnostics, type Share, TEAM } from "@ace/host/protocol"; import { desktop } from "./desktop"; import { host } from "./host"; @@ -180,6 +180,20 @@ function served(directory: Diagnostics["directory"]): boolean { return directory.serving || URL.parse(directory.url || "")?.pathname === "/directory"; } +/** Each shared project and who it is shared with, as "b-sandbox with the team; ace with rivera". */ +function shared(shares: Share[]): string { + const projects = new Map(); + for (const { project, person } of shares) { + const name = project.startsWith("github:") + ? project.slice("github:".length) + : (JSON.parse(project) as [string, string])[1].replace(/\/+$/, "").split("/").pop()!; + const people = projects.get(name) || []; + people.push(person === TEAM ? "the team" : person); + projects.set(name, people); + } + return [...projects].map(([name, people]) => `${name} with ${people.join(", ")}`).join("; "); +} + /** A time today, or a date and time when older, so a stale sync doesn't read as recent. */ function when(time: number) { const date = new Date(time); @@ -340,8 +354,12 @@ function TeamDirectory( )} onCancel={() => setConfirm(undefined)} > - Stop serving the directory? Teammates stop seeing channels on offline Macs, and its - shares are deleted. + Stop serving the directory? Teammates stop seeing channels on offline Macs + {directory.shares.length + ? `, and these shares are deleted, ending the access they give: ${ + shared(directory.shares) + }.` + : "."} )} {confirm === "leave" && ( diff --git a/apps/host/src/diagnostics.ts b/apps/host/src/diagnostics.ts index 1089770c..e9df05b9 100644 --- a/apps/host/src/diagnostics.ts +++ b/apps/host/src/diagnostics.ts @@ -61,6 +61,7 @@ export async function diagnostics(sync?: boolean): Promise { secret: await secret, services: { hosted, app, compute }, serving: served.isServing(), + shares: served.shares(), }, shell: { ...environment }, web: web.address, diff --git a/apps/host/src/directory-server.ts b/apps/host/src/directory-server.ts index 56c1563e..c1362f23 100644 --- a/apps/host/src/directory-server.ts +++ b/apps/host/src/directory-server.ts @@ -96,6 +96,12 @@ export function remove(): void { log("info", "directory.removed", {}); } +/** The project shares stopping deletes. */ +export function shares(): Share[] { + if (!isServing()) return []; + return open().query('SELECT project, person, shared_by AS "by", at FROM shares').all(); +} + /** Requests under `/directory`, with `path` the rest. */ export async function handle(path: string, request: Request, caller: Caller): Promise { if (!isServing()) return new Response("This host serves no directory", { status: 404 }); @@ -150,7 +156,7 @@ function read(sql: Database) { channels: sql.query<{ listing: string }, []>("SELECT listing FROM channels").all().map((row) => JSON.parse(row.listing) ), - shares: sql.query('SELECT project, person, shared_by AS "by", at FROM shares').all(), + shares: shares(), }; } diff --git a/apps/host/src/protocol.ts b/apps/host/src/protocol.ts index 524cb9b4..825d4fbb 100644 --- a/apps/host/src/protocol.ts +++ b/apps/host/src/protocol.ts @@ -66,6 +66,8 @@ export type Diagnostics = { services: { hosted?: string; app?: string; compute?: string }; /** This host serves the team's directory on the tailnet. */ serving: boolean; + /** The project shares in the directory this host serves, which stopping it deletes. */ + shares: Share[]; }; /** Whether the helper loaded the login shell's environment; `pending` while it retries. */ shell: { state: "adopted" | "pending" | "failed"; error?: string };