Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/palette.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,6 @@
## 2026-07-30 - Add window.confirm for destructive actions
**Learning:** Destructive actions like deleting groups and edge relationships previously occurred immediately without user confirmation.
**Action:** Always wrap delete operations with window.confirm() dialogs and ensure corresponding tests successfully mock window.confirm.
## 2025-02-15 - Enable Native Keyboard Support in Input Groups
**Learning:** Interactive UI controls for creating new resources (like projects or connections) that consist of text inputs and adjacent submit buttons can be frustrating for keyboard users if they do not submit natively upon pressing Enter. Using generic `<div>` wrappers instead of semantic forms breaks this expected behavior, hurting accessibility and general UX fluidity.
**Action:** Always wrap data submission input and button groups in a `<form>` element instead of a plain `<div>`. Set the primary action button to `type="submit"`, manage its disabled states accurately, and gracefully handle `onSubmit` by preventing the default event while executing the expected action. Remove redundant `onClick` handlers on the submit button to prevent double-execution issues. This ensures seamless integration with native browser keyboard interactions (like pressing Enter inside an input field).
23 changes: 11 additions & 12 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1080,15 +1080,15 @@ export default function App() {

<div className="field">
<label htmlFor="project-name">New project</label>
<div className="row">
<form className="row" onSubmit={(e) => { e.preventDefault(); if (projectName.trim() && !isCreatingProject) onCreateProject(); }}>
<input
id="project-name"
value={projectName}
onChange={(e) => setProjectName(e.target.value)}
/>
<button
type="button"
onClick={onCreateProject}
type="submit"

disabled={!projectName.trim() || isCreatingProject}
aria-busy={isCreatingProject}
aria-describedby={
Expand All @@ -1097,7 +1097,7 @@ export default function App() {
>
{isCreatingProject ? "Creatingโ€ฆ" : "Create"}
</button>
</div>
</form>
{createProjectHint ? (
<span id="create-project-hint" className="field-hint">
{createProjectHint}
Expand Down Expand Up @@ -1126,7 +1126,7 @@ export default function App() {
</select>
</div>

<div className="field">
<form className="field" onSubmit={(e) => { e.preventDefault(); if (selectedProjectId && connName.trim() && isDsnPresent && !isCreatingConnection) onCreateConnection(); }}>
<label htmlFor="conn-name">New connection (DSN)</label>
<input
id="conn-name"
Expand All @@ -1145,8 +1145,7 @@ export default function App() {
aria-label="Connection DSN"
/>
<button
type="button"
onClick={onCreateConnection}
type="submit"
disabled={
!selectedProjectId ||
!connName.trim() ||
Expand All @@ -1165,7 +1164,7 @@ export default function App() {
{createConnectionHint}
</span>
) : null}
</div>
</form>

<div className="field">
<label htmlFor="schema-filter">Schema filter (optional)</label>
Expand Down Expand Up @@ -1309,20 +1308,20 @@ export default function App() {
<h1 id="projects-title">ํ”„๋กœ์ ํŠธ</h1>
<p>ํ”„๋กœ์ ํŠธ๋ฅผ ์„ ํƒํ•˜๋ฉด ํ•ด๋‹น ๋‹ค์ด์–ด๊ทธ๋žจ ๋ชฉ๋ก์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.</p>
</div>
<div className="inlineCreate">
<form className="inlineCreate" onSubmit={(e) => { e.preventDefault(); if (projectName.trim() && !isCreatingProject) onCreateProject(); }}>
<input
aria-label="์ƒˆ ํ”„๋กœ์ ํŠธ ์ด๋ฆ„"
value={projectName}
onChange={(event) => setProjectName(event.currentTarget.value)}
/>
<button
type="button"
onClick={onCreateProject}
type="submit"

disabled={!projectName.trim() || isCreatingProject}
>
{isCreatingProject ? "์ƒ์„ฑ ์ค‘" : "์ƒˆ ํ”„๋กœ์ ํŠธ"}
</button>
</div>
</form>
</div>
<div className="dataTable" role="table" aria-label="ํ”„๋กœ์ ํŠธ ๋ชฉ๋ก">
<div className="dataTable__row dataTable__row--projects dataTable__row--head" role="row">
Expand Down
Loading