Files
Cyrene_v2/frontend/web/src/lib/api/messages.ts
T
AskaEth 1ac126fc9e
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
feat(web): D 消息编辑/删除前端入口 + 日志聚合前端(Observability后端tail) + 修api-client契约
- D前端: lib/api/messages.ts(patchMessage/deleteMessage,兼容裸DTO与{message}) + MessageActions.tsx(仅user消息; 单击/右键/450ms长按开Miuix玻璃菜单; 编辑弹窗预填+字数→乐观updateMessageById→patchMessage→失败回滚; 删除确认→deleteMessage→removeMessageById; 乐观气泡禁用) + chat.tsx挂载 + Icon加edit/trash/more
- 日志前端: types(AdminLogLine time:string|number) + adminSystem.adminObservabilityLogs + Observability.tsx 后端分级tail(level筛选chip注明'该级及以上'+等宽行HH:mm:ss.SSS·level着色·source·msg+30s刷新) 下半保留WS回显
- Docs/api-client §6a/§4.2 修正: PATCH /messages/{id} 实际返回 {data:<DTO>} 非 {data:{message}}(前端已双向兼容,避免误导Android)
- 前端 build 绿(167 modules); SSR冒烟11 checks
- 遗留: 未实机登录; 菜单absolute理论上边缘可裁切(可改portal)
2026-10-03 15:23:27 +08:00

37 lines
1.7 KiB
TypeScript

import type { MessageDto } from "./sessions";
import { request } from "./core";
/**
* Single-message mutations (design/16 §4.2 D3, Docs/api-client.md §6a/6b).
* Both succeed against the persisted row and broadcast the change over the WS
* hub (`message_edited` / `message_deleted`), so other clients converge without
* a re-fetch; the caller's REST response is only the acknowledgement.
*/
/** The gateway answers PATCH with `{data: <updated message DTO>}` (see
* gateway/history_write.go `writeJSON(w, 200, toHistoryMessage(msg))` and
* history_write_broadcast_test.go, which decodes `data` straight into the DTO).
* Docs/api-client.md §6a writes that envelope as `{data:{message}}`; the optional
* `message` field keeps this call working either way, so a plain DTO is never
* mistaken for an empty result (which would blank the bubble). */
type PatchMessageEnvelope = MessageDto & { message?: MessageDto };
/** PATCH /api/v1/messages/{id} — replace one message's `content`. The backend
* validates non-empty `≤4000` runes (400) and existence (404), and only ever
* changes `content`; role / timestamps / platform are preserved. */
export async function patchMessage(id: string, content: string): Promise<MessageDto> {
const res = await request<PatchMessageEnvelope>(
`/messages/${encodeURIComponent(id)}`,
{ method: "PATCH", body: JSON.stringify({ content }) }
);
return res.message ?? res;
}
/** DELETE /api/v1/messages/{id} — remove one message (404 when already gone).
* The response echoes the deleted id, so a caller can assert what it removed. */
export function deleteMessage(id: string): Promise<{ deleted: string }> {
return request<{ deleted: string }>(`/messages/${encodeURIComponent(id)}`, {
method: "DELETE",
});
}