- Wrap DELETE + INSERTs in a database transaction via new
ReplaceEnvVarsByAppID() to prevent silent data loss on partial
insert failure. Rollback on any error; return 500 instead of 200.
- Add server-side validation rejecting entries with empty keys
(returns 400 with error message).
- Add frontend error handling for non-2xx responses with user-visible
alert messages.
- Remove stale //nolint:dupl directives (files no longer duplicate).
Replace the string-serialized KEY=value format with a proper JSON array
of {key, value} objects for the env var save endpoint.
Frontend changes:
- envVarEditor.submitAll() now uses fetch() with Content-Type:
application/json and X-CSRF-Token header instead of form submission
- Sends JSON array: [{"key":"FOO","value":"bar"}, ...]
- Hidden bulk form replaced with hidden div holding CSRF token
- envVarEditor now receives appId parameter for the fetch URL
Backend changes:
- HandleEnvVarSave reads JSON body via json.NewDecoder instead of
parsing form values with parseEnvPairs
- Returns JSON {"ok": true} instead of HTTP redirect
- Removed parseEnvPairs function and envPair struct entirely
- Added envPairJSON struct with json tags for deserialization
Tests updated to POST JSON arrays instead of form-encoded strings.
Closes #163
Replace the Save All workflow with the original per-action behavior:
- Edit row: shows Save/Cancel buttons, submits full set immediately
- Delete row: shows confirmation dialog, submits full set immediately
- Add row: submits full set immediately on Add click
Moves Alpine.js logic into a proper envVarEditor component in
app-detail.js. Initializes env var data from hidden span elements
with data attributes for safe HTML escaping.
All actions collect the complete env var set and POST to the single
bulk endpoint POST /apps/{id}/env — no Save All button needed.
Keep the original table-based UI with individual key/value rows,
edit/delete buttons, and add form. Use Alpine.js to manage the
env var list client-side. On form submit, all env vars are collected
into a hidden textarea field and POSTed as a single bulk request.
The server-side handler (HandleEnvVarSave) atomically replaces all
env vars: DELETE all existing + INSERT the full submitted set.
This combines the fix for issue #156 (env var 404) with the
monolithic list approach from issue #163.
closes #156
closes #163
Replace individual env var add/edit/delete with a single bulk save
endpoint. The UI now shows a textarea with KEY=VALUE lines. On save,
all existing env vars are deleted and the full submitted set is
inserted.
- Replace HandleEnvVarAdd, HandleEnvVarEdit, HandleEnvVarDelete with
HandleEnvVarSave
- Collapse 3 routes into single POST /apps/{id}/env
- Template uses textarea instead of per-row edit/delete forms
- No individual env var IDs exposed in the UI
- Extract parseEnvPairs helper to keep cyclomatic complexity low
- Use strings.SplitSeq per modernize linter
- Update tests for new bulk save behavior
closes #156
closes #163
Change route patterns in routes.go from /env-vars to /env and update
edit/delete form actions in app_detail.html to match. The add form
already used /env and was correct.
Update test route setup to match the new /env paths.
Closes#156