swarm-ui: broadcast is a composer on the messages page, not a tab of its own
The messages page gets a broadcast button that opens the agent picker and message box above the stream, so a sent message shows up in the list below it. The broadcast route and nav tab go, with no redirect: the page is now the composer, BroadcastComposer, in the messages page.
This commit is contained in:
parent
711e413901
commit
6cf89755e2
2 changed files with 63 additions and 40 deletions
|
|
@ -1,6 +1,16 @@
|
|||
/* <MessagesPage>: the filter bar over the terminal-style message list. */
|
||||
@import "@hive/shared/terminal.css";
|
||||
|
||||
/* The broadcast composer above the list, set apart from it by a rule. The
|
||||
composer's own rules are BroadcastComposer.css's. */
|
||||
.ui-messages-broadcast {
|
||||
margin-block-end: 1em;
|
||||
padding-block-end: 1em;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.ui-messages-broadcast[hidden] {
|
||||
display: none;
|
||||
}
|
||||
.ui-messages-bar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// <MessagesPage> — `/messages`: every message between agents, and from the
|
||||
// operator, reminders and compaction to an agent, as the swarm's controller
|
||||
// streams them (`GET /api/messages/stream`), across all hives.
|
||||
// streams them (`GET /api/messages/stream`), across all hives. The **broadcast**
|
||||
// button opens a composer above the list to send one message to several agents.
|
||||
//
|
||||
// The stream sends the chosen window of history first, then the live tail. A
|
||||
// message an agent drained with an in-turn `recv` is missing, because it starts
|
||||
|
|
@ -11,6 +12,8 @@ import { memo } from "preact/compat";
|
|||
import { useLayoutEffect, useRef, useState } from "preact/hooks";
|
||||
import { Badge, type BadgeTone } from "@hive/shared/badge.js";
|
||||
import { Row } from "@hive/shared/term-row.js";
|
||||
import { BroadcastComposer } from "../broadcast/BroadcastComposer.js";
|
||||
import { Button } from "../../ui/button/Button.js";
|
||||
import { Panel } from "../../ui/panel/Panel.js";
|
||||
import { SelectField } from "../../ui/select-field/SelectField.js";
|
||||
import { TextField } from "../../ui/text-field/TextField.js";
|
||||
|
|
@ -50,6 +53,7 @@ const MessageRow = memo(function MessageRow({ m }: { m: ArrivedMessage }) {
|
|||
export function MessagesPage() {
|
||||
const [sinceMinutes, setSinceMinutes] = useState(DEFAULT_WINDOW_MINUTES);
|
||||
const [query, setQuery] = useState("");
|
||||
const [composing, setComposing] = useState(false);
|
||||
const { messages, connection, reconnect } = useMessageStream(sinceMinutes);
|
||||
const shown = filterMessages(messages, query);
|
||||
|
||||
|
|
@ -79,6 +83,12 @@ export function MessagesPage() {
|
|||
icon="💬"
|
||||
actions={
|
||||
<>
|
||||
<Button
|
||||
variant={composing ? "primary" : "default"}
|
||||
onClick={() => setComposing((on) => !on)}
|
||||
>
|
||||
{composing ? "close broadcast" : "📣 broadcast"}
|
||||
</Button>
|
||||
<Badge
|
||||
tone={CONNECTION_TONE[connection]}
|
||||
value={CONNECTION_LABEL[connection]}
|
||||
|
|
@ -94,6 +104,15 @@ export function MessagesPage() {
|
|||
</>
|
||||
}
|
||||
>
|
||||
{/* Kept mounted while closed, so what was typed and picked stays and the
|
||||
agent list is already loaded when it opens. */}
|
||||
<section
|
||||
class="ui-messages-broadcast"
|
||||
aria-label="broadcast a message"
|
||||
hidden={!composing}
|
||||
>
|
||||
<BroadcastComposer />
|
||||
</section>
|
||||
<div class="ui-messages-bar">
|
||||
<SelectField
|
||||
id="messages-window"
|
||||
|
|
|
|||
Loading…
Reference in a new issue