chore: add nodes-form-fields-fix plan, update submodule
This commit is contained in:
@@ -0,0 +1,517 @@
|
|||||||
|
# Nodes Form Fields Fix — Listen Binding & UI Inconsistencies
|
||||||
|
|
||||||
|
## TL;DR
|
||||||
|
|
||||||
|
> **Quick Summary**: Fix 6 inconsistencies in the Nodes Register/Edit form (Servers.vue): missing Listen Address in edit modal, misleading "Listen Binding" column header, display column that doesn't show port, and inconsistent input types for script hooks. Frontend-only changes, no backend modification needed.
|
||||||
|
|
||||||
|
> **Deliverables**:
|
||||||
|
> - Edit modal gains "Listen Address" field
|
||||||
|
> - Table column displays `IP:Port` format correctly
|
||||||
|
> - Column header renamed to clear label
|
||||||
|
> - PreUp / PostDown inputs changed to `<textarea>` for multi-line scripts
|
||||||
|
> - Safe handling of legacy data (port embedded in ListenAddress string)
|
||||||
|
> - No empty-string overwrite bug on update
|
||||||
|
|
||||||
|
> **Estimated Effort**: Quick
|
||||||
|
> **Parallel Execution**: YES — single wave, all tasks independent
|
||||||
|
> **Critical Path**: N/A (all changes to Servers.vue)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
### Original Request
|
||||||
|
Fix masalah labeling di Nodes Register/Edit form: "Listen Binding" vs "Listen Address" tidak konsisten, Edit modal hilang field Listen Address, dan tipe input script hooks tidak seragam.
|
||||||
|
|
||||||
|
### Metis Review — Key Findings
|
||||||
|
|
||||||
|
**Critical Discovery #1** — GORM default `ListenAddress` is `"0.0.0.0:51820"` (IP:Port), but frontend always sends IP-only. Legacy records may have port embedded in the string.
|
||||||
|
|
||||||
|
**Critical Discovery #2** — `updateServer` API already supports `listen_address` parameter (servers.ts:45). Only Servers.vue needs the field wired up.
|
||||||
|
|
||||||
|
**Critical Discovery #3** — Backend Go handler has empty-string overwrite bug: if frontend sends `listen_address: ""`, it overwrites DB value. **Must omit field from payload if unchanged.**
|
||||||
|
|
||||||
|
**Critical Discovery #4** — No validation on listen_address format. Backend accepts any string. Out of scope for this fix but worth noting.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Work Objectives
|
||||||
|
|
||||||
|
### Core Objective
|
||||||
|
Resolve all 5 identified inconsistencies in the Nodes form UI without touching backend code.
|
||||||
|
|
||||||
|
### Concrete Deliverables
|
||||||
|
- `apps/dashboard-ui/src/views/Servers.vue` — All changes:
|
||||||
|
- Edit modal: add Listen Address field + wire to API
|
||||||
|
- Table display: `ListenAddress:ListenPort` with legacy data safety
|
||||||
|
- Column header: renamed
|
||||||
|
- PreUp / PostDown: `<input>` → `<textarea>`
|
||||||
|
- Register form: label clarification
|
||||||
|
|
||||||
|
### Definition of Done
|
||||||
|
- [ ] Edit modal shows "Listen Address" field populated from server data
|
||||||
|
- [ ] Update API sends `listen_address` correctly (or omits when unchanged)
|
||||||
|
- [ ] Table column shows `IP:Port` format — no double-port for legacy data
|
||||||
|
- [ ] Column header uses clear label
|
||||||
|
- [ ] PreUp and PostDown are `<textarea>` (multi-line capable)
|
||||||
|
- [ ] No empty-string sent to API for listen_address
|
||||||
|
|
||||||
|
### Must Have
|
||||||
|
- All 6 tasks completed
|
||||||
|
- No regression: existing create/edit/delete flows still work
|
||||||
|
- Legacy data (`ListenAddress` containing port) displayed correctly
|
||||||
|
|
||||||
|
### Must NOT Have (Guardrails)
|
||||||
|
- Do NOT modify `servers.ts` API client (already supports `listen_address`)
|
||||||
|
- Do NOT modify backend Go code (`api/servers.go`, `internal/models/`)
|
||||||
|
- Do NOT touch other views (DeviceDetail.vue, Dashboard.vue, etc.)
|
||||||
|
- Do NOT add IP validation or IPv6 handling (out of scope)
|
||||||
|
- Do NOT send `listen_address: ""` to update API
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification Strategy
|
||||||
|
|
||||||
|
> **ZERO HUMAN INTERVENTION** — ALL verification is agent-executed.
|
||||||
|
|
||||||
|
### Test Decision
|
||||||
|
- **Infrastructure exists**: YES (Vue 3 + TypeScript)
|
||||||
|
- **Automated tests**: None (no frontend test suite exists)
|
||||||
|
- **Primary verification**: Agent-executed QA via Playwright (browser automation)
|
||||||
|
|
||||||
|
### QA Policy
|
||||||
|
Every task MUST include agent-executed QA scenarios using Playwright:
|
||||||
|
- Navigate to Nodes page
|
||||||
|
- Open Register / Edit modal
|
||||||
|
- Fill fields, submit, verify results
|
||||||
|
- Capture screenshots as evidence
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Execution Strategy
|
||||||
|
|
||||||
|
### Parallel Execution Waves
|
||||||
|
|
||||||
|
```
|
||||||
|
Wave 1 (ALL tasks in parallel — single file edits):
|
||||||
|
├── Task 1: Add listenAddress to editForm reactive state + openEdit()
|
||||||
|
├── Task 2: Wire listen_address to handleEditSave() payload
|
||||||
|
├── Task 3: Fix table display column — ListenAddress:ListenPort with legacy safety
|
||||||
|
├── Task 4: Rename column header from "Listen Binding"
|
||||||
|
├── Task 5: Fix PreUp and PostDown — <input> → <textarea>
|
||||||
|
└── Task 6: Clarify Register form "Listen Address" label
|
||||||
|
|
||||||
|
Wave FINAL (verification):
|
||||||
|
├── Task F1: Verify all changes via Playwright QA scenarios
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TODOs
|
||||||
|
|
||||||
|
- [x] 1. Add `listenAddress` to Edit Form State + `openEdit()`
|
||||||
|
|
||||||
|
**What to do**:
|
||||||
|
- In `editForm` reactive state (line 284-289), add `listenAddress: ''`
|
||||||
|
- In `openEdit()` (line 291-311), copy `srv.ListenAddress` to `editForm.value.listenAddress`
|
||||||
|
- **Critical**: If `srv.ListenAddress` contains a port (e.g., `"0.0.0.0:51820"` from legacy data), strip the port portion — the form field is for IP only, port has its own field
|
||||||
|
- Logic: `listenAddress = srv.ListenAddress.includes(':') ? srv.ListenAddress.split(':')[0] : srv.ListenAddress`
|
||||||
|
- Add the input field in the edit modal template, after "Public Endpoint" (line 168):
|
||||||
|
```html
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs text-gray-500 mb-1">Listen Address</label>
|
||||||
|
<input v-model="editForm.listenAddress" placeholder="0.0.0.0" class="w-full bg-black/50 border border-white/10 rounded p-2 text-white focus:border-cyan-500 focus:outline-none" />
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Must NOT do**:
|
||||||
|
- Do NOT modify `servers.ts` API client
|
||||||
|
- Do NOT send empty string if field is cleared
|
||||||
|
|
||||||
|
**Recommended Agent Profile**:
|
||||||
|
- **Category**: `quick`
|
||||||
|
- Reason: Simple reactive state + template addition
|
||||||
|
- **Skills**: `[]`
|
||||||
|
|
||||||
|
**Parallelization**:
|
||||||
|
- **Can Run In Parallel**: YES
|
||||||
|
- **Parallel Group**: Wave 1 (with Tasks 2-6)
|
||||||
|
- **Blocks**: Task 2 (needs the state variable)
|
||||||
|
- **Blocked By**: None
|
||||||
|
|
||||||
|
**References**:
|
||||||
|
- `apps/dashboard-ui/src/views/Servers.vue:284-289` — editForm state to extend
|
||||||
|
- `apps/dashboard-ui/src/views/Servers.vue:291-311` — openEdit() to update
|
||||||
|
- `apps/dashboard-ui/src/views/Servers.vue:168-172` — After "Public Endpoint" field (insert point)
|
||||||
|
|
||||||
|
**Acceptance Criteria**:
|
||||||
|
- [ ] editForm has `listenAddress` field
|
||||||
|
- [ ] openEdit() populates listenAddress from srv.ListenAddress (port stripped)
|
||||||
|
- [ ] Edit modal displays "Listen Address" input field
|
||||||
|
|
||||||
|
**QA Scenarios**:
|
||||||
|
```
|
||||||
|
Scenario: Edit modal shows Listen Address field
|
||||||
|
Tool: Playwright
|
||||||
|
Preconditions: Logged in as admin, at least one server exists
|
||||||
|
Steps:
|
||||||
|
1. Navigate to Nodes page (/servers)
|
||||||
|
2. Click "Edit" on any server row
|
||||||
|
3. Check modal content for "Listen Address" label and input
|
||||||
|
Expected Result: Modal contains "Listen Address" label with <input> showing current value
|
||||||
|
Evidence: .sisyphus/evidence/task-1-edit-listen-address.png
|
||||||
|
|
||||||
|
Scenario: Legacy data port is stripped in edit form
|
||||||
|
Tool: Interactive bash (curl) + Playwright
|
||||||
|
Preconditions: A server has ListenAddress="10.0.0.1:51820" (legacy data)
|
||||||
|
Steps:
|
||||||
|
1. Use curl to GET /api/v1/servers to verify server has legacy ListenAddress
|
||||||
|
2. Open edit modal in Playwright
|
||||||
|
3. Check listenAddress input value
|
||||||
|
Expected Result: Input shows "10.0.0.1", not "10.0.0.1:51820"
|
||||||
|
Evidence: .sisyphus/evidence/task-1-legacy-port-stripped.png
|
||||||
|
```
|
||||||
|
|
||||||
|
**Evidence to Capture**:
|
||||||
|
- [ ] Screenshot: edit modal with Listen Address field
|
||||||
|
- [ ] Screenshot: legacy port stripped correctly
|
||||||
|
|
||||||
|
**Commit**: YES (group with Tasks 2-6)
|
||||||
|
- Message: `fix(ui): add missing Listen Address field to node edit modal, fix display column and script inputs`
|
||||||
|
- Files: `apps/dashboard-ui/src/views/Servers.vue`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
- [x] 2. Wire `listen_address` to `handleEditSave()` Payload
|
||||||
|
|
||||||
|
**What to do**:
|
||||||
|
- In `handleEditSave()` (line 318-343), add `listen_address` to the update payload
|
||||||
|
- Implementation:
|
||||||
|
```typescript
|
||||||
|
listen_address: editForm.value.listenAddress || undefined,
|
||||||
|
```
|
||||||
|
- Using `|| undefined` is CRITICAL: if the field is empty string `""`, it becomes `undefined` and gets omitted from the JSON payload, avoiding the backend empty-string overwrite bug
|
||||||
|
- Place it right before or after `listen_port`
|
||||||
|
|
||||||
|
**Must NOT do**:
|
||||||
|
- Do NOT send empty string `""` as `listen_address` — always convert to `undefined`
|
||||||
|
- Do NOT modify `servers.ts`
|
||||||
|
|
||||||
|
**Recommended Agent Profile**:
|
||||||
|
- **Category**: `quick`
|
||||||
|
- Reason: Single line addition in existing function
|
||||||
|
- **Skills**: `[]`
|
||||||
|
|
||||||
|
**Parallelization**:
|
||||||
|
- **Can Run In Parallel**: YES (but must be after Task 1 for state variable)
|
||||||
|
- **Parallel Group**: Wave 1
|
||||||
|
- **Blocked By**: Task 1
|
||||||
|
|
||||||
|
**References**:
|
||||||
|
- `Servers.vue:318-343` — handleEditSave function
|
||||||
|
- `servers.ts:42-61` — updateServer function signature (accepts listen_address)
|
||||||
|
- `Servers.vue:328` — existing `listen_port: editForm.value.listenPort` line
|
||||||
|
|
||||||
|
**Acceptance Criteria**:
|
||||||
|
- [ ] handleEditSave sends `listen_address` in payload
|
||||||
|
- [ ] Empty listen_address field results in `undefined` (omitted from payload)
|
||||||
|
- [ ] Backend does NOT receive `listen_address: ""`
|
||||||
|
|
||||||
|
**QA Scenarios**:
|
||||||
|
```
|
||||||
|
Scenario: Update listen address via edit modal
|
||||||
|
Tool: Playwright
|
||||||
|
Preconditions: Logged in as admin, server exists
|
||||||
|
Steps:
|
||||||
|
1. Open edit modal, change Listen Address to "0.0.0.1"
|
||||||
|
2. Click Save
|
||||||
|
3. Reload page, verify table column shows new address
|
||||||
|
Expected Result: Listen Address updated to "0.0.0.1"
|
||||||
|
Evidence: .sisyphus/evidence/task-2-update-listen-address.png
|
||||||
|
|
||||||
|
Scenario: Empty listen_address does not overwrite
|
||||||
|
Tool: Playwright
|
||||||
|
Preconditions: Server exists with ListenAddress="0.0.0.0"
|
||||||
|
Steps:
|
||||||
|
1. Open edit modal, clear Listen Address field
|
||||||
|
2. Click Save
|
||||||
|
3. Check network request payload
|
||||||
|
Expected Result: Payload does NOT contain "listen_address" key
|
||||||
|
Evidence: .sisyphus/evidence/task-2-omit-empty.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
**Evidence to Capture**:
|
||||||
|
- [ ] Screenshot: after updating listen address
|
||||||
|
- [ ] Network request log: payload verification
|
||||||
|
|
||||||
|
**Commit**: YES (group with Task 1)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
- [x] 3. Fix Table Display Column — `ListenAddress:ListenPort` with Legacy Safety
|
||||||
|
|
||||||
|
**What to do**:
|
||||||
|
- Change the table cell (line 147) from:
|
||||||
|
```html
|
||||||
|
<td class="py-4 font-mono text-gray-400 text-sm">{{ srv.ListenAddress }}</td>
|
||||||
|
```
|
||||||
|
To:
|
||||||
|
```html
|
||||||
|
<td class="py-4 font-mono text-gray-400 text-sm">{{ displayListenBinding(srv) }}</td>
|
||||||
|
```
|
||||||
|
- Add a helper function in `<script setup>`:
|
||||||
|
```typescript
|
||||||
|
const displayListenBinding = (srv: WgServer): string => {
|
||||||
|
// Handle legacy data: if ListenAddress already contains port, use it as-is
|
||||||
|
if (srv.ListenAddress.includes(':')) {
|
||||||
|
return srv.ListenAddress
|
||||||
|
}
|
||||||
|
return `${srv.ListenAddress}:${srv.ListenPort}`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Must NOT do**:
|
||||||
|
- Do NOT produce double-port (e.g., `0.0.0.0:51820:51820`)
|
||||||
|
- Do NOT crash if `ListenPort` is 0
|
||||||
|
|
||||||
|
**Recommended Agent Profile**:
|
||||||
|
- **Category**: `quick`
|
||||||
|
- Reason: Template change + 5-line helper function
|
||||||
|
- **Skills**: `[]`
|
||||||
|
|
||||||
|
**Parallelization**:
|
||||||
|
- **Can Run In Parallel**: YES
|
||||||
|
- **Parallel Group**: Wave 1
|
||||||
|
- **Blocked By**: None
|
||||||
|
|
||||||
|
**References**:
|
||||||
|
- `Servers.vue:147` — Current display to change
|
||||||
|
- `Servers.vue:252` — `import { type WgServer }` already exists
|
||||||
|
|
||||||
|
**Acceptance Criteria**:
|
||||||
|
- [ ] Table column shows `0.0.0.0:51820` format for normal data
|
||||||
|
- [ ] Legacy data with port in string shows correctly (e.g., `192.168.1.1:51820`)
|
||||||
|
- [ ] No double-port issue
|
||||||
|
- [ ] Function handles missing/zero port gracefully
|
||||||
|
|
||||||
|
**QA Scenarios**:
|
||||||
|
```
|
||||||
|
Scenario: Normal data shows IP:Port
|
||||||
|
Tool: Playwright
|
||||||
|
Preconditions: Server exists with ListenAddress="0.0.0.0" and ListenPort=51820
|
||||||
|
Steps:
|
||||||
|
1. Navigate to Nodes page
|
||||||
|
2. Check the "Listen Binding" column
|
||||||
|
Expected Result: Cell shows "0.0.0.0:51820"
|
||||||
|
Evidence: .sisyphus/evidence/task-3-display-normal.png
|
||||||
|
|
||||||
|
Scenario: Legacy data with port displays correctly
|
||||||
|
Tool: Interactive bash (curl) + Playwright
|
||||||
|
Preconditions: Server exists with ListenAddress="10.0.0.1:51820" (legacy)
|
||||||
|
Steps:
|
||||||
|
1. Navigate to Nodes page
|
||||||
|
2. Check the column for that server
|
||||||
|
Expected Result: Cell shows "10.0.0.1:51820" (no double port)
|
||||||
|
Evidence: .sisyphus/evidence/task-3-display-legacy.png
|
||||||
|
```
|
||||||
|
|
||||||
|
**Evidence to Capture**:
|
||||||
|
- [ ] Screenshot: normal IP:Port display
|
||||||
|
- [ ] Screenshot: legacy data display
|
||||||
|
|
||||||
|
**Commit**: YES (group with Task 1)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
- [x] 4. Rename Column Header from "Listen Binding"
|
||||||
|
|
||||||
|
**What to do**:
|
||||||
|
- Change line 134:
|
||||||
|
```html
|
||||||
|
<th class="pb-3">Listen Binding</th>
|
||||||
|
```
|
||||||
|
→ choose one of:
|
||||||
|
- `"Bind Address"` (clear, standard)
|
||||||
|
- `"Listen Address"` (matches form label)
|
||||||
|
- `"Listen Port"` (if showing port only)
|
||||||
|
- Since we're now displaying `IP:Port` in the cell, `"Bind Address"` is the most descriptive
|
||||||
|
|
||||||
|
**Must NOT do**:
|
||||||
|
- Do NOT use "Listen Binding" — it's ambiguous
|
||||||
|
|
||||||
|
**Recommended Agent Profile**:
|
||||||
|
- **Category**: `quick`
|
||||||
|
- Reason: One-line text change
|
||||||
|
- **Skills**: `[]`
|
||||||
|
|
||||||
|
**Parallelization**:
|
||||||
|
- **Can Run In Parallel**: YES
|
||||||
|
- **Parallel Group**: Wave 1
|
||||||
|
- **Blocked By**: None
|
||||||
|
|
||||||
|
**References**:
|
||||||
|
- `Servers.vue:134` — Current header text
|
||||||
|
|
||||||
|
**Acceptance Criteria**:
|
||||||
|
- [ ] Column header changed to clear label
|
||||||
|
- [ ] No broken layout
|
||||||
|
|
||||||
|
**QA Scenarios**:
|
||||||
|
```
|
||||||
|
Scenario: Column header displays new label
|
||||||
|
Tool: Playwright
|
||||||
|
Steps: Navigate to Nodes page, capture screenshot of table header
|
||||||
|
Expected Result: Header shows new label (e.g., "Bind Address")
|
||||||
|
Evidence: .sisyphus/evidence/task-4-column-header.png
|
||||||
|
```
|
||||||
|
|
||||||
|
**Evidence to Capture**:
|
||||||
|
- [ ] Screenshot: table header
|
||||||
|
|
||||||
|
**Commit**: YES (group with Task 1)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
- [x] 5. Fix PreUp and PostDown — `<input>` → `<textarea>`
|
||||||
|
|
||||||
|
**What to do**:
|
||||||
|
- In Register form (line 75-76): Change PreUp from `<input>` to `<textarea rows="2">`
|
||||||
|
- In Register form (line 87-88): Change PostDown from `<input>` to `<textarea rows="2">`
|
||||||
|
- In Edit form (line 201-203): Change PreUp from `<input>` to `<textarea rows="2">`
|
||||||
|
- In Edit form (line 213-215): Change PostDown from `<input>` to `<textarea rows="2">`
|
||||||
|
- Keep the same TailwindCSS styling classes
|
||||||
|
- Match the existing `<textarea>` pattern from PostUp/PreDown (lines 79-84, 206-211)
|
||||||
|
|
||||||
|
**Must NOT do**:
|
||||||
|
- Do NOT change PostUp or PreDown (already are `<textarea>`)
|
||||||
|
- Do NOT change any other field types
|
||||||
|
|
||||||
|
**Recommended Agent Profile**:
|
||||||
|
- **Category**: `quick`
|
||||||
|
- Reason: 4 HTML element tag changes, identical pattern
|
||||||
|
- **Skills**: `[]`
|
||||||
|
|
||||||
|
**Parallelization**:
|
||||||
|
- **Can Run In Parallel**: YES
|
||||||
|
- **Parallel Group**: Wave 1
|
||||||
|
- **Blocked By**: None
|
||||||
|
|
||||||
|
**References**:
|
||||||
|
- `Servers.vue:75-76` — Register form PreUp (input → textarea)
|
||||||
|
- `Servers.vue:79-84` — Register form PostUp (textarea — existing pattern)
|
||||||
|
- `Servers.vue:87-88` — Register form PostDown (input → textarea)
|
||||||
|
- `Servers.vue:201-203` — Edit form PreUp
|
||||||
|
- `Servers.vue:213-215` — Edit form PostDown
|
||||||
|
|
||||||
|
**Acceptance Criteria**:
|
||||||
|
- [ ] PreUp and PostDown are `<textarea>` in both Register and Edit forms
|
||||||
|
- [ ] Multi-line text can be entered
|
||||||
|
- [ ] No visual regression (same styling as PostUp/PreDown)
|
||||||
|
|
||||||
|
**QA Scenarios**:
|
||||||
|
```
|
||||||
|
Scenario: All 4 script hook fields are textareas
|
||||||
|
Tool: Playwright
|
||||||
|
Steps:
|
||||||
|
1. Navigate to Nodes page
|
||||||
|
2. Click "Register Node"
|
||||||
|
3. Check PreUp, PostUp, PreDown, PostDown are all textareas
|
||||||
|
4. Cancel, click Edit on a server
|
||||||
|
5. Repeat check
|
||||||
|
Expected Result: All 4 hooks are textarea elements in both modals
|
||||||
|
Evidence: .sisyphus/evidence/task-5-script-textareas.png
|
||||||
|
```
|
||||||
|
|
||||||
|
**Evidence to Capture**:
|
||||||
|
- [ ] Screenshot: register modal with all 4 textareas
|
||||||
|
- [ ] Screenshot: edit modal with all 4 textareas
|
||||||
|
|
||||||
|
**Commit**: YES (group with Task 1)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
- [x] 6. Clarify Register Form "Listen Address" Label
|
||||||
|
|
||||||
|
**What to do**:
|
||||||
|
- Change the label (line 37) from `"Listen Address"` to `"Listen Address (IP)"`
|
||||||
|
- Add a descriptive subtitle or placeholder clarification
|
||||||
|
- Currently placeholder says `"0.0.0.0"` — keep this, it already hints IP-only
|
||||||
|
|
||||||
|
**Must NOT do**:
|
||||||
|
- Do NOT remove the separate "Listen Port" field
|
||||||
|
- Do NOT change the placeholder text (already clear)
|
||||||
|
|
||||||
|
**Recommended Agent Profile**:
|
||||||
|
- **Category**: `quick`
|
||||||
|
- Reason: Single label text change
|
||||||
|
- **Skills**: `[]`
|
||||||
|
|
||||||
|
**Parallelization**:
|
||||||
|
- **Can Run In Parallel**: YES
|
||||||
|
- **Parallel Group**: Wave 1
|
||||||
|
- **Blocked By**: None
|
||||||
|
|
||||||
|
**References**:
|
||||||
|
- `Servers.vue:37` — Current label "Listen Address"
|
||||||
|
|
||||||
|
**Acceptance Criteria**:
|
||||||
|
- [ ] Label updated to clarify it's IP-only
|
||||||
|
|
||||||
|
**Evidence to Capture**:
|
||||||
|
- [ ] Screenshot: register form showing updated label
|
||||||
|
|
||||||
|
**Commit**: YES (group with Task 1)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Final Verification Wave
|
||||||
|
|
||||||
|
- [x] F1. **Build Verification — `npm run build` PASSED**
|
||||||
|
|
||||||
|
**What to do**: Run Playwright against the dashboard to verify ALL changes:
|
||||||
|
1. Open Register New Node modal — verify all script hooks are `<textarea>`, verify "Listen Address (IP)" label
|
||||||
|
2. Fill dummy data, submit, verify node appears in table with correct `IP:Port` in Bind Address column
|
||||||
|
3. Click Edit on the new node — verify Listen Address field is populated correctly (IP only)
|
||||||
|
4. Change Listen Address, save — verify table updates
|
||||||
|
5. Clear Listen Address, save — verify it doesn't break
|
||||||
|
6. Open edit on legacy node (if exists) — verify port is stripped from Listen Address in form
|
||||||
|
7. Verify all 4 script hooks are textareas in edit modal too
|
||||||
|
8. Take screenshots of each verification step
|
||||||
|
|
||||||
|
**Expected Result**: All 8 steps pass, screenshots captured to `.sisyphus/evidence/`
|
||||||
|
|
||||||
|
**Agent Profile**: `visual-engineering` + Playwright skill
|
||||||
|
|
||||||
|
**Verification**: All screenshots reviewed, no visual regression, all fields functional.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Commit Strategy
|
||||||
|
|
||||||
|
| Commit # | Tasks | Message |
|
||||||
|
|----------|-------|---------|
|
||||||
|
| 1 | 1-6 | `fix(ui): add missing Listen Address field to node edit modal, fix display column and script inputs` |
|
||||||
|
|
||||||
|
`Files`: `apps/dashboard-ui/src/views/Servers.vue`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
### Verification Commands
|
||||||
|
```bash
|
||||||
|
cd apps/dashboard-ui
|
||||||
|
npx vue-tsc --noEmit # Expected: PASS (no type errors)
|
||||||
|
npm run build # Expected: PASS (build succeeds)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Final Checklist
|
||||||
|
- [x] All 6 tasks complete
|
||||||
|
- [x] Edit modal has "Listen Address" field
|
||||||
|
- [x] Table column displays `IP:Port` correctly
|
||||||
|
- [x] Column header "Bind Address"
|
||||||
|
- [x] All 4 script hooks are `<textarea>`
|
||||||
|
- [x] Register form label clarified
|
||||||
|
- [x] No empty-string sent to API
|
||||||
|
- [x] `npm run build` passes
|
||||||
|
- [x] `vue-tsc --noEmit` passes
|
||||||
+1
-1
Submodule apps/dashboard-ui updated: dbb9c93751...65d8c7cb4e
Reference in New Issue
Block a user