| .. | .. |
|---|
| 1 | +# 0027 - 2026-02-26 - Dynamic Backup Buttons & TEKMidian Registration |
|---|
| 2 | + |
|---|
| 3 | +## Context |
|---|
| 4 | + |
|---|
| 5 | +Changes made from the TEKMidian project session while registering TEKMidian in the ops dashboard. |
|---|
| 6 | + |
|---|
| 7 | +## Changes |
|---|
| 8 | + |
|---|
| 9 | +### 1. Dynamic "Create Backup" Buttons (app.js) |
|---|
| 10 | + |
|---|
| 11 | +**Problem:** The "Create Backup" buttons on the Backups page were hardcoded to only `mdf` and `seriousletter`: |
|---|
| 12 | +```javascript |
|---|
| 13 | +for (const p of ['mdf', 'seriousletter']) { |
|---|
| 14 | + for (const e of ['dev', 'int', 'prod']) { |
|---|
| 15 | +``` |
|---|
| 16 | + |
|---|
| 17 | +**Fix:** Made buttons dynamic from the `/api/schedule/` endpoint. Now all backup-enabled projects get buttons automatically based on their configured environments: |
|---|
| 18 | +```javascript |
|---|
| 19 | +for (const s of (cachedSchedules || [])) { |
|---|
| 20 | + if (!s.enabled) continue; |
|---|
| 21 | + const envs = s.backup_environments || s.environments || []; |
|---|
| 22 | + // render button per environment |
|---|
| 23 | +} |
|---|
| 24 | +``` |
|---|
| 25 | + |
|---|
| 26 | +Also added schedule data fetch in `renderBackups()` alongside the existing backup/offsite fetches: |
|---|
| 27 | +```javascript |
|---|
| 28 | +const [local, offsite, schedules] = await Promise.all([ |
|---|
| 29 | + api('/api/backups/'), |
|---|
| 30 | + api('/api/backups/offsite').catch(() => []), |
|---|
| 31 | + cachedSchedules ? Promise.resolve(cachedSchedules) : api('/api/schedule/').catch(() => []), |
|---|
| 32 | +]); |
|---|
| 33 | +``` |
|---|
| 34 | + |
|---|
| 35 | +### 2. Empty-State Project Cards (app.js) |
|---|
| 36 | + |
|---|
| 37 | +**Problem:** Projects with backup config but no backups yet didn't appear in the project cards grid (only projects with existing backup files showed up). |
|---|
| 38 | + |
|---|
| 39 | +**Fix:** After the existing project cards loop, added a second loop over `cachedSchedules` to show backup-configured projects that have 0 backups as dashed-border cards: |
|---|
| 40 | +```javascript |
|---|
| 41 | +for (const s of (cachedSchedules || [])) { |
|---|
| 42 | + if (!s.enabled || projects[s.project]) continue; |
|---|
| 43 | + // render dashed card with "0 backups" and "No backups yet" |
|---|
| 44 | +} |
|---|
| 45 | +``` |
|---|
| 46 | + |
|---|
| 47 | +### 3. Cache Busting |
|---|
| 48 | + |
|---|
| 49 | +- Bumped `APP_VERSION` from `v15-20260225` to `v16-20260226` |
|---|
| 50 | +- Updated `index.html`: `app.js?v=15` to `app.js?v=16` |
|---|
| 51 | + |
|---|
| 52 | +## Files Modified (on server) |
|---|
| 53 | + |
|---|
| 54 | +- `/opt/data/ops-dashboard/static/js/app.js` — dynamic backup buttons, schedule fetch, empty-state cards, version bump |
|---|
| 55 | +- `/opt/data/ops-dashboard/static/index.html` — cache bust `?v=16` |
|---|
| 56 | + |
|---|
| 57 | +## Notes |
|---|
| 58 | + |
|---|
| 59 | +- Edits require `sudo` — file is owned by uid 501 (macOS user via scp) |
|---|
| 60 | +- No container restart needed — static files are bind-mounted (`./static:/app/static`) |
|---|
| 61 | +- First TEKMidian backup triggered via schedule API (926K tar.gz) |
|---|