swarm-ui: agents page — explainer message when the roster is empty
Table gains an optional emptyMessage prop, rendered as a single full-width row in place of a bare empty tbody; AgentsPage is the first consumer. Screenshot-verified against a mock server returning an empty roster.
This commit is contained in:
parent
f1ab7cd43d
commit
46d1271603
3 changed files with 34 additions and 7 deletions
|
|
@ -115,7 +115,14 @@ export function AgentsPage() {
|
||||||
>
|
>
|
||||||
{error ? <ApiErrorPanel context="failed to load the agent roster" problem={error} /> : null}
|
{error ? <ApiErrorPanel context="failed to load the agent roster" problem={error} /> : null}
|
||||||
{!error && rows === null ? <p>loading…</p> : null}
|
{!error && rows === null ? <p>loading…</p> : null}
|
||||||
{rows ? <Table columns={COLUMNS} rows={rows} rowKey={(a) => a.name} /> : null}
|
{rows ? (
|
||||||
|
<Table
|
||||||
|
columns={COLUMNS}
|
||||||
|
rows={rows}
|
||||||
|
rowKey={(a) => a.name}
|
||||||
|
emptyMessage="no agents yet — the swarm-wide identity store has no agents registered on any hive"
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
<Dialog open={createOpen} onClose={() => setCreateOpen(false)} label="create agent">
|
<Dialog open={createOpen} onClose={() => setCreateOpen(false)} label="create agent">
|
||||||
<CreateAgentForm />
|
<CreateAgentForm />
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
|
||||||
|
|
@ -21,3 +21,8 @@
|
||||||
.ui-table tr:last-child td {
|
.ui-table tr:last-child td {
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
|
.ui-table-empty {
|
||||||
|
color: var(--muted);
|
||||||
|
text-align: center;
|
||||||
|
padding: 1.25em 0.75em;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,17 @@ export function Table<T>({
|
||||||
columns,
|
columns,
|
||||||
rows,
|
rows,
|
||||||
rowKey,
|
rowKey,
|
||||||
|
emptyMessage,
|
||||||
}: {
|
}: {
|
||||||
columns: TableColumn<T>[];
|
columns: TableColumn<T>[];
|
||||||
rows: T[];
|
rows: T[];
|
||||||
rowKey: (row: T) => string;
|
rowKey: (row: T) => string;
|
||||||
|
// Rendered as a single full-width row when `rows` is empty. Omit to
|
||||||
|
// leave a bare empty `<tbody>` — a caller whose "no rows yet" is
|
||||||
|
// covered by its own loading/error state (rendered instead of the
|
||||||
|
// table entirely) has nothing useful to add here, so this stays
|
||||||
|
// opt-in rather than every table growing a mandatory default string.
|
||||||
|
emptyMessage?: ComponentChildren;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div class="ui-table-scroll">
|
<div class="ui-table-scroll">
|
||||||
|
|
@ -38,13 +45,21 @@ export function Table<T>({
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{rows.map((row) => (
|
{rows.length === 0 && emptyMessage ? (
|
||||||
<tr key={rowKey(row)}>
|
<tr>
|
||||||
{columns.map((c) => (
|
<td class="ui-table-empty" colSpan={columns.length}>
|
||||||
<td key={c.key}>{c.render(row)}</td>
|
{emptyMessage}
|
||||||
))}
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
) : (
|
||||||
|
rows.map((row) => (
|
||||||
|
<tr key={rowKey(row)}>
|
||||||
|
{columns.map((c) => (
|
||||||
|
<td key={c.key}>{c.render(row)}</td>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
))
|
||||||
|
)}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue