A folder that carries something, and a way to name one
A folder was a name and nothing else -- and not even that, since PATCH could rename one and nothing in the interface ever called it. It now carries a description, a system prompt, and seeds for the model, the kind and the agent target, with a settings page behind the row. The prompt is a fourth rung on the ladder, chat > folder > model > instance, and it goes above the model deliberately: a model's prompt describes the model wherever it is used, a folder's describes this piece of work whichever model is pointed at it. It is read when a reply is built rather than copied when a chat is made, so editing it reaches the chats already there, and the walk up the parents is bounded and cycle-safe because it runs on the request path. `api/pages.py` mirrors the ladder for the settings panel and had to gain the same rung -- a panel naming the wrong source is worse than one naming none, because it is believed. The seeds fill in what the request left empty and nothing it filled in: the folder says what this work usually needs, the screen in front of somebody says what they want this time. `ssh_profile_id` is a plain string rather than a foreign key, for the reason `compacted_through_id` is, so it is validated on read. Getting *into* a folder needed fixing too. `/api/chats/start` has accepted a folder_id since folders existed and nothing ever sent one, so the only route in was to make the chat elsewhere and move it. There is a New chat here on the row now, and `?folder=` on the new-chat screen. Naming is a themed dialog, and deliberately not htmx's hx-prompt: htmx calls the browser's prompt() synchronously and only then fires htmx:prompt with the answer already in hand, so intercepting the event cannot supply a different one and the grey box appears anyway. `data-prompt` follows the data-confirm-button shape instead -- swallow the click, ask, write the answer into hx-vals, click again behind a guard. JSON.stringify rather than concatenation, or a folder called `"` produces hx-vals that does not parse and the rename silently does nothing. Driven under a DOM stub, and there is a test that no template brings hx-prompt back. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -205,6 +205,49 @@
|
||||
});
|
||||
}, true);
|
||||
|
||||
/* Asking for one line of text before a request goes out: renaming a folder,
|
||||
renaming a chat.
|
||||
|
||||
Deliberately NOT htmx's own hx-prompt. htmx calls the browser's prompt()
|
||||
synchronously and only then fires htmx:prompt with the answer already in
|
||||
hand -- so intercepting the event cannot supply a different one, and the
|
||||
native box appears regardless. Cancelling the event only aborts the
|
||||
request. This is the data-confirm-button shape instead: swallow the click,
|
||||
ask in our own dialog, write the answer where htmx will collect it, and
|
||||
click again behind a guard flag.
|
||||
|
||||
The answer goes into hx-vals as a normal field rather than into a header,
|
||||
because every route that wants it already reads a form. htmx reads
|
||||
attributes when the request is built, so setting it just before the second
|
||||
click is enough. It is JSON.stringify'd, never concatenated: a folder
|
||||
called `"` would otherwise produce hx-vals that does not parse, and the
|
||||
request would go out with the field missing rather than with the name. */
|
||||
document.addEventListener("click", function (event) {
|
||||
var el = event.target.closest("[data-prompt]");
|
||||
if (!el || el.dataset.prompted) return;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
var field = el.dataset.promptField || "name";
|
||||
prompt({
|
||||
title: el.dataset.promptTitle,
|
||||
message: el.dataset.prompt,
|
||||
value: el.dataset.promptValue || "",
|
||||
confirmLabel: el.dataset.promptLabel || "Save",
|
||||
}).then(function (value) {
|
||||
/* null is Cancel. An empty string is somebody clearing the box and
|
||||
pressing Save, which is not a rename either -- the routes ignore a
|
||||
blank name, so sending it would be a request that does nothing. */
|
||||
if (value === null || !String(value).trim()) return;
|
||||
var values = {};
|
||||
values[field] = String(value).trim();
|
||||
el.setAttribute("hx-vals", JSON.stringify(values));
|
||||
el.dataset.prompted = "1";
|
||||
el.click();
|
||||
delete el.dataset.prompted;
|
||||
});
|
||||
}, true);
|
||||
|
||||
/* Plain forms opt in with data-confirm, so they need no inline onsubmit. */
|
||||
document.addEventListener("submit", function (event) {
|
||||
var form = event.target;
|
||||
|
||||
Reference in New Issue
Block a user