This commit is contained in:
parent
042dd589fa
commit
b61c4c9479
@ -75,14 +75,6 @@
|
||||
|
||||
<div v-else-if="!loading" class="config-page-body">
|
||||
<section class="editor-panel" :aria-busy="sectionLoading">
|
||||
<div class="panel-heading">
|
||||
<div>
|
||||
<h4>{{ canWrite ? '填写配置' : '查看配置' }}</h4>
|
||||
<p class="heading-note">{{ canWrite ? '按分组填写内容,验证并保存后再应用生效。' : '当前页面的脱敏配置内容。' }}</p>
|
||||
</div>
|
||||
<span class="selected-section-label">{{ currentSection.label }}</span>
|
||||
</div>
|
||||
|
||||
<p v-if="selectedSection === 'ssl' && status.tlsMode === 'proxy'" class="heading-note" role="note">
|
||||
当前由反向代理提供 HTTPS,Smail 不自动申请或续期 SSL 证书。下方配置仅用于本地邮件服务证书;外部续期后请重新导入并应用,不能仅更新反代服务器上的证书。
|
||||
</p>
|
||||
|
||||
@ -1,42 +1,26 @@
|
||||
.config-form {
|
||||
display: grid;
|
||||
gap: 24px;
|
||||
margin-top: 22px;
|
||||
gap: 20px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.config-form:not(:first-child) {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.form-group + .form-group {
|
||||
padding-top: 24px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid var(--pm-border-color);
|
||||
}
|
||||
|
||||
.form-group-heading {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.form-group-heading h5 {
|
||||
margin: 0;
|
||||
color: var(--pm-text-primary);
|
||||
font-size: 15px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.credential-status {
|
||||
color: var(--pm-text-secondary);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.form-group-description,
|
||||
.credential-status,
|
||||
.form-group-note,
|
||||
.form-empty {
|
||||
margin: 6px 0 18px;
|
||||
margin: 0 0 12px;
|
||||
color: var(--pm-text-secondary);
|
||||
font-size: 12px;
|
||||
line-height: 1.7;
|
||||
|
||||
@ -1,13 +1,9 @@
|
||||
<template>
|
||||
<div class="config-form" :data-form-section="section">
|
||||
<p v-if="!groups.length" class="form-empty">当前没有可配置的插件。安装插件后可在这里管理启用状态与运行设置。</p>
|
||||
<section v-for="group in groups" :key="group.id" class="form-group" :aria-labelledby="`form-group-${group.id}`">
|
||||
<div class="form-group-heading">
|
||||
<h5 :id="`form-group-${group.id}`">{{ group.title }}</h5>
|
||||
<span v-if="section === 'plugins'" class="credential-status">{{ group.secretConfigured ? '凭据已配置' : '未配置凭据' }}</span>
|
||||
</div>
|
||||
<p class="form-group-description">{{ group.description }}</p>
|
||||
<p v-if="group.note" class="form-group-description">{{ group.note }}</p>
|
||||
<section v-for="group in groups" :key="group.id" class="form-group" :aria-label="group.title">
|
||||
<p v-if="section === 'plugins'" class="credential-status">{{ group.secretConfigured ? '凭据已配置' : '未配置凭据' }}</p>
|
||||
<p v-if="group.note" class="form-group-note" role="note">{{ group.note }}</p>
|
||||
<div class="form-grid">
|
||||
<ConfigField
|
||||
v-for="field in group.fields"
|
||||
|
||||
@ -127,15 +127,6 @@
|
||||
.panel-heading {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.selected-section-label {
|
||||
padding: 4px 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--pm-bg-primary);
|
||||
color: var(--pm-text-secondary);
|
||||
font-size: 11px;
|
||||
line-height: 1.5;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.editor-hint,
|
||||
.action-hint {
|
||||
margin: 8px 0 0;
|
||||
@ -398,9 +389,6 @@
|
||||
"main";
|
||||
gap: 16px;
|
||||
}
|
||||
.selected-section-label {
|
||||
white-space: normal;
|
||||
}
|
||||
.config-navigation {
|
||||
gap: 12px;
|
||||
position: static;
|
||||
|
||||
@ -32,6 +32,27 @@ test('五个分区使用分组表单,控件和样式能编译且不再提供 J
|
||||
}
|
||||
})
|
||||
|
||||
test('分组不显示重复标题和介绍,保留无障碍名称、凭据状态及异常提示', () => {
|
||||
const template = readFileSync(new URL('ConfigForm/ConfigForm.vue', root), 'utf8')
|
||||
const css = readFileSync(new URL('ConfigForm/ConfigForm.css', root), 'utf8')
|
||||
assert.doesNotMatch(template, /<h[1-6]\b|form-group-heading|form-group-description|group\.description/)
|
||||
assert.doesNotMatch(template, /aria-labelledby/)
|
||||
assert.match(template, /<section\b[^>]*:aria-label="group.title"/)
|
||||
assert.match(template, /v-if="section === 'plugins'" class="credential-status"/)
|
||||
assert.match(template, /group.secretConfigured \? '凭据已配置' : '未配置凭据'/)
|
||||
assert.match(template, /v-if="group.note" class="form-group-note" role="note"/)
|
||||
assert.match(template, /v-if="!groups.length" class="form-empty"/)
|
||||
assert.match(template, /<ConfigField\b/)
|
||||
for (const binding of ['v-for="field in group.fields"', ':value="getValue(config, field.path)"', ':error="errors[fieldKey(field)]"', ':disabled="disabled"', "emit('change', path, value)"]) {
|
||||
assert.ok(template.includes(binding))
|
||||
}
|
||||
assert.doesNotMatch(css, /form-group-heading|form-group-description/)
|
||||
const formStyle = css.match(/\.config-form\s*\{([^}]+)\}/)?.[1] || ''
|
||||
assert.doesNotMatch(formStyle, /margin-top|padding-top/)
|
||||
assert.match(css, /\.config-form:not\(:first-child\)\s*\{\s*margin-top: 16px;/)
|
||||
assert.match(css, /\.form-group \+ \.form-group\s*\{[^}]*border-top:/)
|
||||
})
|
||||
|
||||
test('单字段更新完整保留内部数据,锁定字段和污染路径无法写入', () => {
|
||||
const config = {
|
||||
generation: 8, schemaVersion: 2, database: { type: 'sqlite', localRef: 'test.db', password: null },
|
||||
|
||||
@ -339,6 +339,20 @@ test('配置编辑页移除步骤提示条和专用样式,保留实际操作
|
||||
assert.match(template, /@click="managePending\('cancel'\)"/)
|
||||
})
|
||||
|
||||
test('配置编辑区移除填写标题、说明与重复标签,保留主标题和必要提示', () => {
|
||||
const root = new URL('../../frontend/src/views/components/ConfigSettings/', import.meta.url)
|
||||
const template = readFileSync(new URL('ConfigEditor/ConfigEditor.vue', root), 'utf8')
|
||||
const css = readFileSync(new URL('ConfigSettings.css', root), 'utf8')
|
||||
assert.doesNotMatch(template, /'填写配置'|'查看配置'|按分组填写内容|当前页面的脱敏配置内容|panel-heading|selected-section-label/)
|
||||
assert.doesNotMatch(css, /selected-section-label/)
|
||||
assert.match(template, /<h3 id="config-page-title">{{ currentSection.label }}/)
|
||||
assert.match(template, /v-if="selectedSection === 'ssl' && status.tlsMode === 'proxy'"[^>]*role="note"/)
|
||||
assert.match(template, /v-if="sectionError"[\s\S]*?:title="sectionError"/)
|
||||
assert.match(template, /<p id="config-sensitive-hint"/)
|
||||
assert.match(template, /v-if="secretField" class="secret-editor"/)
|
||||
assert.match(template, /v-if="validationResult"[^>]*role="status"/)
|
||||
})
|
||||
|
||||
test('离开、刷新和正在执行的变更受保护,取消时保留编辑内容', async () => {
|
||||
let cancel = true
|
||||
let prompts = 0
|
||||
|
||||
Loading…
Reference in New Issue
Block a user