fix: Cell Identity changes now show Configuration changes pending banner
Unit Tests / test (push) Successful in 7m26s
Unit Tests / test (push) Successful in 7m26s
DraftConfig dirty state (set when any Cell Identity field changes) was tracked in refs but never checked by the banner, which only looked at backend pending state. Cell name changes in pic_ngo mode intentionally block auto-save (to prevent premature DDNS re-registration), so the backend never marked pending and the banner never appeared. Fix: show the banner when hasDirty() is true in addition to backend pending. Add clearAllDirty() to DraftConfigContext so Cancel immediately clears frontend dirty state without waiting for the next 5-second poll. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+4
-3
@@ -188,7 +188,7 @@ function AppCore() {
|
|||||||
const [applyStatus, setApplyStatus] = useState(null); // null | 'saving' | 'restarting' | 'done' | 'timeout' | 'error'
|
const [applyStatus, setApplyStatus] = useState(null); // null | 'saving' | 'restarting' | 'done' | 'timeout' | 'error'
|
||||||
const [applyError, setApplyError] = useState('');
|
const [applyError, setApplyError] = useState('');
|
||||||
|
|
||||||
const { flushAll, hasDirty } = useDraftConfig();
|
const { flushAll, hasDirty, clearAllDirty } = useDraftConfig();
|
||||||
|
|
||||||
const handleApply = useCallback(async () => {
|
const handleApply = useCallback(async () => {
|
||||||
setApplyError('');
|
setApplyError('');
|
||||||
@@ -231,10 +231,11 @@ function AppCore() {
|
|||||||
}, [flushAll, hasDirty]);
|
}, [flushAll, hasDirty]);
|
||||||
|
|
||||||
const handleCancel = useCallback(async () => {
|
const handleCancel = useCallback(async () => {
|
||||||
|
clearAllDirty();
|
||||||
await cellAPI.cancelPending();
|
await cellAPI.cancelPending();
|
||||||
setPending({ needs_restart: false, changes: [] });
|
setPending({ needs_restart: false, changes: [] });
|
||||||
window.dispatchEvent(new CustomEvent('pic-config-discarded'));
|
window.dispatchEvent(new CustomEvent('pic-config-discarded'));
|
||||||
}, []);
|
}, [clearAllDirty]);
|
||||||
|
|
||||||
const [activeServiceChildren, setActiveServiceChildren] = useState([]);
|
const [activeServiceChildren, setActiveServiceChildren] = useState([]);
|
||||||
|
|
||||||
@@ -327,7 +328,7 @@ function AppCore() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isOnline && pending.needs_restart && !applyStatus && (
|
{isOnline && (pending.needs_restart || hasDirty()) && !applyStatus && (
|
||||||
<PendingRestartBanner pending={pending} onApply={handleApply} onCancel={handleCancel} />
|
<PendingRestartBanner pending={pending} onApply={handleApply} onCancel={handleCancel} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,12 @@ export function DraftConfigProvider({ children }) {
|
|||||||
await Promise.all(flushers.map(fn => fn()));
|
await Promise.all(flushers.map(fn => fn()));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const clearAllDirty = useCallback(() => {
|
||||||
|
hasDirtyRef.current = {};
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DraftConfigContext.Provider value={{ registerFlusher, setDirty, hasDirty, flushAll }}>
|
<DraftConfigContext.Provider value={{ registerFlusher, setDirty, hasDirty, flushAll, clearAllDirty }}>
|
||||||
{children}
|
{children}
|
||||||
</DraftConfigContext.Provider>
|
</DraftConfigContext.Provider>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user