Skip to content

Commit af6b893

Browse files
committed
Add localStorage persistence and UI tweaks
Persist session state to localStorage and add related UI/UX improvements. Saves firewall text, device list, graph layout/filter, and selected test path (stored as device indexes) under a STORAGE_KEY; includes guards for unavailable localStorage and normalization helpers for saved data. Introduces reactive controls (debounced textarea input, selector change handlers), a test-path persistence flow, and functions to read/write/normalise stored state. Adds a footer with repository link and dynamic current year, minor copy edits (OpenWRT → OpenWrt), graph filter handler rename, and CSS for the footer. Layout selection now validates/normalises values and persists changes; handlers save state on relevant interactions.
1 parent d2be2ad commit af6b893

2 files changed

Lines changed: 335 additions & 53 deletions

File tree

ARCHITECTURE.md

Lines changed: 35 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ The OpenWrt Firewall Relationship Visualiser is a single-page browser applicatio
77
The application is intentionally local-first:
88

99
- Firewall text is parsed in the browser.
10-
- Device mappings are held in browser memory for the current session.
10+
- Firewall text, device mappings, graph preferences, and the selected test path are saved in `localStorage` when available.
1111
- No backend, database, build step, or package manager is required.
1212
- The only runtime dependency is Cytoscape.js, loaded from a CDN for graph rendering.
1313

@@ -43,6 +43,8 @@ The app keeps a small amount of global state inside `public/index.html`:
4343
| `firewallModel` | Parsed zones, forwardings, and traffic rules |
4444
| `cy` | Current Cytoscape graph instance |
4545
| `currentLayout` | Selected graph layout name |
46+
| `selectedTestPath` | Source and destination device indexes used by the path tester |
47+
| `storageAvailable` | Guard for browsers where `localStorage` is blocked or unavailable |
4648

4749
## Data Model
4850

@@ -334,6 +336,7 @@ The example is useful for demonstrating the relationship views, but it should no
334336
## Security Considerations
335337

336338
- Firewall text and device mappings stay in the browser.
339+
- Saved sessions use browser `localStorage`; they are not sent to a server.
337340
- Local file loading uses the browser `FileReader` API.
338341
- User-controlled strings are escaped before being inserted into rendered HTML.
339342
- The app is static and can be hosted on any static web server.
@@ -348,76 +351,69 @@ The example is useful for demonstrating the relationship views, but it should no
348351
| Simplified parser | Good for common UCI files, not a complete UCI interpreter |
349352
| Simplified decision engine | Useful for visual exploration, not a full firewall simulation |
350353
| Protocol and port fields are not evaluated | Per-service conclusions may be inaccurate |
351-
| No persistence | Device mappings and edited config are lost on page reload |
354+
| Browser-local persistence | Saved state is per browser/profile and is not portable without a future import/export feature |
352355
| CDN dependency | Graph rendering depends on external script availability |
353356
| No automated tests | Behaviour is currently verified manually |
354357

355358
## Roadmap
356359

357360
### Phase A: Persistence
358361

359-
Add browser persistence with `localStorage`.
362+
Status: implemented.
360363

361-
Store:
364+
The app saves session state to `localStorage` after parsing, device changes, graph layout/filter changes, and path-test selection changes.
365+
366+
Stored fields:
362367

363368
- Firewall config text.
364369
- Device list.
365370
- Selected graph layout.
366371
- Selected graph filter.
367-
- Last tested source and destination device.
372+
- Last tested source and destination device indexes.
368373

369-
Implementation notes:
374+
Relevant functions:
370375

371-
- Add `saveToLocalStorage()`.
372-
- Add `loadFromLocalStorage()`.
373-
- Save after parsing and after device changes.
374-
- Load before the initial render in `main()`.
376+
- `saveToLocalStorage()`.
377+
- `loadFromLocalStorage()`.
378+
- `readStoredState()`.
379+
- `normaliseSavedDevices()`.
380+
- `normaliseSavedTestPath()`.
375381

376382
### Phase B: Reactive Updates
377383

378-
Reduce explicit button clicks by making the page respond to input changes.
384+
Status: implemented.
379385

380-
Implementation notes:
386+
The app now responds to input changes while keeping the explicit buttons as manual controls.
381387

382-
- Add a debounced `input` handler for the firewall textarea.
383-
- Keep the manual "Parse Firewall" button as an explicit recovery path for large configs.
384-
- Re-test the selected device path when either selector changes.
385-
- Batch expensive graph renders behind the debounce.
388+
Implemented behaviour:
386389

387-
Example pattern:
390+
- The firewall textarea has a debounced `input` handler.
391+
- The "Parse Firewall" button remains available.
392+
- The selected device path re-tests when either selector changes.
393+
- Parse/render changes are persisted automatically when `localStorage` is available.
388394

389-
```javascript
390-
function debounce(fn, delay) {
391-
let timeoutId = null;
392-
393-
return function debounced(...args) {
394-
window.clearTimeout(timeoutId);
395-
timeoutId = window.setTimeout(() => fn.apply(this, args), delay);
396-
};
397-
}
395+
Relevant functions:
398396

399-
const autoParse = debounce(() => {
400-
parseAndRender();
401-
saveToLocalStorage();
402-
}, 500);
403-
```
397+
- `debounce()`.
398+
- `autoParse`.
399+
- `bindReactiveControls()`.
400+
- `handleTestSelectorChange()`.
401+
- `renderCurrentTestResult()`.
404402

405403
### Phase C: Project Metadata
406404

407-
Add a small footer with repository and version metadata.
405+
Status: implemented.
408406

409-
Include:
407+
The page footer shows:
410408

411409
- GitHub repository link.
412410
- Current year from `new Date().getFullYear()`.
413-
- Optional static version or build date.
414411

415-
Implementation notes:
412+
Relevant functions and elements:
416413

417-
- Add footer markup before `</body>`.
418-
- Add footer styling to the inline stylesheet.
419-
- Add `setCurrentYear()` and call it from `main()`.
420-
- Use the real repository URL rather than a placeholder.
414+
- `.site-footer`.
415+
- `#currentYear`.
416+
- `setCurrentYear()`.
421417

422418
### Phase D: Rule Engine Accuracy
423419

0 commit comments

Comments
 (0)