fix: don't register pic.ngo subdomain until availability check completes
Auto-save was firing with picAvail === null (the moment the user typed a new cell name, before the 900ms availability debounce even started), which caused the backend to immediately register the subdomain on DDNS. Track the last saved/loaded cell name in loadedCellName. When domainMode is pic_ngo and the typed name differs from the loaded name, block auto-save until picAvail reaches a terminal state (available or unreachable). Also update loadedCellName on successful save so subsequent edits to the same name are not blocked. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -432,6 +432,7 @@ function Settings() {
|
|||||||
// identity
|
// identity
|
||||||
const [identity, setIdentity] = useState({ cell_name: '', domain: '', ip_range: '' });
|
const [identity, setIdentity] = useState({ cell_name: '', domain: '', ip_range: '' });
|
||||||
const [identityDirty, setIdentityDirty] = useState(false);
|
const [identityDirty, setIdentityDirty] = useState(false);
|
||||||
|
const [loadedCellName, setLoadedCellName] = useState('');
|
||||||
|
|
||||||
// DDNS
|
// DDNS
|
||||||
const [domainMode, setDomainMode] = useState('lan');
|
const [domainMode, setDomainMode] = useState('lan');
|
||||||
@@ -475,6 +476,7 @@ function Settings() {
|
|||||||
domain: cfg.domain || '',
|
domain: cfg.domain || '',
|
||||||
ip_range: cfg.ip_range || '',
|
ip_range: cfg.ip_range || '',
|
||||||
});
|
});
|
||||||
|
setLoadedCellName(cfg.cell_name || '');
|
||||||
setIdentityDirty(false);
|
setIdentityDirty(false);
|
||||||
setDomainMode(cfg.domain_mode || 'lan');
|
setDomainMode(cfg.domain_mode || 'lan');
|
||||||
setDomainName(cfg.domain_name || '');
|
setDomainName(cfg.domain_name || '');
|
||||||
@@ -545,6 +547,7 @@ function Settings() {
|
|||||||
try {
|
try {
|
||||||
const res = await cellAPI.updateConfig(identity);
|
const res = await cellAPI.updateConfig(identity);
|
||||||
setIdentityDirty(false);
|
setIdentityDirty(false);
|
||||||
|
setLoadedCellName(identity.cell_name);
|
||||||
draftConfig?.setDirty('identity', false);
|
draftConfig?.setDirty('identity', false);
|
||||||
if (res.data.warnings?.length) res.data.warnings.forEach((w) => toast(w, 'warning'));
|
if (res.data.warnings?.length) res.data.warnings.forEach((w) => toast(w, 'warning'));
|
||||||
// Refresh to get updated domain_name after DDNS registration
|
// Refresh to get updated domain_name after DDNS registration
|
||||||
@@ -687,10 +690,15 @@ function Settings() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!identityDirty) return;
|
if (!identityDirty) return;
|
||||||
if (ipRangeError || cellNameError || domainError) return;
|
if (ipRangeError || cellNameError || domainError) return;
|
||||||
if (domainMode === 'pic_ngo' && (picAvail === 'taken' || picAvail === 'checking')) return;
|
// In pic_ngo mode, if the cell name differs from what was last saved/loaded,
|
||||||
|
// wait for the availability check to reach a terminal state before saving.
|
||||||
|
// 'available' and 'unreachable' are terminal; null/'checking'/'taken' are not.
|
||||||
|
if (domainMode === 'pic_ngo' && identity.cell_name !== loadedCellName) {
|
||||||
|
if (picAvail !== 'available' && picAvail !== 'unreachable') return;
|
||||||
|
}
|
||||||
const timer = setTimeout(() => saveIdentityRef.current(), 800);
|
const timer = setTimeout(() => saveIdentityRef.current(), 800);
|
||||||
return () => clearTimeout(timer);
|
return () => clearTimeout(timer);
|
||||||
}, [identity, identityDirty, ipRangeError, cellNameError, domainError, domainMode, picAvail]); // eslint-disable-line react-hooks/exhaustive-deps
|
}, [identity, identityDirty, ipRangeError, cellNameError, domainError, domainMode, picAvail, loadedCellName]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const timers = SERVICE_DEFS
|
const timers = SERVICE_DEFS
|
||||||
|
|||||||
Reference in New Issue
Block a user