feat: prefill agent-edit modal, Ctrl+Enter submits modals, improve README
Deploy / Build (pull_request) Successful in 29s
Deploy / Test & Lint (pull_request) Successful in 32s
Deploy / Build and Push Docker Image (pull_request) Has been skipped

- AgentFormModal: sync form state to current agent values when the modal
  opens (useEffect on open/agent), so edit always shows the agent's
  current name, description, website, icon URL, and max-pending value.
- Modal: add optional onSubmit prop; Ctrl+Enter (or ⌘+Enter) fires it,
  covering AgentFormModal, DecisionModal, and both Settings modals
  (disable 2FA, delete account) without breaking textarea newlines or
  text-input behaviour.
- README: substantially expanded — purpose, capabilities, architecture,
  quick-start with Docker Compose, dev setup, testing, agent integration
  (OpenClaw, generic MCP, REST), and privacy notes.
- TODO.md: remove three completed items (prefill modal, Ctrl+Enter, human
  readme).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-19 20:39:43 +00:00
parent 4ec8ae0273
commit dfa0c55e3c
6 changed files with 204 additions and 62 deletions
+11 -1
View File
@@ -1,4 +1,4 @@
import { useState } from "react";
import { useEffect, useState } from "react";
import { toast } from "react-toastify";
import { agents as agentsApi } from "../api/client";
import type { Agent } from "../api/types";
@@ -27,6 +27,15 @@ export function AgentFormModal({
const [maxPending, setMaxPending] = useState(agent?.max_pending_requests ?? 5);
const [loading, setLoading] = useState(false);
useEffect(() => {
if (!open) return;
setName(agent?.name ?? "");
setDescription(agent?.description ?? "");
setWebsite(agent?.website ?? "");
setIconUrl(agent?.icon_url ?? "");
setMaxPending(agent?.max_pending_requests ?? 5);
}, [open, agent]);
const submit = async () => {
if (!name.trim()) return toast.error("Name is required");
setLoading(true);
@@ -55,6 +64,7 @@ export function AgentFormModal({
<Modal
open={open}
onClose={onClose}
onSubmit={submit}
title={editing ? "Edit agent" : "New agent"}
footer={
<>
+1
View File
@@ -75,6 +75,7 @@ export function DecisionModal({
<Modal
open={!!decision}
onClose={onClose}
onSubmit={submit}
title={m.title}
footer={
<>
+4 -1
View File
@@ -3,6 +3,7 @@ import { ReactNode, useEffect } from "react";
export function Modal({
open,
onClose,
onSubmit,
title,
children,
footer,
@@ -10,6 +11,7 @@ export function Modal({
}: {
open: boolean;
onClose: () => void;
onSubmit?: () => void;
title: string;
children: ReactNode;
footer?: ReactNode;
@@ -19,6 +21,7 @@ export function Modal({
if (!open) return;
const onKey = (e: KeyboardEvent) => {
if (e.key === "Escape") onClose();
if (e.key === "Enter" && (e.ctrlKey || e.metaKey) && onSubmit) onSubmit();
};
window.addEventListener("keydown", onKey);
document.body.style.overflow = "hidden";
@@ -26,7 +29,7 @@ export function Modal({
window.removeEventListener("keydown", onKey);
document.body.style.overflow = "";
};
}, [open, onClose]);
}, [open, onClose, onSubmit]);
if (!open) return null;
+2
View File
@@ -223,6 +223,7 @@ export function SettingsPage() {
<Modal
open={disable2faOpen}
onClose={() => setDisable2faOpen(false)}
onSubmit={disable2fa}
title="Disable 2FA"
footer={
<>
@@ -246,6 +247,7 @@ export function SettingsPage() {
<Modal
open={deleteOpen}
onClose={() => setDeleteOpen(false)}
onSubmit={deleteAccount}
title="Delete account"
footer={
<>