<!DOCTYPE html>
<html lang="{{ t["lang"] }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ t["edit_title"] }}</title>
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<div class="header">
<h1>{{ t["nav_title"] }}</h1>
<nav>
<a href="/" class="nav-link">{{ t["nav_keys"] }}</a>
<a href="/config" class="nav-link active">{{ t["nav_config"] }}</a>
<a href="/config/raw" class="nav-link">{{ t["nav_raw_edit"] }}</a>
<a href="/backup" class="nav-link">{{ t["nav_backup_all"] }}</a>
</nav>
</div>
<div class="main" style="max-width:700px;margin:0 auto;">
<a href="/config" style="color:#1565c0;text-decoration:none;">{{ t["edit_back"] }}</a>
<h2 style="margin:16px 0;">{% if is_new %}{{ t["edit_add_title"] }}{% else %}{{ t["edit_edit_title_prefix"] }}{{ host_pattern }}{% endif %}</h2>
<form method="post" action="/config/save">
<input type="hidden" name="original_host" value="{{ host_pattern }}">
<div class="form-group">
<label for="host_pattern" class="field-label">{{ t["edit_host_pattern_label"] }}</label>
<input type="text" id="host_pattern" name="host_pattern" value="{{ host_pattern }}"
placeholder="{{ t["edit_host_pattern_placeholder"] }}" required
style="width:100%;padding:8px 12px;border:1px solid #ccc;border-radius:4px;font-size:14px;">
</div>
<h3 style="margin:20px 0 10px;">{{ t["edit_fields_heading"] }}</h3>
<div id="fields-container"></div>
<button type="button" class="btn btn-secondary" onclick="addField()" style="margin:10px 0;">
{{ t["edit_add_field"] }}
</button>
<div class="form-actions" style="margin-top:20px;">
<button type="submit" class="btn btn-primary">{{ t["edit_save"] }}</button>
<a href="/config" class="btn btn-secondary">{{ t["edit_cancel"] }}</a>
</div>
</form>
</div>
<script>
const L = {{ js_locale_json|safe }};
const fields = {{ fields_json|safe }};
const availableKeys = {{ available_keys_json|safe }};
const container = document.getElementById('fields-container');
const commonFields = [
'HostName', 'User', 'Port', 'IdentityFile', 'ProxyJump',
'ProxyCommand', 'ForwardAgent', 'ServerAliveInterval',
'StrictHostKeyChecking', 'AddKeysToAgent', 'IdentitiesOnly',
'LocalForward', 'RemoteForward', 'DynamicForward',
'Compression', 'ConnectTimeout', 'RequestTTY'
];
function addField(key, value) {
key = key || '';
value = value || '';
const row = document.createElement('div');
row.className = 'field-row';
row.style.cssText = 'display:flex;gap:8px;margin-bottom:8px;align-items:center;';
const keyInput = document.createElement('input');
keyInput.type = 'text';
keyInput.name = 'field_keys';
keyInput.value = key;
keyInput.placeholder = L.key_placeholder;
keyInput.setAttribute('list', 'field-keys-list');
keyInput.style.cssText = 'flex:1;padding:8px;border:1px solid #ccc;border-radius:4px;font-size:14px;';
keyInput.addEventListener('change', function() {
swapValueInput(row, this.value, '');
});
const valInput = createValueInput(key, value);
const removeBtn = document.createElement('button');
removeBtn.type = 'button';
removeBtn.textContent = L.remove;
removeBtn.className = 'btn btn-danger btn-sm';
removeBtn.onclick = () => row.remove();
row.appendChild(keyInput);
row.appendChild(valInput);
row.appendChild(removeBtn);
container.appendChild(row);
}
function createValueInput(key, value) {
if (key.toLowerCase() === 'identityfile' && availableKeys.length > 0) {
const sel = document.createElement('select');
sel.name = 'field_values';
sel.style.cssText = 'flex:2;padding:8px;border:1px solid #ccc;border-radius:4px;font-size:14px;';
const blank = document.createElement('option');
blank.value = '';
blank.textContent = L.select_key;
sel.appendChild(blank);
availableKeys.forEach(function(k) {
const opt = document.createElement('option');
opt.value = '~/.ssh/' + k;
opt.textContent = k;
if (value === opt.value || value === k) {
opt.selected = true;
}
sel.appendChild(opt);
});
const custom = document.createElement('option');
custom.value = '__custom__';
custom.textContent = L.custom_path;
sel.appendChild(custom);
sel.addEventListener('change', function() {
if (this.value === '__custom__') {
const inp = document.createElement('input');
inp.type = 'text';
inp.name = 'field_values';
inp.value = '';
inp.placeholder = '~/.ssh/id_xxx';
inp.style.cssText = this.style.cssText;
row_ref = this.parentNode;
row_ref.replaceChild(inp, this);
inp.focus();
}
});
return sel;
} else {
const inp = document.createElement('input');
inp.type = 'text';
inp.name = 'field_values';
inp.value = value;
inp.placeholder = L.value_placeholder;
inp.style.cssText = 'flex:2;padding:8px;border:1px solid #ccc;border-radius:4px;font-size:14px;';
return inp;
}
}
function swapValueInput(row, newKey, newValue) {
const oldVal = row.querySelector('[name="field_values"]');
if (!oldVal) return;
const newVal = createValueInput(newKey, newValue);
row.replaceChild(newVal, oldVal);
}
const datalist = document.createElement('datalist');
datalist.id = 'field-keys-list';
commonFields.forEach(f => {
const opt = document.createElement('option');
opt.value = f;
datalist.appendChild(opt);
});
document.body.appendChild(datalist);
fields.forEach(f => addField(f[0], f[1]));
if (fields.length === 0) {
addField('HostName', '');
addField('User', '');
}
</script>
</body>
</html>