Files

165 lines
5.7 KiB
QML

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)
}
}