Dynamic DNS UI: fix blank columns, redesign the record list

The Host and Last-updated columns were blank because they relied on a jq-repeat
parseData hook that the rest of the app doesn't actually use for display (working
rows derive dates from the .momentFromNow class, not parseData).

- Derive fqdn server-side via DynamicRecord.toJSON so it flows through both the
  REST list and websocket payloads; the template uses {{fqdn}} directly.
- Render last-updated with the .momentFromNow class (data-date) like the rest of
  the app instead of a parseData-computed string.
- apply() now clears last_status on success so the UI only surfaces real errors.
- Redesign the section: prominent public-IP badge, cleaner add form, and a
  Bootstrap list-group of records (fqdn, IP badge, "updated N ago", inline error)
  with outline refresh/remove buttons.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-11 00:32:21 -04:00
parent a2d194f855
commit 83e9753b18
2 changed files with 65 additions and 46 deletions
+8 -1
View File
@@ -51,6 +51,12 @@ class DynamicRecord extends Table{
return (this.name === '@' || !this.name) ? this.domain : `${this.name}.${this.domain}`;
}
// Expose a derived fqdn to the client (REST list + websocket payloads both
// serialize via toJSON), so the UI doesn't depend on client-side parsing.
toJSON(){
return {...super.toJSON(), fqdn: this.fqdn()};
}
// Point this record at `ip` and record the outcome. Never throws — a single
// bad record must not abort a whole refresh cycle.
async apply(ip){
@@ -58,7 +64,8 @@ class DynamicRecord extends Table{
let Domain = require('.').models.Domain;
let domain = await Domain.get(this.domain);
let res = await domain.upsertARecord(this.name, ip);
await this.update({last_ip: ip, last_status: 'ok', last_updated: Date.now()});
// Empty status on success so the UI only surfaces actual errors.
await this.update({last_ip: ip, last_status: '', last_updated: Date.now()});
return res;
}catch(error){
console.error('DynamicRecord.apply', this.id, error.message);