[UI] Prompts edit support added and form polished - #2668
Open
toreysoloio wants to merge 6 commits into
Open
Conversation
…ed it The pencil on each prompt row went to the read-only detail page — the same place the library's name beside it already opened. So it promised an edit and delivered a viewer, while `prompts.update` sat in the client reachable from nowhere in the app: a library could be created and read and then never changed. The API is real, and was checked before any of this was built rather than assumed from the client: `UpdatePromptTemplate` is declared in the proto, implemented in `grpcserver`, and writes the ConfigMap in the prompt template service. It replaces the whole `data` map rather than merging into it, so the form is seeded from a full read and says plainly that a fragment removed there is deleted — "remove this row" and "delete this fragment on save" are one act and only one of them was visible. The name and namespace address the ConfigMap, so they are shown locked; an edit cannot rename a library or move it. `PromptForm` is now the fields for both surfaces, on the division of labour the model form uses: the form owns the fields and the rules, each page owns its request and what follows. The create page is what remains of it after the extraction, and `PromptEditPage` is the other caller, at `/prompts/:namespace/:name/edit`. Sharing them is the point — two renderings of one thing drift, and the one nobody edits is the one that quietly stops offering something the API gained. The rules live in `promptDraft` beside them, where they can be read and tested without a component around them. A save sweeps every read keyed as a prompt library rather than refreshing the one it came from. The list's key carries the namespace filter, so refreshing `usePrompts()` would have refreshed the unfiltered read and left whichever filtered list is on screen showing the old key count. Two things the fixtures had wrong, both found by driving this: the mock's summary returned fragment keys in insertion order where the service sorts them, so a library edited through the app came back ordered differently from the same library read from a cluster. The detail page now sorts its fragments too, for the same reason the form does. The spec covers both ways in, the discard prompt, the save landing on the library, the list behind it being re-read, and the two refusals the controller would also make. It also covers a case worth having: a deep link to the edit address of a library that is gone says so instead of taking input for a save that cannot land. The create path is covered for the first time, since it went through the same extraction. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Torey Scheer <torey.scheer@solo.io>
The discard question only ever appeared on the form's own Cancel button. The "Back to library" link beside it, the sidebar, and the browser's back button all threw a draft away without a word — and the header link is the more obvious way to leave, so the guard was invisible in practice. A confirmation on one exit is worse than none: it teaches a reader the work is held safe and then loses it somewhere else. So the draft blocks *leaving* rather than one button. `useBlocker` catches every in-app navigation, Cancel included — which is why Cancel is now an ordinary link or callback with no question of its own, and why Discard resumes the navigation that was blocked instead of going somewhere this form picked. A `beforeunload` listener covers the exits the router cannot see: a reload, a closed tab, a typed address. Two consequences worth stating. A save navigates as part of succeeding, so the draft stops counting as unsaved before the caller navigates, or the guard would stop the save's own navigation and ask whether to discard it; a failed save marks it unsaved again, because nothing was written and the work is still on screen. And the baseline is captured at mount rather than read from the `initial` prop, so a library being written for the first time is guarded too — its baseline is the empty draft, and a typed name is something to lose. An untouched form still leaves in silence. A question over a form nobody has touched is the thing that teaches people to click through the next one. Every exit is pinned in the spec: the header link and the sidebar ask and keep the draft, Discard leaves for where the reader was heading, the create form asks once something is typed, and the save's own navigation is not questioned — the URL assertion there is what fails if it ever is. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Torey Scheer <torey.scheer@solo.io>
…t always be present)
Every other authoring form in the app asks for the name first — the MCP server form, the model form, the agent template form — and the prompt form was the one that did not, with nothing written down claiming a reason. The namespace also arrives filled in with a default and is usually left alone, so leading with it put a box to tab past in front of the empty field the reader actually came to fill. The spec gains two things. The fragment remove button is asserted to carry antd's danger class: a default button hovers towards the brand colour, which turned the one destructive control in the row purple under the pointer while every delete elsewhere went red. And the create journey no longer races itself. Filling the name immediately after dismissing the discard dialog let the state change that closes the dialog re-render the field back to its previous value, so Firefox created a library under the name the earlier step had typed. Waiting for the dialog to go and asserting the value took is the fix; nothing a reader can hit at human speed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Torey Scheer <torey.scheer@solo.io>
cjlg-soloio
approved these changes
Sep 3, 2026
cjlg-soloio
left a comment
Contributor
There was a problem hiding this comment.
didn't test but code and screenshots lgtm!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
delete disabled when only 1 empty fragment: