Slice 7: §14 chrome + settings and admin neighborhoods
§14.1 richer landing, §14.2 /philosophy route (disk-backed), §14.3 persistent About link. /settings/notifications surfaces Slice 6's preferences/quiet-hours/mute/watches endpoints. /admin home base consolidates role management, the §6.2 write-mute, the audit-log viewer, the permission-events log, and the §13.2 graduation queue. Backend: backend/app/philosophy.py, backend/app/api_admin.py (seven admin endpoints + user-search), GET /api/users/me/notification-mutes. Frontend: Landing.jsx (deck), Philosophy.jsx, NotificationSettings.jsx, Admin.jsx, App.jsx routing for the chrome surfaces. Tests: backend/tests/test_chrome_vertical.py — 13 cases. Full suite 75/75 green. Spec corrections: §14.2 (PHILOSOPHY.md source is a deployment-time decision), §17 (admin block extended to name the seven new endpoints + user-search and notification-mutes read). §19.1 rewritten for Slice 8 hardening; §19.2 grew four candidates (owner succession, mute-from-actor, the "Following since <date>" disclosure, audit-log row prose). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -478,6 +478,68 @@ export async function advanceChatSeen(slug, branch, lastSeenMessageId) {
|
||||
}))
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// §14.2 / Slice 7: PHILOSOPHY.md surface
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export async function getPhilosophy() {
|
||||
return jsonOrThrow(await fetch('/api/philosophy'))
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Slice 7: admin neighborhood (§17 admin/* + user search for the §15.8 mute
|
||||
// typeahead).
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export async function listAdminUsers() {
|
||||
return jsonOrThrow(await fetch('/api/admin/users'))
|
||||
}
|
||||
|
||||
export async function setUserRole(userId, role) {
|
||||
return jsonOrThrow(await fetch(`/api/admin/users/${userId}/role`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ role }),
|
||||
}))
|
||||
}
|
||||
|
||||
export async function setUserMute(userId, muted) {
|
||||
return jsonOrThrow(await fetch(`/api/admin/users/${userId}/mute`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ muted }),
|
||||
}))
|
||||
}
|
||||
|
||||
export async function listAuditLog({ actionKind, actorUserId, rfcSlug, beforeId, limit } = {}) {
|
||||
const params = new URLSearchParams()
|
||||
if (actionKind) params.set('action_kind', actionKind)
|
||||
if (actorUserId != null) params.set('actor_user_id', actorUserId)
|
||||
if (rfcSlug) params.set('rfc_slug', rfcSlug)
|
||||
if (beforeId != null) params.set('before_id', beforeId)
|
||||
if (limit != null) params.set('limit', limit)
|
||||
const qs = params.toString()
|
||||
return jsonOrThrow(await fetch(`/api/admin/audit${qs ? `?${qs}` : ''}`))
|
||||
}
|
||||
|
||||
export async function listPermissionEvents({ beforeId, limit } = {}) {
|
||||
const params = new URLSearchParams()
|
||||
if (beforeId != null) params.set('before_id', beforeId)
|
||||
if (limit != null) params.set('limit', limit)
|
||||
const qs = params.toString()
|
||||
return jsonOrThrow(await fetch(`/api/admin/permission-events${qs ? `?${qs}` : ''}`))
|
||||
}
|
||||
|
||||
export async function listGraduationQueue() {
|
||||
return jsonOrThrow(await fetch('/api/admin/graduation-queue'))
|
||||
}
|
||||
|
||||
export async function searchUsers(q) {
|
||||
const params = new URLSearchParams()
|
||||
if (q) params.set('q', q)
|
||||
return jsonOrThrow(await fetch(`/api/users/search?${params}`))
|
||||
}
|
||||
|
||||
// SSE subscription helper. Returns a close() function. The handler
|
||||
// surface mirrors §15.3: a snapshot event on open, then per-notification
|
||||
// `notification` events, plus `read` events when another tab marks a row.
|
||||
|
||||
Reference in New Issue
Block a user