fixup
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
{% extends "_shell.html" %}
|
||||
{% block title %}{% if let Some(db) = editing %}編輯連接:{{ db.name }}{% else %}新增連接{% endif %} — alterdb{% endblock %}
|
||||
{% block style %}
|
||||
<style>
|
||||
.form-card {
|
||||
padding: 1.4rem 1.6rem;
|
||||
border: 1px solid color-mix(in srgb, currentColor 20%, transparent);
|
||||
border-radius: 10px;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
.form-card h2 { margin: 0 0 1.1rem; }
|
||||
.error {
|
||||
margin: 0 0 1rem;
|
||||
padding: .5rem .75rem;
|
||||
border-radius: 6px;
|
||||
color: light-dark(#b3261e, #ffb4ab);
|
||||
background: color-mix(in srgb, currentColor 8%, transparent);
|
||||
}
|
||||
.db-form {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 1rem 1.4rem;
|
||||
}
|
||||
.db-form label {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: .35rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
.db-form input, .db-form select {
|
||||
font: inherit;
|
||||
padding: .45rem .65rem;
|
||||
border: 1px solid color-mix(in srgb, currentColor 30%, transparent);
|
||||
border-radius: 6px;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
}
|
||||
.db-form .form-actions {
|
||||
grid-column: 1 / -1;
|
||||
display: flex;
|
||||
gap: .6rem;
|
||||
}
|
||||
.db-form .form-actions button,
|
||||
.db-form .form-actions a {
|
||||
font: inherit;
|
||||
font-weight: 600;
|
||||
padding: .5rem 1.1rem;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
background: color-mix(in srgb, currentColor 12%, transparent);
|
||||
}
|
||||
.db-form .form-actions a {
|
||||
background: transparent;
|
||||
border: 1px solid color-mix(in srgb, currentColor 30%, transparent);
|
||||
}
|
||||
.db-form .form-actions button:hover,
|
||||
.db-form .form-actions a:hover { background: color-mix(in srgb, currentColor 22%, transparent); }
|
||||
.db-form .hint { font-size: .85rem; opacity: .7; font-weight: 400; }
|
||||
@media (max-width: 34rem) { .db-form { grid-template-columns: 1fr; } }
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block page %}
|
||||
<div class="form-card">
|
||||
<h2>{% if let Some(db) = editing %}編輯連接:{{ db.name }}{% else %}新增連接{% endif %}</h2>
|
||||
<p id="form-error" class="error" role="alert" hidden></p>
|
||||
<form id="db-form" class="db-form"
|
||||
data-mode="{% if editing.is_some() %}edit{% else %}create{% endif %}"
|
||||
{% if let Some(db) = editing %}data-id="{{ db.id }}"{% endif %}>
|
||||
<label>名稱
|
||||
<input name="name" required maxlength="128" autocomplete="off"
|
||||
value="{% if let Some(db) = editing %}{{ db.name }}{% endif %}">
|
||||
</label>
|
||||
<label>類型
|
||||
<select name="type">
|
||||
<option value="mysql"{% if let Some(db) = editing %}{% if db.db_type.as_str() == "mysql" %} selected{% endif %}{% endif %}>MySQL</option>
|
||||
<option value="postgres"{% if let Some(db) = editing %}{% if db.db_type.as_str() == "postgres" %} selected{% endif %}{% endif %}>PostgreSQL</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>主機
|
||||
<input name="host" required maxlength="255" autocomplete="off" placeholder="如 10.0.0.5 或 db.example.com"
|
||||
value="{% if let Some(db) = editing %}{{ db.host }}{% endif %}">
|
||||
</label>
|
||||
<label>埠
|
||||
<input name="port" type="number" min="1" max="65535" inputmode="numeric"
|
||||
value="{% if let Some(db) = editing %}{{ db.port }}{% endif %}">
|
||||
</label>
|
||||
<label>用戶名
|
||||
<input name="username" required maxlength="64" autocomplete="off"
|
||||
value="{% if let Some(db) = editing %}{{ db.username }}{% endif %}">
|
||||
</label>
|
||||
<label>密碼
|
||||
<input name="password" type="password" maxlength="128" autocomplete="new-password"
|
||||
placeholder="{% if editing.is_some() %}留空保留原密碼{% else %}可留空{% endif %}">
|
||||
</label>
|
||||
<label>資料庫名
|
||||
<input name="database_name" required maxlength="64" autocomplete="off"
|
||||
value="{% if let Some(db) = editing %}{{ db.database_name }}{% endif %}">
|
||||
</label>
|
||||
<div class="form-actions">
|
||||
<button type="submit">儲存</button>
|
||||
<a href="/databases">取消</a>
|
||||
</div>
|
||||
<p class="hint" style="grid-column: 1 / -1; margin: 0;">埠留空按類型補默認(MySQL 3306 / PostgreSQL 5432);密碼不會顯示與回填。</p>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block script %}
|
||||
<script>
|
||||
(() => {
|
||||
'use strict';
|
||||
|
||||
const TYPE_PORTS = { mysql: 3306, postgres: 5432 };
|
||||
|
||||
const form = document.getElementById('db-form');
|
||||
const formError = document.getElementById('form-error');
|
||||
const typeSelect = form.elements['type'];
|
||||
const portInput = form.elements['port'];
|
||||
const passwordInput = form.elements['password'];
|
||||
const editing = form.dataset.mode === 'edit';
|
||||
const editingId = form.dataset.id || null;
|
||||
|
||||
function updatePortHint() {
|
||||
portInput.placeholder = '留空使用默認 ' + TYPE_PORTS[typeSelect.value];
|
||||
}
|
||||
updatePortHint();
|
||||
|
||||
async function api(path, options) {
|
||||
const response = await fetch(path, options);
|
||||
if (!response.ok) {
|
||||
let message = '請求失敗(HTTP ' + response.status + ')';
|
||||
try {
|
||||
const body = await response.json();
|
||||
if (body.error) { message = body.error; }
|
||||
} catch (_) { /* 非 JSON 錯誤體,保留默認訊息 */ }
|
||||
throw new Error(message);
|
||||
}
|
||||
return response.status === 204 ? null : response.json();
|
||||
}
|
||||
|
||||
form.addEventListener('submit', async (event) => {
|
||||
event.preventDefault();
|
||||
formError.hidden = true;
|
||||
|
||||
const payload = {
|
||||
name: form.elements['name'].value.trim(),
|
||||
type: typeSelect.value,
|
||||
host: form.elements['host'].value.trim(),
|
||||
username: form.elements['username'].value.trim(),
|
||||
database_name: form.elements['database_name'].value.trim(),
|
||||
};
|
||||
const port = portInput.value.trim();
|
||||
if (port !== '') { payload.port = Number(port); }
|
||||
// 密碼留空時省略該鍵:新增視為空密碼(後端默認)、編輯保留原值
|
||||
if (passwordInput.value !== '') { payload.password = passwordInput.value; }
|
||||
|
||||
const url = editing ? '/api/databases/' + editingId : '/api/databases';
|
||||
try {
|
||||
await api(url, {
|
||||
method: editing ? 'PUT' : 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
window.location.assign('/databases');
|
||||
} catch (err) {
|
||||
formError.textContent = err.message;
|
||||
formError.hidden = false;
|
||||
}
|
||||
});
|
||||
|
||||
typeSelect.addEventListener('change', updatePortHint);
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user