refactor: introduce model layer for centralized data synchronization
Add hoover model.js as a central reactive store per subsystem, replacing per-component data fetching with a single source of truth. - Add hoover/model.js with modelRegister, modelFetch, and WS invalidation - Refactor websocket.js to route messages to model refresh (drop per-component subscribe/unsubscribe) - Simplify component.js by removing WS subscription management - Add refresh option to apiSubmit, deprecate refactorLoad and checkAbort - Rewrite all pages to use getModel() instead of inline data fetching - Bootstrap model registrations in app.js - Add GET /api/firewall/state endpoint - Fix restart-services.sh restart order and add service health verification - Update hoover.md docs with model layer architecture
This commit is contained in:
@@ -6,7 +6,8 @@
|
||||
* ToastContainer component for rendering queued toasts.
|
||||
*/
|
||||
|
||||
import { h } from './vdom.js?v=6';
|
||||
import { h } from './vdom.js?v=7';
|
||||
import { modelFetch } from './model.js?v=7';
|
||||
|
||||
/**
|
||||
* JSON-friendly fetch wrapper.
|
||||
@@ -100,6 +101,8 @@ export function ToastContainer() {
|
||||
/**
|
||||
* Create an abort-checking function from an AbortController.
|
||||
*
|
||||
* @deprecated Use model layer (`modelRegister` / `modelFetch`) for data
|
||||
* fetching with abort handling and loading state management.
|
||||
* @param {AbortController} ac
|
||||
* @returns {function} () => boolean
|
||||
*/
|
||||
@@ -112,6 +115,8 @@ export function checkAbort(ac) {
|
||||
*
|
||||
* Sets loading=true before, loading=false after, tracks errors.
|
||||
*
|
||||
* @deprecated Use model layer (`modelRegister` / `modelFetch`) for data
|
||||
* fetching with abort handling and loading state management.
|
||||
* @param {object} state - Reactive state object
|
||||
* @param {function} dataKey - (s) => any, current data to compare for refresh detection
|
||||
* @param {function} fetchFn - (state, signal, isAborted) => Promise
|
||||
@@ -204,7 +209,7 @@ export async function poll(opts) {
|
||||
* @param {function} [opts.body] - () => object, body builder
|
||||
* @param {function} [opts.validate] - (body) => string|null, validation function
|
||||
* @param {string} [opts.successMsg] - Success toast message
|
||||
* @param {function} [opts.reload] - () => Promise, data reload function
|
||||
* @param {string|string[]} [opts.refresh] - Model name(s) to refresh via modelFetch
|
||||
* @param {string} [opts.submitText] - Submit button text (default: 'Submit')
|
||||
* @returns {object[]} Array of action descriptors
|
||||
*/
|
||||
@@ -215,7 +220,7 @@ export function apiSubmit(opts) {
|
||||
body,
|
||||
validate,
|
||||
successMsg = 'Saved',
|
||||
reload,
|
||||
refresh,
|
||||
submitText = 'Submit',
|
||||
closeModal,
|
||||
} = opts;
|
||||
@@ -235,7 +240,10 @@ export function apiSubmit(opts) {
|
||||
if (res.ok) {
|
||||
toast(successMsg, 'success');
|
||||
if (closeModal) closeModal();
|
||||
if (reload) await reload();
|
||||
if (refresh) {
|
||||
const models = Array.isArray(refresh) ? refresh : [refresh];
|
||||
await Promise.all(models.map(m => modelFetch(m)));
|
||||
}
|
||||
} else {
|
||||
toast(res.error || 'Failed', 'error');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user