✨ feat(client): 插件页改为三组列表与键值状态,权限带状态点
This commit is contained in:
@@ -6,6 +6,12 @@
|
||||
* row's description) and `page` (the whole form). Everything visible here
|
||||
* belongs to this package, including the platform-specific permission hint.
|
||||
*
|
||||
* The page is laid out as three groups — what to notify about, the system
|
||||
* channel's own state, and what the plugin is doing right now. Each group keeps
|
||||
* its controls in one place: a list whose rows carry the subject on the left and
|
||||
* the control on the right, and a fact list for the readings, so the status
|
||||
* block is scannable instead of being four sentences in one cell.
|
||||
*
|
||||
* @module @dsh-plugin/session-notify/client/ui/ConfigSection
|
||||
*/
|
||||
|
||||
@@ -22,6 +28,7 @@ export function ConfigSection(props) {
|
||||
const snapshot = useOwnStore(props.store)
|
||||
const tr = seatTranslator(props, props.fallbackT)
|
||||
if (props.view === 'summary') return h(React.Fragment, null, tr('settings.description'))
|
||||
|
||||
const permission = snapshot.permission
|
||||
const supported = permission !== 'unsupported'
|
||||
const failed = permission === 'denied' || snapshot.promptError !== ''
|
||||
@@ -32,9 +39,19 @@ export function ConfigSection(props) {
|
||||
: supported
|
||||
? 'settings.permission.default'
|
||||
: 'settings.permission.unsupported'
|
||||
const permissionText = snapshot.promptError === ''
|
||||
? `${tr(statusKey)}${permission === 'denied' || !supported ? ` · ${tr(`settings.permission.hint.${props.platform}`)}` : ''}`
|
||||
: snapshot.promptError
|
||||
const promptFailed = snapshot.promptError !== ''
|
||||
const permissionText = promptFailed ? snapshot.promptError : tr(statusKey)
|
||||
const dotClass = permission === 'granted'
|
||||
? ''
|
||||
: failed ? ' is-error' : supported ? ' is-warn' : ' is-muted'
|
||||
const permissionNote = promptFailed
|
||||
? ''
|
||||
: permission === 'denied' || !supported
|
||||
? tr(`settings.permission.hint.${props.platform}`)
|
||||
: permission === 'granted'
|
||||
? tr('config.testHint')
|
||||
: tr('settings.permission.hint.plain')
|
||||
|
||||
const health = snapshot.health
|
||||
const healthText = health.state === 'watching'
|
||||
? tr('settings.health.watching')
|
||||
@@ -44,55 +61,80 @@ export function ConfigSection(props) {
|
||||
? tr('settings.health.error', { message: health.message })
|
||||
: tr('settings.health.starting')
|
||||
const healthFailed = health.state !== 'watching' && health.state !== 'starting'
|
||||
|
||||
const delivery = props.copy.deliveryFacts(snapshot.lastDelivery, tr)
|
||||
|
||||
return h(React.Fragment, null,
|
||||
h('style', null, CSS),
|
||||
h('div', { className: 'dsn-sections' },
|
||||
// The page header already shows this bundle's title and description, so
|
||||
// this section opens with what the header cannot say: how alerts are
|
||||
// carried, and what this form changes.
|
||||
h('section', { className: 'dsn-section' },
|
||||
h('p', { className: 'dsn-section-desc' }, tr('config.intro'))),
|
||||
h('section', { className: 'dsn-section' },
|
||||
h('h3', { className: 'dsn-section-title' }, tr('config.section.kinds')),
|
||||
KINDS.map((kind) => h(KindRow, {
|
||||
key: kind,
|
||||
label: tr(`settings.kind.${kind}`),
|
||||
checked: snapshot.kinds[kind] === true,
|
||||
disabled: false,
|
||||
onToggle: () => props.setKind(kind, snapshot.kinds[kind] !== true),
|
||||
})),
|
||||
h('p', { className: 'dsn-section-desc' }, tr('config.saveNote'))),
|
||||
h('section', { className: 'dsn-section' },
|
||||
h('h3', { className: 'dsn-section-title' }, tr('config.section.permission')),
|
||||
h('div', { className: 'dsn-row' },
|
||||
h('div', { className: 'dsn-row-text' },
|
||||
h('div', { className: 'dsn-page' },
|
||||
// The page header already shows this bundle's title and description, so this
|
||||
// lede says what the header cannot: how an alert travels, and that the
|
||||
// channel is chosen at delivery time.
|
||||
h('p', { className: 'dsn-lede' }, tr('config.intro')),
|
||||
|
||||
h('section', { className: 'dsn-group' },
|
||||
h('h3', { className: 'dsn-group-title' }, tr('config.section.kinds')),
|
||||
h('div', { className: 'dsn-list' },
|
||||
KINDS.map((kind) => h(KindRow, {
|
||||
key: kind,
|
||||
label: tr(`settings.kind.${kind}`),
|
||||
checked: snapshot.kinds[kind] === true,
|
||||
disabled: false,
|
||||
onToggle: () => props.setKind(kind, snapshot.kinds[kind] !== true),
|
||||
}))),
|
||||
h('p', { className: 'dsn-group-note' }, tr('config.saveNote'))),
|
||||
|
||||
h('section', { className: 'dsn-group' },
|
||||
h('h3', { className: 'dsn-group-title' }, tr('config.section.permission')),
|
||||
h('div', { className: 'dsn-list' },
|
||||
h('div', { className: 'dsn-row' },
|
||||
h('div', { className: 'dsn-row-text' },
|
||||
h('span', {
|
||||
className: 'dsn-state',
|
||||
role: failed ? 'alert' : 'status',
|
||||
},
|
||||
h('span', { className: `dsn-dot${dotClass}` }),
|
||||
permissionText),
|
||||
h('p', { className: 'dsn-row-sub' }, permissionNote)),
|
||||
h('button', {
|
||||
type: 'button',
|
||||
className: `dsn-button${supported && permission !== 'granted' ? ' is-primary' : ''}`,
|
||||
disabled: !supported,
|
||||
onClick: permission === 'granted' ? props.testSystem : props.ask,
|
||||
}, tr(!supported
|
||||
? 'settings.action.unsupported'
|
||||
: permission === 'granted' ? 'settings.action.testSystem' : 'settings.action.allow'))))),
|
||||
|
||||
h('section', { className: 'dsn-group' },
|
||||
h('h3', { className: 'dsn-group-title' }, tr('config.section.status')),
|
||||
h('dl', { className: 'dsn-facts' },
|
||||
h('dt', { className: 'dsn-fact-key' }, tr('config.diag.window')),
|
||||
h('dd', { className: 'dsn-fact' },
|
||||
h('p', { className: 'dsn-fact-value' }, tr(windowIsAway() ? 'config.diag.away' : 'config.diag.inFront'))),
|
||||
h('dt', { className: 'dsn-fact-key' }, tr('config.diag.watch')),
|
||||
h('dd', { className: 'dsn-fact' },
|
||||
h('p', {
|
||||
className: `dsn-status${failed ? ' dsn-status-error' : ''}`,
|
||||
role: failed ? 'alert' : 'status',
|
||||
}, permissionText)),
|
||||
h('button', {
|
||||
type: 'button',
|
||||
className: 'dsn-button',
|
||||
disabled: !supported,
|
||||
onClick: permission === 'granted' ? props.testSystem : props.ask,
|
||||
}, tr(!supported
|
||||
? 'settings.action.unsupported'
|
||||
: permission === 'granted' ? 'settings.action.testSystem' : 'settings.action.allow'))),
|
||||
h('p', { className: 'dsn-section-desc' }, tr('config.testHint'))),
|
||||
h('section', { className: 'dsn-section' },
|
||||
h('h3', { className: 'dsn-section-title' }, tr('config.section.status')),
|
||||
h('div', { className: 'dsn-row' },
|
||||
h('div', { className: 'dsn-row-text' },
|
||||
h('p', { className: 'dsn-status' }, `${tr('config.diag.window')}: ${tr(windowIsAway() ? 'config.diag.away' : 'config.diag.inFront')}`),
|
||||
h('p', {
|
||||
className: `dsn-status${healthFailed ? ' dsn-status-error' : ''}`,
|
||||
className: `dsn-fact-value${healthFailed ? ' is-error' : ''}`,
|
||||
role: healthFailed ? 'alert' : 'status',
|
||||
}, healthText),
|
||||
h('p', { className: 'dsn-status' }, props.copy.describeDelivery(snapshot.lastDelivery, tr)),
|
||||
h('p', { className: 'dsn-status' }, props.copy.describeReplay(props.replayCount(), tr))),
|
||||
h('button', {
|
||||
type: 'button',
|
||||
className: 'dsn-button',
|
||||
onClick: props.testAny,
|
||||
}, tr('settings.action.testAny'))))))
|
||||
}, healthText)),
|
||||
h('dt', { className: 'dsn-fact-key' }, tr('config.diag.last')),
|
||||
h('dd', { className: 'dsn-fact' },
|
||||
delivery === null
|
||||
? h('p', { className: 'dsn-fact-value' }, tr('config.diag.none'))
|
||||
: [
|
||||
h('p', { key: 'line', className: 'dsn-fact-value' }, `${delivery.at} · ${delivery.outcome}`),
|
||||
delivery.title === ''
|
||||
? null
|
||||
: h('p', { key: 'title', className: 'dsn-fact-title' }, delivery.title),
|
||||
]),
|
||||
h('dt', { className: 'dsn-fact-key' }, tr('config.diag.replay')),
|
||||
h('dd', { className: 'dsn-fact' },
|
||||
h('p', { className: 'dsn-fact-value' }, props.copy.replayValue(props.replayCount(), tr)))),
|
||||
h('div', { className: 'dsn-list' },
|
||||
h('div', { className: 'dsn-row is-action' },
|
||||
h('button', {
|
||||
type: 'button',
|
||||
className: 'dsn-button',
|
||||
onClick: props.testAny,
|
||||
}, tr('settings.action.testAny')))))))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user