admin: title-only information becomes visible text
the client address follows its name as visible muted text in the query tables, the config lock indicator prints its reason beside the tag except in table rows where a page-level note explains the lock instead, and the locked delete buttons describe themselves through that one visible note. the chart legend tooltip is deleted because a named client is deliberately not addressed in the chart, and the dead series address field went with it. titles that merely repeat visible copyable text stay.
This commit is contained in:
@@ -10,7 +10,7 @@ import NetworkAssignments from "./NetworkAssignments";
|
||||
import { ClientDisplayName } from "./clientIdentity";
|
||||
import InlineError from "@/lib/InlineError";
|
||||
import ConfirmDialog from "@/ui/ConfirmDialog";
|
||||
import ConfigLockIndicator from "@/features/configuration/ConfigLockIndicator";
|
||||
import ConfigLockIndicator, { lockReason } from "@/features/configuration/ConfigLockIndicator";
|
||||
import { useAuthority, useReadOnlyConfig, type Authority } from "@/features/configuration/authority";
|
||||
import { styles as shared } from "@/ui/styles";
|
||||
import { colors } from "@/ui/tokens.stylex";
|
||||
@@ -25,6 +25,9 @@ import { colors } from "@/ui/tokens.stylex";
|
||||
* alone cannot say which operator surface set the row — so the sentence names
|
||||
* the doubt rather than asserting a declaration, the way `provenanceOf` does.
|
||||
*/
|
||||
/** The one note every locked Delete on this page describes itself with. */
|
||||
const DELETE_LOCK_NOTE_ID = "clients-delete-locked-note";
|
||||
|
||||
function declaredDeleteNote(authority: Authority): string {
|
||||
if (authority.state === "resolved") {
|
||||
return "This client is declared in the configuration file; remove it there and restart.";
|
||||
@@ -52,6 +55,15 @@ const styles = stylex.create({
|
||||
marginTop: "1rem",
|
||||
color: colors.textMuted,
|
||||
},
|
||||
lockNote: {
|
||||
marginTop: "1rem",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "0.25rem",
|
||||
fontSize: "0.875rem",
|
||||
lineHeight: "1.25rem",
|
||||
color: colors.textMuted,
|
||||
},
|
||||
filterBar: {
|
||||
marginTop: "1rem",
|
||||
display: "flex",
|
||||
@@ -127,6 +139,11 @@ export default function ClientsPage() {
|
||||
// question: the operator is told why, and only they close the dialog.
|
||||
const deleteLocked = pendingDelete !== null && readOnly && pendingDelete.hand_edited;
|
||||
|
||||
// The reason a locked Delete will not answer, printed once above the table.
|
||||
// Per row it would repeat down the whole page; on the button it was a `title`
|
||||
// that a keyboard and a touch screen never reached.
|
||||
const deletesLocked = readOnly && rows.some((client) => client.hand_edited);
|
||||
|
||||
return (
|
||||
<section>
|
||||
<h1 {...stylex.props(styles.heading)}>Clients</h1>
|
||||
@@ -142,6 +159,15 @@ export default function ClientsPage() {
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
{/* The whole explanation for this page's locks, printed once. Per row it
|
||||
would repeat down the table; on the controls it was a `title` that a
|
||||
keyboard and a touch screen never reached. */}
|
||||
{readOnly && (
|
||||
<div {...stylex.props(styles.lockNote)}>
|
||||
<p>{lockReason(authority)}.</p>
|
||||
{deletesLocked && <p id={DELETE_LOCK_NOTE_ID}>{declaredDeleteNote(authority)}</p>}
|
||||
</div>
|
||||
)}
|
||||
{clients.length === 0 ? (
|
||||
<p {...stylex.props(styles.empty)}>
|
||||
No clients yet. Rows appear automatically as devices on the network make DNS queries — there is
|
||||
@@ -187,7 +213,7 @@ export default function ClientsPage() {
|
||||
{/* Naming a client writes configuration, so the affordance is
|
||||
absent — not disabled — wherever the write cannot land. */}
|
||||
{readOnly ? (
|
||||
<ConfigLockIndicator />
|
||||
<ConfigLockIndicator compact />
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
@@ -201,10 +227,8 @@ export default function ClientsPage() {
|
||||
type="button"
|
||||
onClick={() => setPendingDelete(client)}
|
||||
disabled={readOnly && client.hand_edited}
|
||||
title={
|
||||
readOnly && client.hand_edited
|
||||
? declaredDeleteNote(authority)
|
||||
: undefined
|
||||
aria-describedby={
|
||||
readOnly && client.hand_edited ? DELETE_LOCK_NOTE_ID : undefined
|
||||
}
|
||||
{...stylex.props(
|
||||
shared.smallButton,
|
||||
|
||||
Reference in New Issue
Block a user