// ── Admin · Rust · Permissions — a group's chat style (phase 17, D138) ───── // // All twelve of BetterChat's group fields, on a group this site authors. A style // is the whole of a BetterChat group or nothing, so the editor always shows all // twelve, starting from BetterChat's own defaults. // // Three things the section says out loud, because each looks like success from // here: // // • a server where BetterChat is not loaded holds nothing yet — the style // lands when BetterChat does, at the next sync; // • a field somebody changed in game is NOT overwritten — it shows under // "Changed in game", to adopt or put back; // • a field BetterChat refused (`InvalidValue`) is named with its server. // // Removing a style removes the group from BetterChat on the next sync (D139), // which is BetterChat's own `chat group remove` — it has no quieter way. import { useState } from 'react' const LABELS = { Priority: 'Priority (lower wins when a player is in several groups)', Title: 'Title', TitleColor: 'Title colour', TitleSize: 'Title size', TitleHidden: 'Hide the title', TitleHiddenIfNotPrimary: 'Hide the title unless this is the player’s main group', UsernameColor: 'Name colour', UsernameSize: 'Name size', MessageColor: 'Message colour', MessageSize: 'Message size', ChatFormat: 'Chat format', ConsoleFormat: 'Console format', } /** BetterChat's defaults for this group, from the field list the server sent. */ function defaultsFor(group, fields) { const out = {} for (const f of fields) out[f.name] = f.default === null ? '' : f.default out.Title = group === 'default' ? '[Player]' : `[${group}]` return out } /** What each server's last sync said about this group's style. */ function styleNotes(group, servers) { const notes = [] for (const s of servers) { const chat = s.report && s.report.chat if (!chat) continue if (chat.loaded === false) { notes.push(`${s.serverId}: BetterChat is not loaded, so nothing is styled there yet.`) continue } for (const f of chat.failed || []) { if (f.group !== group) continue notes.push(`${s.serverId}: BetterChat refused ${f.field || 'the group'} (${f.reason}).`) } } return notes } export default function ChatStyleSection({ group, fields, servers, busy, onSave }) { const [editing, setEditing] = useState(null) if (!fields || !fields.length) return null const notes = group.chat ? styleNotes(group.name, servers) : [] const set = (name, value) => setEditing((e) => ({ ...e, [name]: value })) return ( <>
Chat style (BetterChat)
{!editing && !group.chat && (

No chat style. BetterChat, where it is installed, styles this group’s members as it does anybody else.

)} {!editing && group.chat && (

{group.chat.TitleHidden === 'true' ? '(title hidden)' : group.chat.Title} {' '} priority {group.chat.Priority} · {group.chat.ChatFormat}

)} {notes.map((n) => (

{n}

))} {!editing && (
{group.chat && ( )}
)} {editing && (
{ event.preventDefault() if (await onSave(editing)) setEditing(null) }} className="sans" style={{ display: 'grid', gap: 8, marginTop: 8, fontSize: '0.82rem' }} > {fields.map((f) => ( ))}

A format must hold {'{Message}'} exactly once; {'{Title}'} and {'{Username}'}{' '} are where the title and name go. A hand edit in game is reported rather than overwritten.

)} ) }