diff --git a/plugin/Cargo.toml b/plugin/Cargo.toml index 5fb8d24..3a1cce9 100644 --- a/plugin/Cargo.toml +++ b/plugin/Cargo.toml @@ -24,7 +24,13 @@ dirs = "6.0.0" tracing = "0.1.44" tracing-subscriber = { version = "0.3.23", features = ["env-filter"] } zbus = { version = "5.15.0", default-features = false, features = ["tokio"] } -tokio = { version = "1.52.2", features = ["macros", "net", "rt", "sync", "time"] } +tokio = { version = "1.52.2", features = [ + "macros", + "net", + "rt", + "sync", + "time", +] } [build-dependencies] cxx-qt-build = "0.8.1" diff --git a/plugin/src/modules_service.rs b/plugin/src/modules_service.rs index aea0e77..05e33ad 100644 --- a/plugin/src/modules_service.rs +++ b/plugin/src/modules_service.rs @@ -101,11 +101,9 @@ pub mod qobject { #[qproperty(bool, dock_applet_mpris, cxx_name = "dockAppletMpris")] #[qproperty(bool, dock_applet_notifications, cxx_name = "dockAppletNotifications")] #[qproperty(bool, dock_applet_power, cxx_name = "dockAppletPower")] - // Systemd / machinectl bar modules. + // Unified systemd bar module (covers local + nspawn containers, and later remotes). #[qproperty(bool, systemd_enable, cxx_name = "systemdEnable")] #[qproperty(i32, systemd_interval, cxx_name = "systemdInterval")] - #[qproperty(bool, machinectl_enable, cxx_name = "machinectlEnable")] - #[qproperty(i32, machinectl_interval, cxx_name = "machinectlInterval")] type ModulesService = super::ModulesServiceRust; } @@ -522,8 +520,6 @@ mod data { #[serde(default)] pub systemd: WithInterval, #[serde(default)] - pub machinectl: WithInterval, - #[serde(default)] pub stats_daemon: StatsDaemon, } } @@ -599,8 +595,6 @@ pub struct ModulesServiceRust { dock_applet_power: bool, systemd_enable: bool, systemd_interval: i32, - machinectl_enable: bool, - machinectl_interval: i32, } impl Default for ModulesServiceRust { @@ -684,8 +678,6 @@ impl ModulesServiceRust { dock_applet_power: d.dock.applets.power, systemd_enable: d.systemd.enable, systemd_interval: d.systemd.interval, - machinectl_enable: d.machinectl.enable, - machinectl_interval: d.machinectl.interval, } } } @@ -746,7 +738,6 @@ fn parse_modules(raw: &str, path: &std::path::Path) -> ModulesData { "lock", "dock", "systemd", - "machinectl", "statsDaemon", ]; for key in map.keys() { diff --git a/plugin/src/systemd_service.rs b/plugin/src/systemd_service.rs index 42bfddb..53021d0 100644 --- a/plugin/src/systemd_service.rs +++ b/plugin/src/systemd_service.rs @@ -12,7 +12,7 @@ use cxx_qt_lib::QString; use serde::Serialize; use std::sync::OnceLock; use tokio::runtime::Runtime; -use zbus::{proxy, Connection}; +use zbus::{Connection, proxy}; #[cxx_qt::bridge] pub mod qobject { @@ -72,11 +72,8 @@ trait SystemdManager { fn list_units_filtered(&self, states: Vec<&str>) -> zbus::Result>; - fn restart_unit( - &self, - name: &str, - mode: &str, - ) -> zbus::Result; + fn restart_unit(&self, name: &str, mode: &str) + -> zbus::Result; } #[proxy( @@ -242,9 +239,11 @@ impl qobject::SystemdService { self.as_mut().set_system_state(QString::from(sys_state)); self.as_mut().set_user_state(QString::from(user_state)); - self.as_mut().set_failed_units_json(QString::from(failed_json)); + self.as_mut() + .set_failed_units_json(QString::from(failed_json)); self.as_mut().set_failed_count(count); - self.as_mut().set_containers_json(QString::from(containers_json)); + self.as_mut() + .set_containers_json(QString::from(containers_json)); } fn restart_unit(self: Pin<&mut Self>, name: QString, scope: QString, machine: QString) { diff --git a/shell/applets/MachinectlApplet.qml b/shell/applets/MachinectlApplet.qml deleted file mode 100644 index 62c7e0e..0000000 --- a/shell/applets/MachinectlApplet.qml +++ /dev/null @@ -1,354 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import "../services" as S -import NovaStats as NS - -Column { - id: root - - required property color accentColor - property bool active: true - - property bool _localExpanded: true - - // Localhost section header - Item { - width: root.width - height: 32 - - Rectangle { - anchors.fill: parent - anchors.leftMargin: 4 - anchors.rightMargin: 4 - color: _localHdrHover.hovered ? NS.ThemeService.base02 : "transparent" - radius: NS.ThemeService.radius - z: -1 - } - - HoverHandler { - id: _localHdrHover - } - - Text { - anchors.left: parent.left - anchors.leftMargin: 12 - anchors.verticalCenter: parent.verticalCenter - text: " localhost" - color: NS.ThemeService.base05 - font.pixelSize: NS.ThemeService.fontSize - font.family: NS.ThemeService.fontFamily - } - - Rectangle { - id: _localStateChip - anchors.right: _localChevron.left - anchors.rightMargin: 8 - anchors.verticalCenter: parent.verticalCenter - visible: S.SystemdService.systemState !== "unknown" - color: { - const st = S.SystemdService.systemState; - if (st === "running") - return NS.ThemeService.base0B; - if (st === "degraded") - return NS.ThemeService.base0A; - return NS.ThemeService.base08; - } - opacity: 0.85 - radius: 3 - width: _localStateLbl.width + 8 - height: 14 - - Text { - id: _localStateLbl - anchors.centerIn: parent - text: S.SystemdService.systemState - color: NS.ThemeService.base00 - font.pixelSize: NS.ThemeService.fontSize - 3 - font.family: NS.ThemeService.fontFamily - } - } - - Text { - id: _localChevron - anchors.right: parent.right - anchors.rightMargin: 12 - anchors.verticalCenter: parent.verticalCenter - text: root._localExpanded ? "" : "" - color: NS.ThemeService.base04 - font.pixelSize: NS.ThemeService.fontSize - 2 - font.family: NS.ThemeService.iconFontFamily - } - - TapHandler { - onTapped: root._localExpanded = !root._localExpanded - } - } - - // Localhost expanded content - Column { - visible: root._localExpanded - width: root.width - - // System sub-section - Item { - width: root.width - height: 22 - - Text { - anchors.left: parent.left - anchors.leftMargin: 24 - anchors.verticalCenter: parent.verticalCenter - text: "SYSTEM" - color: NS.ThemeService.base03 - font.pixelSize: NS.ThemeService.fontSize - 3 - font.family: NS.ThemeService.fontFamily - font.letterSpacing: 1 - } - } - - Repeater { - model: S.SystemdService.systemUnits - delegate: SystemdUnitRow { - required property var modelData - unitName: modelData.name - description: modelData.description - subState: modelData.subState - isUser: false - machineName: "" - accentColor: root.accentColor - } - } - - Item { - visible: S.SystemdService.systemUnits.length === 0 - width: root.width - height: 22 - Text { - anchors.centerIn: parent - text: "no failures" - color: NS.ThemeService.base0B - font.pixelSize: NS.ThemeService.fontSize - 2 - font.family: NS.ThemeService.fontFamily - } - } - - // User sub-section - Item { - width: root.width - height: 22 - - Text { - anchors.left: parent.left - anchors.leftMargin: 24 - anchors.verticalCenter: parent.verticalCenter - text: "USER" - color: NS.ThemeService.base03 - font.pixelSize: NS.ThemeService.fontSize - 3 - font.family: NS.ThemeService.fontFamily - font.letterSpacing: 1 - } - } - - Repeater { - model: S.SystemdService.userUnits - delegate: SystemdUnitRow { - required property var modelData - unitName: modelData.name - description: modelData.description - subState: modelData.subState - isUser: true - machineName: "" - accentColor: root.accentColor - } - } - - Item { - visible: S.SystemdService.userUnits.length === 0 - width: root.width - height: 22 - Text { - anchors.centerIn: parent - text: "no failures" - color: NS.ThemeService.base0B - font.pixelSize: NS.ThemeService.fontSize - 2 - font.family: NS.ThemeService.fontFamily - } - } - } - - // Containers - Repeater { - model: S.MachinectlService.machines - - delegate: Column { - id: _machineSection - required property var modelData - required property int index - - property bool _expanded: false - property bool _loading: false - - width: root.width - - Connections { - target: S.MachinectlService - function onMachineReady(machineName) { - if (machineName === _machineSection.modelData.name) - _machineSection._loading = false; - } - } - - Separator {} - - // Machine header - Item { - width: _machineSection.width - height: 32 - - Rectangle { - anchors.fill: parent - anchors.leftMargin: 4 - anchors.rightMargin: 4 - color: _mHdrHover.hovered ? NS.ThemeService.base02 : "transparent" - radius: NS.ThemeService.radius - z: -1 - } - - HoverHandler { - id: _mHdrHover - } - - Text { - anchors.left: parent.left - anchors.leftMargin: 12 - anchors.verticalCenter: parent.verticalCenter - text: " " + _machineSection.modelData.name - color: NS.ThemeService.base05 - font.pixelSize: NS.ThemeService.fontSize - font.family: NS.ThemeService.fontFamily - elide: Text.ElideRight - width: parent.width - 100 - } - - Rectangle { - id: _mStateChip - anchors.right: _mChevron.left - anchors.rightMargin: 8 - anchors.verticalCenter: parent.verticalCenter - visible: _machineSection._expanded && !_machineSection._loading - color: { - const st = S.MachinectlService.machineState(_machineSection.modelData.name); - if (st === "running") - return NS.ThemeService.base0B; - if (st === "degraded") - return NS.ThemeService.base0A; - return st === "unknown" ? "transparent" : NS.ThemeService.base08; - } - opacity: 0.85 - radius: 3 - width: _mStateLbl.width + 8 - height: 14 - - Text { - id: _mStateLbl - anchors.centerIn: parent - text: S.MachinectlService.machineState(_machineSection.modelData.name) - color: NS.ThemeService.base00 - font.pixelSize: NS.ThemeService.fontSize - 3 - font.family: NS.ThemeService.fontFamily - } - } - - Text { - id: _mChevron - anchors.right: parent.right - anchors.rightMargin: 12 - anchors.verticalCenter: parent.verticalCenter - text: _machineSection._expanded ? "" : "" - color: NS.ThemeService.base04 - font.pixelSize: NS.ThemeService.fontSize - 2 - font.family: NS.ThemeService.iconFontFamily - } - - TapHandler { - onTapped: { - _machineSection._expanded = !_machineSection._expanded; - if (_machineSection._expanded) { - _machineSection._loading = true; - S.MachinectlService.fetchMachine(_machineSection.modelData.name); - } - } - } - } - - // Machine expanded content - Column { - visible: _machineSection._expanded - width: _machineSection.width - - Item { - visible: _machineSection._loading - width: _machineSection.width - height: 28 - Text { - anchors.centerIn: parent - text: "loading..." - color: NS.ThemeService.base04 - font.pixelSize: NS.ThemeService.fontSize - 2 - font.family: NS.ThemeService.fontFamily - } - } - - // System units inside the container - Item { - visible: !_machineSection._loading - width: _machineSection.width - height: 22 - - Text { - anchors.left: parent.left - anchors.leftMargin: 24 - anchors.verticalCenter: parent.verticalCenter - text: "SYSTEM" - color: NS.ThemeService.base03 - font.pixelSize: NS.ThemeService.fontSize - 3 - font.family: NS.ThemeService.fontFamily - font.letterSpacing: 1 - } - } - - Repeater { - model: !_machineSection._loading ? S.MachinectlService.machineUnits(_machineSection.modelData.name) : [] - delegate: SystemdUnitRow { - required property var modelData - unitName: modelData.name - description: modelData.description - subState: modelData.subState - isUser: false - machineName: _machineSection.modelData.name - accentColor: root.accentColor - } - } - - Item { - visible: !_machineSection._loading && S.MachinectlService.machineUnits(_machineSection.modelData.name).length === 0 - width: _machineSection.width - height: 22 - Text { - anchors.centerIn: parent - text: "no failures" - color: NS.ThemeService.base0B - font.pixelSize: NS.ThemeService.fontSize - 2 - font.family: NS.ThemeService.fontFamily - } - } - } - } - } - - Item { - width: 1 - height: 4 - } -} diff --git a/shell/applets/SystemdApplet.qml b/shell/applets/SystemdApplet.qml index 6462ed3..bd2f1aa 100644 --- a/shell/applets/SystemdApplet.qml +++ b/shell/applets/SystemdApplet.qml @@ -9,156 +9,43 @@ Column { required property color accentColor property bool active: true - // Emitted when content resizes; parent can connect to extend panel-close grace. signal contentResized - // Section header: state label + unit count - Item { + onHeightChanged: root.contentResized() + + // Local machine header + units + SystemdMachineSection { width: root.width - height: 28 - - Text { - anchors.left: parent.left - anchors.leftMargin: 12 - anchors.verticalCenter: parent.verticalCenter - text: "SYSTEM" - color: NS.ThemeService.base03 - font.pixelSize: NS.ThemeService.fontSize - 3 - font.family: NS.ThemeService.fontFamily - font.letterSpacing: 1 - } - - Rectangle { - anchors.right: parent.right - anchors.rightMargin: 12 - anchors.verticalCenter: parent.verticalCenter - visible: S.SystemdService.systemState !== "unknown" - color: { - const st = S.SystemdService.systemState; - if (st === "running") - return NS.ThemeService.base0B; - if (st === "degraded") - return NS.ThemeService.base0A; - return NS.ThemeService.base08; - } - opacity: 0.85 - radius: 3 - width: _sysStateLbl.width + 8 - height: 14 - - Text { - id: _sysStateLbl - anchors.centerIn: parent - text: S.SystemdService.systemState - color: NS.ThemeService.base00 - font.pixelSize: NS.ThemeService.fontSize - 3 - font.family: NS.ThemeService.fontFamily - } - } + accentColor: root.accentColor + machineName: "" + title: S.SystemdService.hostname + marker: " this machine" + systemState: S.SystemdService.systemState + units: S.SystemdService.failedUnits + startExpanded: true } + // Containers Repeater { - model: S.SystemdService.systemUnits + model: S.SystemdService.containers - delegate: SystemdUnitRow { + delegate: Column { + id: _row required property var modelData - unitName: modelData.name - description: modelData.description - subState: modelData.subState - isUser: false - machineName: "" - accentColor: root.accentColor - onHeightChanged: root.contentResized() - } - } + width: root.width - Item { - visible: S.SystemdService.systemUnits.length === 0 - width: root.width - height: 24 + Separator {} - Text { - anchors.centerIn: parent - text: "no failed system units" - color: NS.ThemeService.base0B - font.pixelSize: NS.ThemeService.fontSize - 2 - font.family: NS.ThemeService.fontFamily - } - } - - Separator {} - - // User section - Item { - width: root.width - height: 28 - - Text { - anchors.left: parent.left - anchors.leftMargin: 12 - anchors.verticalCenter: parent.verticalCenter - text: "USER" - color: NS.ThemeService.base03 - font.pixelSize: NS.ThemeService.fontSize - 3 - font.family: NS.ThemeService.fontFamily - font.letterSpacing: 1 - } - - Rectangle { - anchors.right: parent.right - anchors.rightMargin: 12 - anchors.verticalCenter: parent.verticalCenter - visible: S.SystemdService.userState !== "unknown" - color: { - const st = S.SystemdService.userState; - if (st === "running") - return NS.ThemeService.base0B; - if (st === "degraded") - return NS.ThemeService.base0A; - return NS.ThemeService.base08; + SystemdMachineSection { + width: _row.width + accentColor: root.accentColor + machineName: _row.modelData.name + title: _row.modelData.name + marker: "" + systemState: _row.modelData.systemState ?? "unknown" + units: _row.modelData.failedUnits ?? [] + startExpanded: (_row.modelData.failedUnits ?? []).length > 0 } - opacity: 0.85 - radius: 3 - width: _userStateLbl.width + 8 - height: 14 - - Text { - id: _userStateLbl - anchors.centerIn: parent - text: S.SystemdService.userState - color: NS.ThemeService.base00 - font.pixelSize: NS.ThemeService.fontSize - 3 - font.family: NS.ThemeService.fontFamily - } - } - } - - Repeater { - model: S.SystemdService.userUnits - - delegate: SystemdUnitRow { - required property var modelData - unitName: modelData.name - description: modelData.description - subState: modelData.subState - isUser: true - machineName: "" - accentColor: root.accentColor - onHeightChanged: root.contentResized() - } - } - - Item { - visible: S.SystemdService.userUnits.length === 0 - width: root.width - height: 24 - - Text { - anchors.centerIn: parent - text: "no failed user units" - color: NS.ThemeService.base0B - font.pixelSize: NS.ThemeService.fontSize - 2 - font.family: NS.ThemeService.fontFamily } } diff --git a/shell/applets/SystemdMachineSection.qml b/shell/applets/SystemdMachineSection.qml new file mode 100644 index 0000000..632c9db --- /dev/null +++ b/shell/applets/SystemdMachineSection.qml @@ -0,0 +1,111 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import "../services" as S +import NovaStats as NS + +// One section of the systemd applet: a header with title + state chip, +// expandable list of failed units underneath. +Column { + id: root + + required property color accentColor + required property string machineName + required property string title + required property string marker + required property string systemState + required property var units + property bool startExpanded: false + + width: parent?.width ?? 0 + + property bool _expanded: startExpanded + + Item { + width: root.width + height: 32 + + Rectangle { + anchors.fill: parent + anchors.leftMargin: 4 + anchors.rightMargin: 4 + color: _hdrHover.hovered ? NS.ThemeService.base02 : "transparent" + radius: NS.ThemeService.radius + z: -1 + } + + HoverHandler { + id: _hdrHover + } + + Text { + anchors.left: parent.left + anchors.leftMargin: 12 + anchors.right: _stateChip.left + anchors.rightMargin: 6 + anchors.verticalCenter: parent.verticalCenter + text: root.title + (root.marker !== "" ? " " + root.marker : "") + color: NS.ThemeService.base05 + font.pixelSize: NS.ThemeService.fontSize + font.family: NS.ThemeService.fontFamily + elide: Text.ElideRight + } + + Rectangle { + id: _stateChip + anchors.right: _chevron.left + anchors.rightMargin: 8 + anchors.verticalCenter: parent.verticalCenter + visible: root.systemState !== "unknown" + color: { + const st = root.systemState; + if (st === "running") + return NS.ThemeService.base0B; + if (st === "degraded") + return NS.ThemeService.base0A; + return NS.ThemeService.base08; + } + opacity: 0.85 + radius: 3 + width: _stateLbl.width + 8 + height: 14 + + Text { + id: _stateLbl + anchors.centerIn: parent + text: root.systemState + color: NS.ThemeService.base00 + font.pixelSize: NS.ThemeService.fontSize - 3 + font.family: NS.ThemeService.fontFamily + } + } + + Text { + id: _chevron + anchors.right: parent.right + anchors.rightMargin: 12 + anchors.verticalCenter: parent.verticalCenter + text: root._expanded ? "" : "" + color: NS.ThemeService.base04 + font.pixelSize: NS.ThemeService.fontSize - 2 + font.family: NS.ThemeService.iconFontFamily + } + + TapHandler { + onTapped: root._expanded = !root._expanded + } + } + + Repeater { + model: root._expanded ? root.units : [] + delegate: SystemdUnitRow { + required property var modelData + unitName: modelData.name + description: modelData.description ?? "" + subState: modelData.subState ?? "" + scope: modelData.scope ?? "system" + machineName: root.machineName + accentColor: root.accentColor + } + } +} diff --git a/shell/applets/SystemdUnitRow.qml b/shell/applets/SystemdUnitRow.qml index e05d49f..4c4f2a0 100644 --- a/shell/applets/SystemdUnitRow.qml +++ b/shell/applets/SystemdUnitRow.qml @@ -8,233 +8,95 @@ Item { required property string unitName required property string description required property string subState - required property bool isUser - property string machineName: "" + required property string scope + required property string machineName required property color accentColor - property string _jText: "" - property bool _expanded: false - property bool _loading: false - width: parent?.width ?? 0 - height: _row.height + (_expanded ? _journalArea.height : 0) + height: 28 - Behavior on height { - NumberAnimation { - duration: 150 + HoverHandler { + id: _rowHover + } + + Rectangle { + anchors.fill: parent + anchors.leftMargin: 4 + anchors.rightMargin: 4 + color: _rowHover.hovered ? NS.ThemeService.base02 : "transparent" + radius: NS.ThemeService.radius + z: -1 + } + + Text { + anchors.left: parent.left + anchors.leftMargin: 12 + anchors.right: _subStateTag.left + anchors.rightMargin: 6 + anchors.verticalCenter: parent.verticalCenter + text: root.unitName + color: NS.ThemeService.base05 + font.pixelSize: NS.ThemeService.fontSize - 1 + font.family: NS.ThemeService.fontFamily + elide: Text.ElideRight + } + + Rectangle { + id: _subStateTag + anchors.right: _restartBtn.left + anchors.rightMargin: 6 + anchors.verticalCenter: parent.verticalCenter + color: NS.ThemeService.base08 + opacity: 0.85 + radius: 3 + width: _subStateLbl.width + 8 + height: 14 + + Text { + id: _subStateLbl + anchors.centerIn: parent + text: root.subState + color: NS.ThemeService.base00 + font.pixelSize: NS.ThemeService.fontSize - 3 + font.family: NS.ThemeService.fontFamily } } - Connections { - target: S.SystemdService - enabled: root.machineName === "" - function onJournalReady(unitName, isUser, text) { - if (unitName === root.unitName && isUser === root.isUser) { - root._jText = text; - root._loading = false; - } - } - } - - Connections { - target: S.MachinectlService - enabled: root.machineName !== "" - function onMachineJournalReady(mname, unitName, text) { - if (mname === root.machineName && unitName === root.unitName) { - root._jText = text; - root._loading = false; - } - } - } - - function _fetchJournal() { - root._loading = true; - root._jText = ""; - if (root.machineName === "") - S.SystemdService.fetchJournal(root.unitName, root.isUser); - else - S.MachinectlService.fetchMachineJournal(root.machineName, root.unitName); - } - - function _doRestart() { - if (root.machineName === "") - S.SystemdService.restartUnit(root.unitName, root.isUser); - else - S.MachinectlService.restartMachineUnit(root.machineName, root.unitName); - } - - // Row + // Restart button only visible while hovering the row. = fa-refresh Item { - id: _row - width: parent.width - height: 32 - - Rectangle { - anchors.fill: parent - anchors.leftMargin: 4 - anchors.rightMargin: 4 - color: _rowHover.hovered ? NS.ThemeService.base02 : "transparent" - radius: NS.ThemeService.radius - z: -1 - } - - HoverHandler { - id: _rowHover + id: _restartBtn + anchors.right: parent.right + anchors.rightMargin: 8 + anchors.verticalCenter: parent.verticalCenter + width: 24 + height: 24 + opacity: _rowHover.hovered ? 1 : 0 + Behavior on opacity { + NumberAnimation { + duration: 80 + } } Text { - anchors.left: parent.left - anchors.leftMargin: 12 - anchors.right: _subStateTag.left - anchors.rightMargin: 6 - anchors.verticalCenter: parent.verticalCenter - text: root.unitName - color: NS.ThemeService.base05 - font.pixelSize: NS.ThemeService.fontSize - 1 - font.family: NS.ThemeService.fontFamily - elide: Text.ElideRight - } - - Rectangle { - id: _subStateTag - anchors.right: _restartBtn.left - anchors.rightMargin: 6 - anchors.verticalCenter: parent.verticalCenter - color: NS.ThemeService.base08 - opacity: 0.85 - radius: 3 - width: _subStateLbl.width + 8 - height: 14 - - Text { - id: _subStateLbl - anchors.centerIn: parent - text: root.subState - color: NS.ThemeService.base00 - font.pixelSize: NS.ThemeService.fontSize - 3 - font.family: NS.ThemeService.fontFamily - } - } - - // Restart button -  = fa-refresh - Item { - id: _restartBtn - anchors.right: _expandBtn.left - anchors.rightMargin: 2 - anchors.verticalCenter: parent.verticalCenter - width: 24 - height: 24 - - Text { - anchors.centerIn: parent - text: "" - color: _rHover.hovered ? root.accentColor : NS.ThemeService.base04 - font.pixelSize: NS.ThemeService.fontSize - font.family: NS.ThemeService.iconFontFamily - Behavior on color { - ColorAnimation { - duration: 80 - } - } - } - - HoverHandler { - id: _rHover - cursorShape: Qt.PointingHandCursor - } - TapHandler { - onTapped: { - root._doRestart(); - if (root._expanded) { - root._jText = ""; - Qt.callLater(root._fetchJournal); - } + anchors.centerIn: parent + text: "" + color: _rHover.hovered ? root.accentColor : NS.ThemeService.base04 + font.pixelSize: NS.ThemeService.fontSize + font.family: NS.ThemeService.iconFontFamily + Behavior on color { + ColorAnimation { + duration: 80 } } } - // Expand chevron -  = fa-chevron-down,  = fa-chevron-up - Item { - id: _expandBtn - anchors.right: parent.right - anchors.rightMargin: 4 - anchors.verticalCenter: parent.verticalCenter - width: 24 - height: 24 - - Text { - anchors.centerIn: parent - text: root._expanded ? "" : "" - color: _expHover.hovered ? root.accentColor : NS.ThemeService.base04 - font.pixelSize: NS.ThemeService.fontSize - 1 - font.family: NS.ThemeService.iconFontFamily - Behavior on color { - ColorAnimation { - duration: 80 - } - } - } - - HoverHandler { - id: _expHover - cursorShape: Qt.PointingHandCursor - } - TapHandler { - onTapped: { - root._expanded = !root._expanded; - if (root._expanded && root._jText === "") - root._fetchJournal(); - } - } + HoverHandler { + id: _rHover + cursorShape: Qt.PointingHandCursor } - } - - // Journal area - Item { - id: _journalArea - anchors.top: _row.bottom - width: parent.width - height: 120 - visible: root._expanded - clip: true - - Rectangle { - anchors.fill: parent - anchors.leftMargin: 8 - anchors.rightMargin: 8 - anchors.bottomMargin: 4 - color: NS.ThemeService.base01 - radius: NS.ThemeService.radius - - Text { - anchors.centerIn: parent - visible: root._loading - text: "loading..." - color: NS.ThemeService.base04 - font.pixelSize: NS.ThemeService.fontSize - 2 - font.family: NS.ThemeService.fontFamily - } - - Flickable { - id: _flick - anchors.fill: parent - anchors.margins: 6 - visible: !root._loading - contentHeight: _jContent.height - clip: true - - Text { - id: _jContent - width: _flick.width - text: root._jText - color: NS.ThemeService.base04 - font.pixelSize: NS.ThemeService.fontSize - 3 - font.family: NS.ThemeService.fontFamily - wrapMode: Text.WrapAnywhere - } - - onContentHeightChanged: contentY = Math.max(0, contentHeight - height) - } + TapHandler { + enabled: _rowHover.hovered + onTapped: S.SystemdService.restartUnit(root.unitName, root.scope, root.machineName) } } } diff --git a/shell/applets/qmldir b/shell/applets/qmldir index 355dd6a..d1908e6 100644 --- a/shell/applets/qmldir +++ b/shell/applets/qmldir @@ -10,7 +10,6 @@ GpuApplet 1.0 GpuApplet.qml HexWaveBackground 1.0 HexWaveBackground.qml HoverableListItem 1.0 HoverableListItem.qml InfoRow 1.0 InfoRow.qml -MachinectlApplet 1.0 MachinectlApplet.qml MemoryApplet 1.0 MemoryApplet.qml MprisApplet 1.0 MprisApplet.qml NetworkApplet 1.0 NetworkApplet.qml @@ -19,6 +18,7 @@ PowerApplet 1.0 PowerApplet.qml Separator 1.0 Separator.qml SparklineCanvas 1.0 SparklineCanvas.qml SystemdApplet 1.0 SystemdApplet.qml +SystemdMachineSection 1.0 SystemdMachineSection.qml SystemdUnitRow 1.0 SystemdUnitRow.qml TemperatureApplet 1.0 TemperatureApplet.qml VolumeApplet 1.0 VolumeApplet.qml diff --git a/shell/modules/Bar.qml b/shell/modules/Bar.qml index 36af284..21a9009 100644 --- a/shell/modules/Bar.qml +++ b/shell/modules/Bar.qml @@ -187,7 +187,6 @@ PanelWindow { M.WeatherModule {} M.DiskModule {} M.SystemdModule {} - M.MachinectlModule {} } // Power + Dock diff --git a/shell/modules/MachinectlModule.qml b/shell/modules/MachinectlModule.qml deleted file mode 100644 index 6fa8197..0000000 --- a/shell/modules/MachinectlModule.qml +++ /dev/null @@ -1,47 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import "." as M -import "../services" as S -import "../applets" as C -import NovaStats as NS - -M.BarModule { - id: root - active: NS.ModulesService.machinectlEnable - tooltip: { - const n = S.MachinectlService.machines.length; - return n === 0 ? "no containers" : n + " container" + (n === 1 ? "" : "s"); - } - panelNamespace: "nova-machinectl" - panelContentWidth: 320 - panelComponent: Component { - C.MachinectlApplet { - width: parent.width - accentColor: root.accentColor - active: root._showPanel - } - } - - Connections { - target: S.MachinectlService - function onMachineReady() { - root.keepPanelOpen(300); - } - } - - readonly property color _stateColor: S.MachinectlService.anyUnhealthy ? NS.ThemeService.base0A : root.accentColor - - M.BarIcon { - icon: "" - color: root._stateColor - anchors.verticalCenter: parent.verticalCenter - } - M.BarLabel { - label: S.MachinectlService.machines.length.toString() - minText: "9" - color: root._stateColor - anchors.verticalCenter: parent.verticalCenter - } -} diff --git a/shell/modules/SystemdModule.qml b/shell/modules/SystemdModule.qml index b558592..582bcaf 100644 --- a/shell/modules/SystemdModule.qml +++ b/shell/modules/SystemdModule.qml @@ -1,7 +1,6 @@ pragma ComponentBehavior: Bound import QtQuick -import Quickshell import "." as M import "../services" as S import "../applets" as C @@ -11,12 +10,11 @@ M.BarModule { id: root active: NS.ModulesService.systemdEnable tooltip: { - const sys = S.SystemdService.systemState; - const fc = S.SystemdService.totalFailedCount; - return "systemd: " + sys + (fc > 0 ? " (" + fc + " failed)" : ""); + const fc = S.SystemdService.failedCount; + return fc === 0 ? "systemd: ok" : "systemd: " + fc + " failed"; } panelNamespace: "nova-systemd" - panelContentWidth: 300 + panelContentWidth: 320 panelComponent: Component { C.SystemdApplet { width: parent.width @@ -28,22 +26,12 @@ M.BarModule { Connections { target: S.SystemdService - function onSystemUnitsChanged() { - root.keepPanelOpen(300); - } - function onUserUnitsChanged() { + function onFailedUnitsChanged() { root.keepPanelOpen(300); } } - readonly property color _stateColor: { - const st = S.SystemdService.systemState; - if (st === "running") - return root.accentColor; - if (st === "degraded") - return NS.ThemeService.base0A; - return NS.ThemeService.base08; - } + readonly property color _stateColor: S.SystemdService.failedCount > 0 ? NS.ThemeService.base0A : root.accentColor M.BarIcon { icon: "" @@ -51,8 +39,8 @@ M.BarModule { anchors.verticalCenter: parent.verticalCenter } M.BarLabel { - label: S.SystemdService.totalFailedCount > 0 ? S.SystemdService.totalFailedCount + " failed" : S.SystemdService.systemState - minText: "degraded" + label: S.SystemdService.failedCount > 0 ? S.SystemdService.failedCount + " failed" : "ok" + minText: "0 failed" color: root._stateColor anchors.verticalCenter: parent.verticalCenter } diff --git a/shell/modules/qmldir b/shell/modules/qmldir index fbdec44..87c86df 100644 --- a/shell/modules/qmldir +++ b/shell/modules/qmldir @@ -16,7 +16,6 @@ DockModule 1.0 DockModule.qml GpuModule 1.0 GpuModule.qml HoverPanel 1.0 HoverPanel.qml IdleInhibitorModule 1.0 IdleInhibitorModule.qml -MachinectlModule 1.0 MachinectlModule.qml MemoryModule 1.0 MemoryModule.qml MprisModule 1.0 MprisModule.qml NetworkModule 1.0 NetworkModule.qml diff --git a/shell/services/MachinectlService.qml b/shell/services/MachinectlService.qml deleted file mode 100644 index 30a39f0..0000000 --- a/shell/services/MachinectlService.qml +++ /dev/null @@ -1,152 +0,0 @@ -pragma Singleton - -import QtQuick -import Quickshell.Io -import "." as S -import NovaStats as NS - -QtObject { - id: root - - property var machines: [] - - // cache: machineName -> {state, units, loading} - property var _cache: ({}) - - readonly property bool anyUnhealthy: { - for (const k of Object.keys(_cache)) { - if ((_cache[k]?.units?.length ?? 0) > 0) - return true; - } - return false; - } - - function machineState(name) { - return _cache[name]?.state ?? "unknown"; - } - function machineUnits(name) { - return _cache[name]?.units ?? []; - } - function machineLoading(name) { - return _cache[name]?.loading ?? false; - } - - signal machineReady(string machineName, string state, var units) - signal machineJournalReady(string machineName, string unitName, string text) - - // Per-call state: kept on root (not on the inline Process objects) so qmllint can see them. - property string _machineName: "" - property string _journalMachine: "" - property string _journalUnit: "" - property string _restartMachine: "" - - function fetchMachine(name) { - const c = Object.assign({}, _cache); - c[name] = Object.assign({}, c[name] ?? {}, { - loading: true - }); - _cache = c; - - root._machineName = name; - _machineProc.command = ["sh", "-c", "busctl get-property --json=short --machine=" + name + " org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager SystemState 2>/dev/null || echo '{}'; " + "busctl call --json=short --machine=" + name + " org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager ListUnitsFiltered as 1 failed 2>/dev/null || echo '{}'"]; - if (_machineProc.running) - _machineProc.running = false; - _machineProc.running = true; - } - - function fetchMachineJournal(machineName, unitName) { - root._journalMachine = machineName; - root._journalUnit = unitName; - _machineJournalProc.command = ["journalctl", "-M", machineName, "-u", unitName, "-n", "80", "--no-pager", "--output=short-precise"]; - if (_machineJournalProc.running) - _machineJournalProc.running = false; - _machineJournalProc.running = true; - } - - function restartMachineUnit(machineName, unitName) { - root._restartMachine = machineName; - _machineRestartProc.command = ["pkexec", "systemctl", "-M", machineName, "restart", unitName]; - if (_machineRestartProc.running) - _machineRestartProc.running = false; - _machineRestartProc.running = true; - } - - property Timer _poll: Timer { - interval: NS.ModulesService.machinectlInterval ?? 15000 - running: NS.ModulesService.machinectlEnable - repeat: true - triggeredOnStart: true - onTriggered: if (!root._listProc.running) - root._listProc.running = true - } - - property Process _listProc: Process { - command: ["busctl", "call", "--json=short", "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", "ListMachines"] - stdout: StdioCollector { - onStreamFinished: { - try { - const parsed = JSON.parse(text.trim()); - const newMachines = (parsed.data?.[0] || []).map(m => ({ - name: m[0], - class: m[1], - service: m[2] - })); - root.machines = newMachines; - // drop stale cache entries - const names = new Set(newMachines.map(m => m.name)); - const c = {}; - for (const k of Object.keys(root._cache)) { - if (names.has(k)) - c[k] = root._cache[k]; - } - root._cache = c; - } catch (e) { - root.machines = []; - } - } - } - } - - // 2 lines of output: state, failed-units - property Process _machineProc: Process { - stdout: StdioCollector { - onStreamFinished: { - const lines = text.trim().split("\n"); - let state = "unknown"; - let units = []; - try { - state = JSON.parse(lines[0] ?? "").data || "unknown"; - } catch (e) {} - try { - const parsed = JSON.parse(lines[1] ?? ""); - units = (parsed.data?.[0] || []).map(u => ({ - name: u[0], - description: u[1], - loadState: u[2], - activeState: u[3], - subState: u[4] - })); - } catch (e) {} - const c = Object.assign({}, root._cache); - c[root._machineName] = { - state: state, - units: units, - loading: false - }; - root._cache = c; - root.machineReady(root._machineName, state, units); - } - } - } - - property Process _machineJournalProc: Process { - stdout: StdioCollector { - onStreamFinished: root.machineJournalReady(root._journalMachine, root._journalUnit, text) - } - } - - property Process _machineRestartProc: Process { - onRunningChanged: if (!running && root._restartMachine !== "") - root.fetchMachine(root._restartMachine) - } -} diff --git a/shell/services/SystemdService.qml b/shell/services/SystemdService.qml index afe9fcc..4ba5f38 100644 --- a/shell/services/SystemdService.qml +++ b/shell/services/SystemdService.qml @@ -1,100 +1,53 @@ pragma Singleton import QtQuick -import Quickshell.Io -import "." as S import NovaStats as NS +// Thin wrapper around NS.SystemdService: drives the poll Timer and parses the +// JSON-encoded list properties into JS arrays for QML consumers. Restart helper +// proxies through to the Rust singleton. QtObject { id: root - property string systemState: "unknown" - property string userState: "unknown" - property var systemUnits: [] - property var userUnits: [] - readonly property int totalFailedCount: systemUnits.length + userUnits.length + readonly property string hostname: NS.SystemdService.hostname + readonly property string systemState: NS.SystemdService.systemState + readonly property string userState: NS.SystemdService.userState + readonly property int failedCount: NS.SystemdService.failedCount - signal journalReady(string unitName, bool isUser, string text) - - function refresh() { - if (!_pollProc.running) - _pollProc.running = true; - } - - // Per-fetch journal state: kept here (not on the Process) so qmllint can see them. - property string _journalUnitName: "" - property bool _journalIsUser: false - - function fetchJournal(unitName, isUser) { - _journalProc.command = isUser ? ["journalctl", "--user", "-u", unitName, "-n", "80", "--no-pager", "--output=short-precise"] : ["journalctl", "-u", unitName, "-n", "80", "--no-pager", "--output=short-precise"]; - root._journalUnitName = unitName; - root._journalIsUser = isUser; - if (_journalProc.running) - _journalProc.running = false; - _journalProc.running = true; - } - - function restartUnit(unitName, isUser) { - _restartProc.command = isUser ? ["systemctl", "--user", "restart", unitName] : ["pkexec", "systemctl", "restart", unitName]; - if (_restartProc.running) - _restartProc.running = false; - _restartProc.running = true; - } - - function _parseState(json) { + // Parsed [{ name, description, subState, scope, machine }, ...] + readonly property var failedUnits: { try { - return JSON.parse(json).data || "unknown"; - } catch (e) { - return "unknown"; - } - } - - function _parseUnits(json) { - try { - const parsed = JSON.parse(json); - return (parsed.data?.[0] || []).map(u => ({ - name: u[0], - description: u[1], - loadState: u[2], - activeState: u[3], - subState: u[4] - })); + return JSON.parse(NS.SystemdService.failedUnitsJson); } catch (e) { return []; } } - property Timer _poll: Timer { - interval: NS.ModulesService.systemdInterval ?? 15000 + // Parsed [{ name, class, service, systemState, failedUnits: [...] }, ...] + readonly property var containers: { + try { + return JSON.parse(NS.SystemdService.containersJson); + } catch (e) { + return []; + } + } + + function restartUnit(name, scope, machine) { + NS.SystemdService.restartUnit(name, scope ?? "system", machine ?? ""); + } + + function refresh() { + NS.SystemdService.poll(); + } + + property Timer _pollTimer: Timer { + interval: { + const ms = NS.ModulesService.systemdInterval; + return ms > 0 ? ms : 15000; + } running: NS.ModulesService.systemdEnable repeat: true - triggeredOnStart: true - onTriggered: if (!root._pollProc.running) - root._pollProc.running = true - } - - // 4 lines of output: systemState, systemUnits, userState, userUnits - property Process _pollProc: Process { - command: ["sh", "-c", "busctl get-property --json=short org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager SystemState 2>/dev/null || echo '{}'; " + "busctl call --json=short org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager ListUnitsFiltered as 1 failed 2>/dev/null || echo '{}'; " + "busctl --user get-property --json=short org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager SystemState 2>/dev/null || echo '{}'; " + "busctl --user call --json=short org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager ListUnitsFiltered as 1 failed 2>/dev/null || echo '{}'"] - stdout: StdioCollector { - onStreamFinished: { - const lines = text.trim().split("\n"); - root.systemState = root._parseState(lines[0] ?? ""); - root.systemUnits = root._parseUnits(lines[1] ?? ""); - root.userState = root._parseState(lines[2] ?? ""); - root.userUnits = root._parseUnits(lines[3] ?? ""); - } - } - } - - property Process _journalProc: Process { - stdout: StdioCollector { - onStreamFinished: root.journalReady(root._journalUnitName, root._journalIsUser, text) - } - } - - property Process _restartProc: Process { - onRunningChanged: if (!running) - root.refresh() + triggeredOnStart: false + onTriggered: NS.SystemdService.poll() } } diff --git a/shell/services/qmldir b/shell/services/qmldir index 6169b75..59bfa3d 100644 --- a/shell/services/qmldir +++ b/shell/services/qmldir @@ -8,7 +8,6 @@ singleton CpuService 1.0 CpuService.qml singleton DockState 1.0 DockState.qml singleton IdleInhibitService 1.0 IdleInhibitService.qml singleton LockService 1.0 LockService.qml -singleton MachinectlService 1.0 MachinectlService.qml singleton MprisService 1.0 MprisService.qml singleton NetworkService 1.0 NetworkService.qml singleton NiriIpc 1.0 NiriIpc.qml diff --git a/test/qmllint-baseline.txt b/test/qmllint-baseline.txt index 79d3638..0baf41e 100644 --- a/test/qmllint-baseline.txt +++ b/test/qmllint-baseline.txt @@ -36,14 +36,6 @@ shell/applets/HexWaveBackground.qml: Type "QColor" of property "base0E" not foun shell/applets/HoverableListItem.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] shell/applets/InfoRow.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] shell/applets/InfoRow.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] -shell/applets/MachinectlApplet.qml: Type "QColor" of property "base00" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] -shell/applets/MachinectlApplet.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] -shell/applets/MachinectlApplet.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] -shell/applets/MachinectlApplet.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] -shell/applets/MachinectlApplet.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] -shell/applets/MachinectlApplet.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] -shell/applets/MachinectlApplet.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] -shell/applets/MachinectlApplet.qml: Type "QColor" of property "base0B" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] shell/applets/MemoryApplet.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] shell/applets/MemoryApplet.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] shell/applets/MemoryApplet.qml: Type "QColor" of property "base0D" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] @@ -78,13 +70,14 @@ shell/applets/PowerApplet.qml: Type "QColor" of property "base0D" not found. Thi shell/applets/PowerApplet.qml: Type "QColor" of property "base0E" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] shell/applets/PowerApplet.qml: Unqualified access [unqualified] shell/applets/Separator.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] -shell/applets/SystemdApplet.qml: Type "QColor" of property "base00" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] -shell/applets/SystemdApplet.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] -shell/applets/SystemdApplet.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] -shell/applets/SystemdApplet.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] -shell/applets/SystemdApplet.qml: Type "QColor" of property "base0B" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] +shell/applets/SystemdMachineSection.qml: Type "QColor" of property "base00" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] +shell/applets/SystemdMachineSection.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] +shell/applets/SystemdMachineSection.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] +shell/applets/SystemdMachineSection.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] +shell/applets/SystemdMachineSection.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] +shell/applets/SystemdMachineSection.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] +shell/applets/SystemdMachineSection.qml: Type "QColor" of property "base0B" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] shell/applets/SystemdUnitRow.qml: Type "QColor" of property "base00" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] -shell/applets/SystemdUnitRow.qml: Type "QColor" of property "base01" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] shell/applets/SystemdUnitRow.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] shell/applets/SystemdUnitRow.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] shell/applets/SystemdUnitRow.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] @@ -182,7 +175,6 @@ shell/modules/HoverPanel.qml: Type PanelWindow is not creatable. [uncreatable-ty shell/modules/HoverPanel.qml: Type margins is used but it is not resolved [unresolved-type] shell/modules/HoverPanel.qml: unknown grouped property scope margins. [unqualified] shell/modules/IdleInhibitorModule.qml: Type "QColor" of property "base09" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] -shell/modules/MachinectlModule.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] shell/modules/MemoryModule.qml: Unqualified access [unqualified] shell/modules/MprisModule.qml: Unqualified access [unqualified] shell/modules/NetworkModule.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] @@ -218,7 +210,6 @@ shell/modules/ScreenCorners.qml: Type PanelWindow is not creatable. [uncreatable shell/modules/ScreenCorners.qml: Type margins is used but it is not resolved [unresolved-type] shell/modules/ScreenCorners.qml: Unqualified access [unqualified] shell/modules/ScreenCorners.qml: unknown grouped property scope margins. [unqualified] -shell/modules/SystemdModule.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] shell/modules/SystemdModule.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] shell/modules/TemperatureModule.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] shell/modules/TemperatureModule.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]