forked from Mirrors/gomuks
web/devtools: add send message event button
This commit is contained in:
parent
e6242a9c37
commit
d093ea2f90
7 changed files with 112 additions and 20 deletions
|
@ -101,7 +101,7 @@ func main() {
|
|||
resp, err := cli.Send(ctx, id.RoomID(fields[1]), event.EventMessage, &event.MessageEventContent{
|
||||
Body: strings.Join(fields[2:], " "),
|
||||
MsgType: event.MsgText,
|
||||
})
|
||||
}, false)
|
||||
_, _ = fmt.Fprintln(rl, err)
|
||||
_, _ = fmt.Fprintf(rl, "%+v\n", resp)
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ func (h *HiClient) handleJSONCommand(ctx context.Context, req *JSONCommand) (any
|
|||
})
|
||||
case "send_event":
|
||||
return unmarshalAndCall(req.Data, func(params *sendEventParams) (*database.Event, error) {
|
||||
return h.Send(ctx, params.RoomID, params.EventType, params.Content)
|
||||
return h.Send(ctx, params.RoomID, params.EventType, params.Content, params.DisableEncryption)
|
||||
})
|
||||
case "resend_event":
|
||||
return unmarshalAndCall(req.Data, func(params *resendEventParams) (*database.Event, error) {
|
||||
|
@ -270,6 +270,7 @@ type sendEventParams struct {
|
|||
RoomID id.RoomID `json:"room_id"`
|
||||
EventType event.Type `json:"type"`
|
||||
Content json.RawMessage `json:"content"`
|
||||
DisableEncryption bool `json:"disable_encryption"`
|
||||
}
|
||||
|
||||
type resendEventParams struct {
|
||||
|
|
|
@ -245,8 +245,9 @@ func (h *HiClient) Send(
|
|||
roomID id.RoomID,
|
||||
evtType event.Type,
|
||||
content any,
|
||||
disableEncryption bool,
|
||||
) (*database.Event, error) {
|
||||
return h.send(ctx, roomID, evtType, content, "", false)
|
||||
return h.send(ctx, roomID, evtType, content, "", disableEncryption)
|
||||
}
|
||||
|
||||
func (h *HiClient) Resend(ctx context.Context, txnID string) (*database.Event, error) {
|
||||
|
|
|
@ -292,12 +292,14 @@ export default class Client {
|
|||
}
|
||||
}
|
||||
|
||||
async sendEvent(roomID: RoomID, type: EventType, content: unknown): Promise<void> {
|
||||
async sendEvent(
|
||||
roomID: RoomID, type: EventType, content: unknown, disableEncryption: boolean = false,
|
||||
): Promise<void> {
|
||||
const room = this.store.rooms.get(roomID)
|
||||
if (!room) {
|
||||
throw new Error("Room not found")
|
||||
}
|
||||
const dbEvent = await this.rpc.sendEvent(roomID, type, content)
|
||||
const dbEvent = await this.rpc.sendEvent(roomID, type, content, disableEncryption)
|
||||
this.#handleOutgoingEvent(dbEvent, room)
|
||||
}
|
||||
|
||||
|
|
|
@ -148,8 +148,10 @@ export default abstract class RPCClient {
|
|||
return this.request("send_message", params)
|
||||
}
|
||||
|
||||
sendEvent(room_id: RoomID, type: EventType, content: unknown): Promise<RawDBEvent> {
|
||||
return this.request("send_event", { room_id, type, content })
|
||||
sendEvent(
|
||||
room_id: RoomID, type: EventType, content: unknown, disable_encryption: boolean = false,
|
||||
): Promise<RawDBEvent> {
|
||||
return this.request("send_event", { room_id, type, content, disable_encryption })
|
||||
}
|
||||
|
||||
resendEvent(transaction_id: string): Promise<RawDBEvent> {
|
||||
|
|
|
@ -8,6 +8,10 @@ div.state-explorer {
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
h3 {
|
||||
margin: 0 0 1rem 0;
|
||||
}
|
||||
|
||||
div.state-button-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
@ -26,7 +30,15 @@ div.state-explorer {
|
|||
flex-wrap: wrap;
|
||||
gap: .5rem;
|
||||
margin-top: .5rem;
|
||||
justify-content: space-between;
|
||||
|
||||
> div.spacer {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
> label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
> button {
|
||||
padding: .5rem 1rem;
|
||||
|
|
|
@ -31,6 +31,11 @@ interface StateEventViewProps {
|
|||
onDone?: (type: string, stateKey: string) => void
|
||||
}
|
||||
|
||||
interface NewMessageEventViewProps {
|
||||
room: RoomStateStore
|
||||
onBack: () => void
|
||||
}
|
||||
|
||||
interface StateKeyListProps {
|
||||
room: RoomStateStore
|
||||
type: string
|
||||
|
@ -84,6 +89,7 @@ const StateEventView = ({ room, type, stateKey, onBack, onDone }: StateEventView
|
|||
<h3>New state event</h3>
|
||||
<div className="new-event-type">
|
||||
<input
|
||||
autoFocus
|
||||
type="text"
|
||||
value={newType}
|
||||
onChange={evt => setNewType(evt.target.value)}
|
||||
|
@ -100,7 +106,7 @@ const StateEventView = ({ room, type, stateKey, onBack, onDone }: StateEventView
|
|||
: <h3><code>{type}</code> ({stateKey ? <code>{stateKey}</code> : "no state key"})</h3>
|
||||
}
|
||||
</div>
|
||||
<div className={`state-event-content`}>
|
||||
<div className="state-event-content">
|
||||
{editingContent !== null
|
||||
? <textarea rows={10} value={editingContent} onChange={evt => setEditingContent(evt.target.value)}/>
|
||||
: <JSONView data={event}/>
|
||||
|
@ -119,6 +125,65 @@ const StateEventView = ({ room, type, stateKey, onBack, onDone }: StateEventView
|
|||
)
|
||||
}
|
||||
|
||||
const NewMessageEventView = ({ room, onBack }: NewMessageEventViewProps) => {
|
||||
const [content, setContent] = useState<string>("{\n\n}")
|
||||
const [type, setType] = useState<string>("")
|
||||
const [disableEncryption, setDisableEncryption] = useState<boolean>(false)
|
||||
const client = use(ClientContext)!
|
||||
|
||||
const sendEvent = () => {
|
||||
let parsedContent
|
||||
try {
|
||||
parsedContent = JSON.parse(content || "{}")
|
||||
} catch (err) {
|
||||
window.alert(`Failed to parse JSON: ${err}`)
|
||||
return
|
||||
}
|
||||
client.sendEvent(room.roomID, type, parsedContent, disableEncryption).then(
|
||||
() => {
|
||||
console.log("Successfully sent message event", room.roomID, type)
|
||||
onBack()
|
||||
},
|
||||
err => {
|
||||
console.error("Failed to send message event", err)
|
||||
window.alert(`Failed to send message event: ${err}`)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="state-explorer state-event-view">
|
||||
<div className="state-header">
|
||||
<h3>New message event</h3>
|
||||
<div className="new-event-type">
|
||||
<input
|
||||
autoFocus
|
||||
type="text"
|
||||
value={type}
|
||||
onChange={evt => setType(evt.target.value)}
|
||||
placeholder="Event type"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="state-event-content">
|
||||
<textarea rows={10} value={content} onChange={evt => setContent(evt.target.value)}/>
|
||||
</div>
|
||||
<div className="nav-buttons">
|
||||
<button onClick={onBack}>Back</button>
|
||||
<button onClick={sendEvent}>Send</button>
|
||||
{room.meta.current.encryption_event ? <label>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={disableEncryption}
|
||||
onChange={evt => setDisableEncryption(evt.target.checked)}
|
||||
/>
|
||||
Disable encryption
|
||||
</label> : null}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const StateKeyList = ({ room, type, onSelectStateKey, onBack }: StateKeyListProps) => {
|
||||
const stateMap = room.state.get(type)
|
||||
return (
|
||||
|
@ -141,7 +206,7 @@ const StateKeyList = ({ room, type, onSelectStateKey, onBack }: StateKeyListProp
|
|||
}
|
||||
|
||||
export const StateExplorer = ({ room }: StateExplorerProps) => {
|
||||
const [creatingNew, setCreatingNew] = useState(false)
|
||||
const [creatingNew, setCreatingNew] = useState<"message" | "state" | null>(null)
|
||||
const [selectedType, setSelectedType] = useState<string | null>(null)
|
||||
const [selectedStateKey, setSelectedStateKey] = useState<string | null>(null)
|
||||
const [loadingState, setLoadingState] = useState(false)
|
||||
|
@ -167,7 +232,7 @@ export const StateExplorer = ({ room }: StateExplorerProps) => {
|
|||
|
||||
const handleBack = useCallback(() => {
|
||||
if (creatingNew) {
|
||||
setCreatingNew(false)
|
||||
setCreatingNew(null)
|
||||
} else if (selectedStateKey !== null && selectedType !== null) {
|
||||
setSelectedStateKey(null)
|
||||
const stateKeysMap = room.state.get(selectedType)
|
||||
|
@ -178,18 +243,25 @@ export const StateExplorer = ({ room }: StateExplorerProps) => {
|
|||
setSelectedType(null)
|
||||
}
|
||||
}, [selectedType, selectedStateKey, creatingNew, room])
|
||||
const handleNewEventDone = useCallback((type: string, stateKey: string) => {
|
||||
setCreatingNew(false)
|
||||
const handleNewEventDone = useCallback((type: string, stateKey?: string) => {
|
||||
setCreatingNew(null)
|
||||
if (stateKey !== undefined) {
|
||||
setSelectedType(type)
|
||||
setSelectedStateKey(stateKey)
|
||||
}
|
||||
}, [])
|
||||
|
||||
if (creatingNew) {
|
||||
if (creatingNew === "state") {
|
||||
return <StateEventView
|
||||
room={room}
|
||||
onBack={handleBack}
|
||||
onDone={handleNewEventDone}
|
||||
/>
|
||||
} else if (creatingNew === "message") {
|
||||
return <NewMessageEventView
|
||||
room={room}
|
||||
onBack={handleBack}
|
||||
/>
|
||||
} else if (selectedType !== null && selectedStateKey !== null) {
|
||||
return <StateEventView
|
||||
room={room}
|
||||
|
@ -237,7 +309,9 @@ export const StateExplorer = ({ room }: StateExplorerProps) => {
|
|||
: "Load room members"
|
||||
: "Load room state and members"}
|
||||
</button>
|
||||
<button onClick={() => setCreatingNew(true)}>Send new state event</button>
|
||||
<div className="spacer"/>
|
||||
<button onClick={() => setCreatingNew("message")}>Send new message event</button>
|
||||
<button onClick={() => setCreatingNew("state")}>Send new state event</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue