import QtQuick import qs.config import qs.services Item { id: root required property var check property bool issue: false property bool divider: true property int actionActivationCount: 0 signal actionRequested(var check) readonly property bool repairWorking: Health.repairingId === root.check.id readonly property bool repairFailed: root.check.status !== "ok" && Health.lastRepair.checkId === root.check.id && (Health.lastRepair.accepted === false || Health.lastRepair.exitCode !== 0) readonly property bool rechecking: Health.refreshingId === root.check.id && Health.refreshingCheck // What the row says under its title. Defaults to the check's own detail; // the page overrides it where it has more to say -- a repair row is given // the command it would run. property string detailText: String(root.check.detail ?? "") objectName: `health-check-row:${root.issue ? "issue" : "quiet"}:${root.check.id}` implicitHeight: 62 // The isolated contract uses the same signal path as a pointer or keyboard // activation instead of calling HealthPage's action handler directly. function activateAction(): bool { if (!actionButton.visible || !actionButton.enabled) return false; root.actionActivationCount += 1; actionButton.clicked(); return true; } function statusLabel(status: string): string { if (status === "ok") return "Healthy"; if (status === "warning") return "Needs attention"; if (status === "error") return "Action required"; return "Not set up"; } function statusColor(status: string): color { if (status === "ok") return Theme.ok; if (status === "warning") return Theme.warn; if (status === "error") return Theme.danger; return Theme.fgMuted; } function displayedStatus(): string { if (root.repairWorking) return "Working…"; if (root.repairFailed) return "Repair failed"; return root.statusLabel(root.check.status); } Rectangle { id: issueMark visible: root.issue width: 7 height: 7 radius: 4 anchors.left: parent.left anchors.leftMargin: 1 anchors.verticalCenter: parent.verticalCenter color: root.statusColor(root.check.status) border.width: 1 border.color: Theme.alpha(Theme.bgPanel, 0.9) } Column { anchors.left: parent.left anchors.leftMargin: root.issue ? 22 : 0 anchors.right: trailing.left anchors.rightMargin: 16 anchors.verticalCenter: parent.verticalCenter spacing: 3 Text { width: parent.width text: root.check.title color: Theme.fg font.family: Theme.fontFamily font.pixelSize: Theme.fontSize font.weight: Font.Medium elide: Text.ElideRight } Text { width: parent.width text: root.detailText color: Theme.fgDim font.family: Theme.fontFamily font.pixelSize: Theme.fontSizeSmall elide: Text.ElideRight } } Row { id: trailing anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter spacing: 12 Text { objectName: `health-status-text:${root.issue ? "issue" : "quiet"}:${root.check.id}` anchors.verticalCenter: parent.verticalCenter text: root.rechecking ? "Checking…" : root.displayedStatus() color: root.statusColor(root.check.status) font.family: Theme.fontFamily font.pixelSize: Theme.fontSizeSmall } SettingsButton { id: actionButton objectName: `health-row-action:${root.issue ? "issue" : "quiet"}:${root.check.id}` visible: root.check.action !== undefined text: root.check.action?.label ?? "" enabled: visible && !root.repairWorking && !Health.busy activeFocusOnTab: enabled border.width: activeFocus ? 2 : 1 border.color: activeFocus ? Theme.accent : Theme.alpha(Theme.fg, 0.08) onClicked: root.actionRequested(root.check) Keys.onReturnPressed: if (enabled) root.actionRequested(root.check) Keys.onSpacePressed: if (enabled) root.actionRequested(root.check) } // One probe rather than thirty. After a repair -- or after fixing // something by hand in a terminal -- the question is whether THIS row // is happy now, and a full rescan to answer it costs nine seconds and // re-renders the whole page. Offered on rows that are unhappy, since a // healthy row has nothing to re-ask. SettingsButton { id: recheckButton objectName: `health-row-recheck:${root.check.id}` visible: root.issue text: root.rechecking ? "Checking…" : "Re-check" enabled: visible && !Health.busy && !Health.refreshingCheck activeFocusOnTab: enabled border.width: activeFocus ? 2 : 1 border.color: activeFocus ? Theme.accent : Theme.alpha(Theme.fg, 0.08) onClicked: Health.refreshCheck(root.check.id) Keys.onReturnPressed: if (enabled) Health.refreshCheck(root.check.id) Keys.onSpacePressed: if (enabled) Health.refreshCheck(root.check.id) } } Rectangle { visible: root.divider anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom height: 1 color: Theme.alpha(Theme.fg, 0.07) } }