Control 보안 정책 설정 확장

This commit is contained in:
seo
2026-06-26 03:14:09 +09:00
parent 772984d9f0
commit 7a9d4af9ad
5 changed files with 380 additions and 179 deletions
+72 -12
View File
@@ -616,6 +616,54 @@
if (!byGroup[group]) byGroup[group] = [];
byGroup[group].push(item);
});
const fieldHtml = item => {
const key = escapeHtml(item.key);
const value = item.value ?? item.default ?? '';
const type = item.type || 'number';
if (type === 'boolean') {
const checked = value === true || value === 1 || value === '1' || value === 'true';
return `
<span class="settings-toggle">
<input data-setting-key="${key}" type="checkbox" value="1" ${checked ? 'checked' : ''}>
<span>${checked ? 'ON' : 'OFF'}</span>
</span>
`;
}
if (type === 'select') {
const options = item.options || {};
return `
<select data-setting-key="${key}" class="settings-select">
${Object.entries(options).map(([optionValue, label]) => `
<option value="${escapeHtml(optionValue)}" ${String(optionValue) === String(value) ? 'selected' : ''}>${escapeHtml(label)}</option>
`).join('')}
</select>
`;
}
if (type === 'text') {
return `
<input
data-setting-key="${key}"
type="text"
maxlength="${escapeHtml(item.max_length ?? 255)}"
value="${escapeHtml(value)}">
`;
}
return `
<input
data-setting-key="${key}"
type="number"
min="${escapeHtml(item.min ?? '')}"
max="${escapeHtml(item.max ?? '')}"
step="${escapeHtml(item.step ?? '1')}"
value="${escapeHtml(value)}">
`;
};
const defaultValueText = item => {
if (item.type === 'select' && item.options && item.options[item.default]) {
return item.options[item.default];
}
return item.default ?? '';
};
els.settingsBody.innerHTML = Object.entries(byGroup).map(([group, items]) => `
<section class="settings-group">
@@ -628,20 +676,29 @@
<span>${escapeHtml(item.unit || '')}</span>
</span>
<span class="settings-control">
<input
data-setting-key="${escapeHtml(item.key)}"
type="number"
min="${escapeHtml(item.min ?? '')}"
max="${escapeHtml(item.max ?? '')}"
step="${escapeHtml(item.step ?? '1')}"
value="${escapeHtml(item.value ?? item.default ?? '')}">
<span class="settings-default">${t('settingsDefault')} ${escapeHtml(item.default ?? '')}</span>
${fieldHtml(item)}
<span class="settings-default">${t('settingsDefault')} ${escapeHtml(defaultValueText(item))}</span>
</span>
</label>
`).join('')}
</div>
</section>
`).join('');
els.settingsBody.querySelectorAll('.settings-toggle input').forEach(input => {
input.addEventListener('change', () => {
const label = input.closest('.settings-toggle')?.querySelector('span');
if (label) label.textContent = input.checked ? 'ON' : 'OFF';
});
input.closest('.settings-toggle')?.addEventListener('click', () => {
input.checked = !input.checked;
input.dispatchEvent(new Event('change'));
});
});
}
function settingByKey(key, fallback = null) {
const item = (state.settingsPayload?.items || []).find(row => row.key === key);
return item ? item.value : fallback;
}
async function openSettings() {
@@ -668,7 +725,9 @@
function currentSettingsFormValues() {
const values = {};
els.settingsBody?.querySelectorAll('[data-setting-key]').forEach(input => {
values[input.dataset.settingKey] = input.value;
values[input.dataset.settingKey] = input.type === 'checkbox'
? (input.checked ? '1' : '0')
: input.value;
});
return values;
}
@@ -1906,12 +1965,13 @@
title: t('rebootTitle'),
okText: t('next'),
danger: true,
placeholder: t('rebootPhrase'),
placeholder: String(settingByKey('security.reboot_phrase', t('rebootPhrase'))),
autocomplete: 'off',
});
if (phrase === null) return;
if (String(phrase).trim() !== t('rebootPhrase')) {
const expectedPhrase = String(settingByKey('security.reboot_phrase', t('rebootPhrase')));
if (String(phrase).trim() !== expectedPhrase) {
await window.customAlert(t('rebootPhraseMismatch'), {
title: t('rebootCanceled'),
danger: true,
@@ -1932,7 +1992,7 @@
els.rebootBtn.disabled = true;
notice(t('rebootSending'), 'info');
await api('reboot', {
phrase: '재부팅',
phrase: expectedPhrase,
password,
});
await window.customAlert(t('rebootStartedBody'), {