/** * This plugin's configuration, rendered on its own page in the plugin * manager (`plugins.bundle.config`, keyed by this package's name). * * The owner asks for two views: `summary` (a one-liner that stands in for the * 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 */ import * as React from 'react' import { DISMISS_CHOICES, KINDS } from '../constants.js' import { windowIsAway } from '../platform.js' import { DismissRow } from './DismissRow.js' import { KindRow } from './KindRow.js' import { seatTranslator, useOwnStore } from './hooks.js' import { CSS } from './styles.js' const h = React.createElement 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 !== '' const statusKey = permission === 'granted' ? 'settings.permission.granted' : permission === 'denied' ? 'settings.permission.denied' : supported ? 'settings.permission.default' : 'settings.permission.unsupported' 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') : health.state === 'noHooks' ? tr('settings.health.noHooks') : health.state === 'error' ? 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-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.popup')), h('div', { className: 'dsn-list' }, h(DismissRow, { label: tr('settings.dismiss.label'), options: DISMISS_CHOICES.map((value) => ({ value, label: tr(`settings.dismiss.${value}`) })), value: snapshot.dismissAfterMs, onChange: props.setDismiss, })), h('p', { className: 'dsn-group-note' }, tr('config.dismiss.note'))), 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-fact-value${healthFailed ? ' is-error' : ''}`, role: healthFailed ? 'alert' : 'status', }, 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'))))))) }