sync: add cross-subsystem event bus for config consistency
Add EventBus with loop guards to keep firewall, dnsmasq, wireguard, and network configs consistent. Handlers emit SyncEvent after mutations; subscribers compute diffs and write JSON without manual cascade loops.
This commit is contained in:
@@ -238,7 +238,13 @@ export function apiSubmit(opts) {
|
||||
}
|
||||
const res = await apiFetch(url, { method, body: b });
|
||||
if (res.ok) {
|
||||
toast(successMsg, 'success');
|
||||
const synced = res.data?.synced;
|
||||
let msg = successMsg;
|
||||
if (synced && synced.length) {
|
||||
msg += ' (auto-synced: ' + synced.join(', ') + ')';
|
||||
synced.forEach(s => modelFetch(s));
|
||||
}
|
||||
toast(msg, 'success');
|
||||
if (closeModal) closeModal();
|
||||
if (refresh) {
|
||||
const models = Array.isArray(refresh) ? refresh : [refresh];
|
||||
|
||||
@@ -64,6 +64,9 @@ export function Card(props = {}) {
|
||||
|
||||
/**
|
||||
* A Remove button that confirms, deletes via API, toasts, and refreshes models.
|
||||
* When the response includes a ``synced`` array (list of subsystem names
|
||||
* that were auto-updated), shows a secondary toast and refreshes those
|
||||
* models.
|
||||
*
|
||||
* @param {object} props
|
||||
* @param {string} props.url - API DELETE URL
|
||||
@@ -81,7 +84,13 @@ export function ConfirmDelete(props = {}) {
|
||||
if (!confirm(props.message)) return;
|
||||
const r = await apiFetch(props.url, opts);
|
||||
if (r.ok) {
|
||||
toast(props.success || 'Removed', 'success');
|
||||
const synced = r.data?.synced;
|
||||
let msg = props.success || 'Removed';
|
||||
if (synced && synced.length) {
|
||||
msg += ' (auto-synced: ' + synced.join(', ') + ')';
|
||||
synced.forEach(s => modelFetch(s));
|
||||
}
|
||||
toast(msg, 'success');
|
||||
if (props.refresh) {
|
||||
const names = Array.isArray(props.refresh) ? props.refresh : [props.refresh];
|
||||
names.forEach(n => modelFetch(n));
|
||||
@@ -95,6 +104,9 @@ export function ConfirmDelete(props = {}) {
|
||||
/**
|
||||
* An action button that POSTs to an API endpoint, toasts on result,
|
||||
* and optionally refreshes models. Supports toggle labels for on/off buttons.
|
||||
* When the response includes a ``synced`` array (list of subsystem names
|
||||
* that were auto-updated), shows a secondary toast and refreshes those
|
||||
* models.
|
||||
*
|
||||
* @param {object} props
|
||||
* @param {string} props.url - API URL
|
||||
@@ -125,7 +137,14 @@ export function ActionButton(props = {}) {
|
||||
if (body !== undefined) opts.body = body;
|
||||
const resp = await apiFetch(props.url, opts);
|
||||
if (resp.ok) {
|
||||
if (props.successMsg) toast(props.successMsg, 'success');
|
||||
const synced = resp.data?.synced;
|
||||
let msg = props.successMsg || '';
|
||||
if (synced && synced.length) {
|
||||
if (msg) msg += ' ';
|
||||
msg += '(auto-synced: ' + synced.join(', ') + ')';
|
||||
synced.forEach(s => modelFetch(s));
|
||||
}
|
||||
if (msg) toast(msg, 'success');
|
||||
if (props.refresh) {
|
||||
const names = Array.isArray(props.refresh) ? props.refresh : [props.refresh];
|
||||
names.forEach(n => modelFetch(n));
|
||||
|
||||
Reference in New Issue
Block a user