OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
 
main @ 482 LINES
 
[ HISTORY ]  [ UP ]
 

import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Wayland

// right slide-out pane showing the tailnet machines from ooknet-monitor.
// full-screen overlay so it can dim + click-away to close; the panel translates
// in from the right edge.
PanelWindow {
    id: win
    visible: Monitor.open || panel.x < win.width
    color: "transparent"
    WlrLayershell.layer: WlrLayer.Overlay
    WlrLayershell.namespace: "ookshell-dashboard"
    WlrLayershell.keyboardFocus: WlrKeyboardFocus.None

    // iso (2026-09-30...) -> au dd/mm/yyyy
    function fmtDate(iso) {
        if (!iso)
            return "";
        const p = iso.slice(0, 10).split("-"); // [yyyy, mm, dd]
        return p.length === 3 ? p[2] + "/" + p[1] + "/" + p[0] : iso.slice(0, 10);
    }
    function isExpired(iso) {
        return !!iso && new Date(iso).getTime() < Date.now();
    }
    function fmtUptime(s) {
        if (!s)
            return "";
        const d = Math.floor(s / 86400), h = Math.floor(s % 86400 / 3600);
        if (d > 0)
            return d + "d";
        if (h > 0)
            return h + "h";
        return Math.floor(s / 60) + "m";
    }
    // iso ts -> compact relative age (now / 5m / 3h / 2d), else short date
    function notifTime(iso) {
        if (!iso)
            return "";
        const s = Math.floor((Date.now() - new Date(iso).getTime()) / 1000);
        if (s < 60)
            return "now";
        if (s < 3600)
            return Math.floor(s / 60) + "m";
        if (s < 86400)
            return Math.floor(s / 3600) + "h";
        if (s < 604800)
            return Math.floor(s / 86400) + "d";
        return fmtDate(iso);
    }
    // strip unicode directional-isolate chars (discord uses them) so they don't r
ender as boxes
    function clean(t) {
        return (t || "").replace(/[\u2066-\u2069]/g, "");
    }
    // nerd glyph per os. this fleet's linux boxes are all nixos
    function osGlyph(os) {
        switch ((os || "").toLowerCase()) {
        case "linux":
            return "?"; // nixos
        case "macos":
            return "?"; // apple
        case "android":
            return "?"; // android
        case "windows":
            return "?"; // windows
        default:
            return "?"; // generic device
        }
    }

    anchors {
        top: true
        bottom: true
        left: true
        right: true
    }
    exclusiveZone: -1 // span the full screen (ignore the bar's reserved zone) so 
the dim covers the top too

    // dim backdrop, click anywhere to dismiss
    Rectangle {
        anchors.fill: parent
        color: "#000000"
        opacity: Monitor.open ? 0.35 : 0
        Behavior on opacity {
            NumberAnimation {
                duration: 200
            }
        }
        MouseArea {
            anchors.fill: parent
            onClicked: Monitor.open = false
        }
    }

    Rectangle {
        id: panel
        width: Config.dashWidth
        // inset by the hyprland window gap on top/bottom/right so it aligns with
        // tiled windows; wears the shared window frame (rounding/border)
        // window now spans from screen top, so clear the bar (flush below it, lik
e a tiled window)
        anchors.top: parent.top
        anchors.topMargin: Config.barMarginTop + Config.barHeight
        anchors.bottom: parent.bottom
        anchors.bottomMargin: Config.dashGap
        x: Monitor.open ? parent.width - width - Config.dashGap : parent.width
        Behavior on x {
            NumberAnimation {
                duration: 240
                easing.type: Easing.OutCubic
            }
        }

        clip: true
        color: Config.bg
        radius: Config.frameRounding
        border.color: Config.frameBorder
        border.width: Config.frameBorderWidth

        MouseArea {
            anchors.fill: parent // swallow clicks so they don't hit the backdrop
        }

        ColumnLayout {
            anchors.fill: parent
            anchors.margins: Config.barPadding
            spacing: Config.barSpacing

            // header
            RowLayout {
                Layout.fillWidth: true
                Text {
                    Layout.fillWidth: true
                    text: Monitor.view
                    font.family: Config.fontFamily
                    font.pixelSize: Config.fontSize + 3
                    font.bold: true
                    color: Config.text
                }
                Text {
                    text: Monitor.view === "notifications" ? NotifHistory.items.le
ngth + " logged" : Monitor.view === "services" ? Monitor.services.filter(s => s.st
atus === "up").length + "/" + Monitor.services.length + " up" : [].concat(Monitor.
machines).filter(m => m.online).length + "/" + Monitor.machines.length + " up"
                    font.family: Config.fontFamily
                    font.pixelSize: Config.fontSize - 2
                    color: Config.text
                    opacity: 0.6
                }
            }

            Rectangle {
                Layout.fillWidth: true
                Layout.preferredHeight: 1
                color: Config.border
            }

            // machines view
            ListView {
                visible: Monitor.view === "machines"
                Layout.fillWidth: true
                Layout.fillHeight: true
                clip: true
                spacing: 6
                model: Monitor.machines

                delegate: Rectangle {
                    id: card
                    required property var modelData
                    width: ListView.view.width
                    implicitHeight: cardCol.implicitHeight + 16
                    radius: 6
                    color: Qt.rgba(1, 1, 1, 0.04)
                    border.width: 1
                    border.color: Config.border

                    RowLayout {
                        anchors.fill: parent
                        anchors.margins: 8
                        spacing: 8

                        Rectangle {
                            Layout.alignment: Qt.AlignTop
                            Layout.topMargin: 4
                            width: 9
                            height: 9
                            radius: 4.5
                            color: card.modelData.online ? Config.batGood : Config
.urgent
                        }

                        ColumnLayout {
                            id: cardCol
                            Layout.fillWidth: true
                            spacing: 2

                            RowLayout {
                                Layout.fillWidth: true
                                Text {
                                    text: card.modelData.hostname ?? "?"
                                    font.family: Config.fontFamily
                                    font.pixelSize: Config.fontSize
                                    font.bold: true
                                    color: Config.text
                                }
                                Item {
                                    Layout.fillWidth: true
                                }
                                Text {
                                    text: win.osGlyph(card.modelData.os)
                                    font.family: Config.fontFamily
                                    font.pixelSize: Config.fontSize
                                    color: Config.text
                                    opacity: 0.7
                                }
                            }

                            Text {
                                text: card.modelData.ip ?? ""
                                font.family: Config.fontFamily
                                font.pixelSize: Config.fontSize - 2
                                color: Config.text
                                opacity: 0.55
                            }

                            // host data from ssh (kernel ? uptime), nixos hosts o
nly
                            Text {
                                visible: !!card.modelData.kernel
                                text: (card.modelData.kernel ?? "") + (card.modelD
ata.uptimeSec ? "  ?  up " + win.fmtUptime(card.modelData.uptimeSec) : "")
                                font.family: Config.fontFamily
                                font.pixelSize: Config.fontSize - 3
                                color: Config.text
                                opacity: 0.45
                            }

                            RowLayout {
                                Layout.fillWidth: true
                                spacing: 6
                                Text {
                                    visible: card.modelData.ssh === true
                                    text: "SSH"
                                    font.family: Config.fontFamily
                                    font.pixelSize: Config.fontSize - 4
                                    color: Config.primary
                                }
                                Text {
                                    visible: !!card.modelData.keyExpiry
                                    text: "exp " + win.fmtDate(card.modelData.keyE
xpiry)
                                    font.family: Config.fontFamily
                                    font.pixelSize: Config.fontSize - 4
                                    color: win.isExpired(card.modelData.keyExpiry)
 ? Config.urgent : Config.text
                                    opacity: win.isExpired(card.modelData.keyExpir
y) ? 0.9 : 0.45
                                }
                                Item {
                                    Layout.fillWidth: true
                                }
                                Text {
                                    visible: !card.modelData.online && !!card.mode
lData.lastSeen
                                    text: card.modelData.lastSeen ? "seen " + win.
fmtDate(card.modelData.lastSeen) : ""
                                    font.family: Config.fontFamily
                                    font.pixelSize: Config.fontSize - 4
                                    color: Config.text
                                    opacity: 0.45
                                }
                            }
                        }
                    }
                }
            }

            // services view
            ListView {
                visible: Monitor.view === "services"
                Layout.fillWidth: true
                Layout.fillHeight: true
                clip: true
                spacing: 6
                model: Monitor.services

                delegate: Rectangle {
                    id: svc
                    required property var modelData
                    property bool expanded: false
                    width: ListView.view.width
                    implicitHeight: svcCol.implicitHeight + 16
                    radius: 6
                    color: Qt.rgba(1, 1, 1, svc.expanded ? 0.07 : 0.04)
                    border.width: 1
                    border.color: Config.border
                    clip: true

                    Behavior on implicitHeight {
                        NumberAnimation {
                            duration: 130
                            easing.type: Easing.OutCubic
                        }
                    }

                    ColumnLayout {
                        id: svcCol
                        anchors.fill: parent
                        anchors.margins: 8
                        spacing: 6

                        RowLayout {
                            Layout.fillWidth: true
                            spacing: 10

                            Rectangle {
                                Layout.alignment: Qt.AlignVCenter
                                width: 9
                                height: 9
                                radius: 4.5
                                color: svc.modelData.status === "up" ? Config.batG
ood : svc.modelData.status === "degraded" ? Config.batWarn : Config.urgent
                            }

                            Text {
                                Layout.fillWidth: true
                                text: svc.modelData.name ?? "?"
                                elide: Text.ElideRight
                                font.family: Config.fontFamily
                                font.pixelSize: Config.fontSize
                                font.bold: true
                                color: Config.text
                            }

                            Text {
                                text: svc.modelData.detail ?? ""
                                font.family: Config.fontFamily
                                font.pixelSize: Config.fontSize - 2
                                color: Config.text
                                opacity: 0.55
                            }

                            Text {
                                text: "?" // nf-fa-chevron-down
                                font.family: Config.fontFamily
                                font.pixelSize: Config.fontSize - 4
                                color: Config.text
                                opacity: 0.4
                                rotation: svc.expanded ? 180 : 0
                                Behavior on rotation {
                                    NumberAnimation {
                                        duration: 130
                                    }
                                }
                            }
                        }

                        // expanded detail: modelData.info key/values
                        ColumnLayout {
                            Layout.fillWidth: true
                            Layout.leftMargin: 19
                            spacing: 2
                            visible: svc.expanded
                            Repeater {
                                model: svc.expanded ? svc.modelData.info ?? [] : [
]
                                delegate: RowLayout {
                                    required property var modelData
                                    Layout.fillWidth: true
                                    spacing: 12
                                    Text {
                                        Layout.fillWidth: true
                                        text: modelData.key
                                        elide: Text.ElideRight
                                        font.family: Config.fontFamily
                                        font.pixelSize: Config.fontSize - 3
                                        color: Config.text
                                        opacity: 0.45
                                    }
                                    Text {
                                        Layout.maximumWidth: svc.width * 0.45
                                        text: modelData.value
                                        horizontalAlignment: Text.AlignRight
                                        elide: Text.ElideRight
                                        font.family: Config.fontFamily
                                        font.pixelSize: Config.fontSize - 3
                                        color: Config.text
                                        opacity: 0.7
                                    }
                                }
                            }
                        }
                    }

                    MouseArea {
                        anchors.fill: parent
                        onClicked: svc.expanded = !svc.expanded
                    }
                }
            }

            // notification history view
            ListView {
                visible: Monitor.view === "notifications"
                onVisibleChanged: if (visible)
                    NotifHistory.load()
                Layout.fillWidth: true
                Layout.fillHeight: true
                clip: true
                spacing: 6
                model: visible ? NotifHistory.items : []

                delegate: Rectangle {
                    id: note
                    required property var modelData
                    width: ListView.view.width
                    implicitHeight: noteCol.implicitHeight + 16
                    radius: 6
                    color: Qt.rgba(1, 1, 1, 0.04)
                    border.width: 1
                    border.color: Config.border

                    RowLayout {
                        anchors.fill: parent
                        anchors.margins: 8
                        spacing: 8

                        // urgency dot: critical -> urgent, low -> dim, else good
                        Rectangle {
                            Layout.alignment: Qt.AlignTop
                            Layout.topMargin: 4
                            width: 9
                            height: 9
                            radius: 4.5
                            color: note.modelData.urgency === "critical" ? Config.
urgent : Config.text
                            opacity: note.modelData.urgency === "low" ? 0.3 : 1
                        }

                        ColumnLayout {
                            id: noteCol
                            Layout.fillWidth: true
                            spacing: 2

                            RowLayout {
                                Layout.fillWidth: true
                                Text {
                                    Layout.fillWidth: true
                                    text: win.clean(note.modelData.app) || "?"
                                    elide: Text.ElideRight
                                    font.family: Config.fontFamily
                                    font.pixelSize: Config.fontSize - 2
                                    color: Config.primary
                                }
                                Text {
                                    text: win.notifTime(note.modelData.ts)
                                    font.family: Config.fontFamily
                                    font.pixelSize: Config.fontSize - 3
                                    color: Config.text
                                    opacity: 0.45
                                }
                            }

                            Text {
                                Layout.fillWidth: true
                                visible: !!text
                                text: win.clean(note.modelData.summary)
                                wrapMode: Text.Wrap
                                maximumLineCount: 2
                                elide: Text.ElideRight
                                font.family: Config.fontFamily
                                font.pixelSize: Config.fontSize
                                font.bold: true
                                color: Config.text
                            }

                            Text {
                                Layout.fillWidth: true
                                visible: !!text
                                text: win.clean(note.modelData.body)
                                wrapMode: Text.Wrap
                                maximumLineCount: 3
                                elide: Text.ElideRight
                                font.family: Config.fontFamily
                                font.pixelSize: Config.fontSize - 2
                                color: Config.text
                                opacity: 0.6
                            }
                        }
                    }
                }
            }
        }
    }
}

import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Wayland

// right slide-out pane showing the tailnet 
machines from ooknet-monitor.
// full-screen overlay so it can dim + click
-away to close; the panel translates
// in from the right edge.
PanelWindow {
    id: win
    visible: Monitor.open || panel.x < win.w
idth
    color: "transparent"
    WlrLayershell.layer: WlrLayer.Overlay
    WlrLayershell.namespace: "ookshell-dashb
oard"
    WlrLayershell.keyboardFocus: WlrKeyboard
Focus.None

    // iso (2026-09-30...) -> au dd/mm/yyyy
    function fmtDate(iso) {
        if (!iso)
            return "";
        const p = iso.slice(0, 10).split("-"
); // [yyyy, mm, dd]
        return p.length === 3 ? p[2] + "/" +
 p[1] + "/" + p[0] : iso.slice(0, 10);
    }
    function isExpired(iso) {
        return !!iso && new Date(iso).getTim
e() < Date.now();
    }
    function fmtUptime(s) {
        if (!s)
            return "";
        const d = Math.floor(s / 86400), h =
 Math.floor(s % 86400 / 3600);
        if (d > 0)
            return d + "d";
        if (h > 0)
            return h + "h";
        return Math.floor(s / 60) + "m";
    }
    // iso ts -> compact relative age (now /
 5m / 3h / 2d), else short date
    function notifTime(iso) {
        if (!iso)
            return "";
        const s = Math.floor((Date.now() - n
ew Date(iso).getTime()) / 1000);
        if (s < 60)
            return "now";
        if (s < 3600)
            return Math.floor(s / 60) + "m";
        if (s < 86400)
            return Math.floor(s / 3600) + "h
";
        if (s < 604800)
            return Math.floor(s / 86400) + "
d";
        return fmtDate(iso);
    }
    // strip unicode directional-isolate cha
rs (discord uses them) so they don't render 
as boxes
    function clean(t) {
        return (t || "").replace(/[\u2066-\u
2069]/g, "");
    }
    // nerd glyph per os. this fleet's linux
 boxes are all nixos
    function osGlyph(os) {
        switch ((os || "").toLowerCase()) {
        case "linux":
            return "?"; // nixos
        case "macos":
            return "?"; // apple
        case "android":
            return "?"; // android
        case "windows":
            return "?"; // windows
        default:
            return "?"; // generic device
        }
    }

    anchors {
        top: true
        bottom: true
        left: true
        right: true
    }
    exclusiveZone: -1 // span the full scree
n (ignore the bar's reserved zone) so the di
m covers the top too

    // dim backdrop, click anywhere to dismi
ss
    Rectangle {
        anchors.fill: parent
        color: "#000000"
        opacity: Monitor.open ? 0.35 : 0
        Behavior on opacity {
            NumberAnimation {
                duration: 200
            }
        }
        MouseArea {
            anchors.fill: parent
            onClicked: Monitor.open = false
        }
    }

    Rectangle {
        id: panel
        width: Config.dashWidth
        // inset by the hyprland window gap 
on top/bottom/right so it aligns with
        // tiled windows; wears the shared w
indow frame (rounding/border)
        // window now spans from screen top,
 so clear the bar (flush below it, like a ti
led window)
        anchors.top: parent.top
        anchors.topMargin: Config.barMarginT
op + Config.barHeight
        anchors.bottom: parent.bottom
        anchors.bottomMargin: Config.dashGap
        x: Monitor.open ? parent.width - wid
th - Config.dashGap : parent.width
        Behavior on x {
            NumberAnimation {
                duration: 240
                easing.type: Easing.OutCubic
            }
        }

        clip: true
        color: Config.bg
        radius: Config.frameRounding
        border.color: Config.frameBorder
        border.width: Config.frameBorderWidt
h

        MouseArea {
            anchors.fill: parent // swallow 
clicks so they don't hit the backdrop
        }

        ColumnLayout {
            anchors.fill: parent
            anchors.margins: Config.barPaddi
ng
            spacing: Config.barSpacing

            // header
            RowLayout {
                Layout.fillWidth: true
                Text {
                    Layout.fillWidth: true
                    text: Monitor.view
                    font.family: Config.font
Family
                    font.pixelSize: Config.f
ontSize + 3
                    font.bold: true
                    color: Config.text
                }
                Text {
                    text: Monitor.view === "
notifications" ? NotifHistory.items.length +
 " logged" : Monitor.view === "services" ? M
onitor.services.filter(s => s.status === "up
").length + "/" + Monitor.services.length + 
" up" : [].concat(Monitor.machines).filter(m
 => m.online).length + "/" + Monitor.machine
s.length + " up"
                    font.family: Config.font
Family
                    font.pixelSize: Config.f
ontSize - 2
                    color: Config.text
                    opacity: 0.6
                }
            }

            Rectangle {
                Layout.fillWidth: true
                Layout.preferredHeight: 1
                color: Config.border
            }

            // machines view
            ListView {
                visible: Monitor.view === "m
achines"
                Layout.fillWidth: true
                Layout.fillHeight: true
                clip: true
                spacing: 6
                model: Monitor.machines

                delegate: Rectangle {
                    id: card
                    required property var mo
delData
                    width: ListView.view.wid
th
                    implicitHeight: cardCol.
implicitHeight + 16
                    radius: 6
                    color: Qt.rgba(1, 1, 1, 
0.04)
                    border.width: 1
                    border.color: Config.bor
der

                    RowLayout {
                        anchors.fill: parent
                        anchors.margins: 8
                        spacing: 8

                        Rectangle {
                            Layout.alignment
: Qt.AlignTop
                            Layout.topMargin
: 4
                            width: 9
                            height: 9
                            radius: 4.5
                            color: card.mode
lData.online ? Config.batGood : Config.urgen
t
                        }

                        ColumnLayout {
                            id: cardCol
                            Layout.fillWidth
: true
                            spacing: 2

                            RowLayout {
                                Layout.fillW
idth: true
                                Text {
                                    text: ca
rd.modelData.hostname ?? "?"
                                    font.fam
ily: Config.fontFamily
                                    font.pix
elSize: Config.fontSize
                                    font.bol
d: true
                                    color: C
onfig.text
                                }
                                Item {
                                    Layout.f
illWidth: true
                                }
                                Text {
                                    text: wi
n.osGlyph(card.modelData.os)
                                    font.fam
ily: Config.fontFamily
                                    font.pix
elSize: Config.fontSize
                                    color: C
onfig.text
                                    opacity:
 0.7
                                }
                            }

                            Text {
                                text: card.m
odelData.ip ?? ""
                                font.family:
 Config.fontFamily
                                font.pixelSi
ze: Config.fontSize - 2
                                color: Confi
g.text
                                opacity: 0.5
5
                            }

                            // host data fro
m ssh (kernel ? uptime), nixos hosts only
                            Text {
                                visible: !!c
ard.modelData.kernel
                                text: (card.
modelData.kernel ?? "") + (card.modelData.up
timeSec ? "  ?  up " + win.fmtUptime(card.mo
delData.uptimeSec) : "")
                                font.family:
 Config.fontFamily
                                font.pixelSi
ze: Config.fontSize - 3
                                color: Confi
g.text
                                opacity: 0.4
5
                            }

                            RowLayout {
                                Layout.fillW
idth: true
                                spacing: 6
                                Text {
                                    visible:
 card.modelData.ssh === true
                                    text: "S
SH"
                                    font.fam
ily: Config.fontFamily
                                    font.pix
elSize: Config.fontSize - 4
                                    color: C
onfig.primary
                                }
                                Text {
                                    visible:
 !!card.modelData.keyExpiry
                                    text: "e
xp " + win.fmtDate(card.modelData.keyExpiry)
                                    font.fam
ily: Config.fontFamily
                                    font.pix
elSize: Config.fontSize - 4
                                    color: w
in.isExpired(card.modelData.keyExpiry) ? Con
fig.urgent : Config.text
                                    opacity:
 win.isExpired(card.modelData.keyExpiry) ? 0
.9 : 0.45
                                }
                                Item {
                                    Layout.f
illWidth: true
                                }
                                Text {
                                    visible:
 !card.modelData.online && !!card.modelData.
lastSeen
                                    text: ca
rd.modelData.lastSeen ? "seen " + win.fmtDat
e(card.modelData.lastSeen) : ""
                                    font.fam
ily: Config.fontFamily
                                    font.pix
elSize: Config.fontSize - 4
                                    color: C
onfig.text
                                    opacity:
 0.45
                                }
                            }
                        }
                    }
                }
            }

            // services view
            ListView {
                visible: Monitor.view === "s
ervices"
                Layout.fillWidth: true
                Layout.fillHeight: true
                clip: true
                spacing: 6
                model: Monitor.services

                delegate: Rectangle {
                    id: svc
                    required property var mo
delData
                    property bool expanded: 
false
                    width: ListView.view.wid
th
                    implicitHeight: svcCol.i
mplicitHeight + 16
                    radius: 6
                    color: Qt.rgba(1, 1, 1, 
svc.expanded ? 0.07 : 0.04)
                    border.width: 1
                    border.color: Config.bor
der
                    clip: true

                    Behavior on implicitHeig
ht {
                        NumberAnimation {
                            duration: 130
                            easing.type: Eas
ing.OutCubic
                        }
                    }

                    ColumnLayout {
                        id: svcCol
                        anchors.fill: parent
                        anchors.margins: 8
                        spacing: 6

                        RowLayout {
                            Layout.fillWidth
: true
                            spacing: 10

                            Rectangle {
                                Layout.align
ment: Qt.AlignVCenter
                                width: 9
                                height: 9
                                radius: 4.5
                                color: svc.m
odelData.status === "up" ? Config.batGood : 
svc.modelData.status === "degraded" ? Config
.batWarn : Config.urgent
                            }

                            Text {
                                Layout.fillW
idth: true
                                text: svc.mo
delData.name ?? "?"
                                elide: Text.
ElideRight
                                font.family:
 Config.fontFamily
                                font.pixelSi
ze: Config.fontSize
                                font.bold: t
rue
                                color: Confi
g.text
                            }

                            Text {
                                text: svc.mo
delData.detail ?? ""
                                font.family:
 Config.fontFamily
                                font.pixelSi
ze: Config.fontSize - 2
                                color: Confi
g.text
                                opacity: 0.5
5
                            }

                            Text {
                                text: "?" //
 nf-fa-chevron-down
                                font.family:
 Config.fontFamily
                                font.pixelSi
ze: Config.fontSize - 4
                                color: Confi
g.text
                                opacity: 0.4
                                rotation: sv
c.expanded ? 180 : 0
                                Behavior on 
rotation {
                                    NumberAn
imation {
                                        dura
tion: 130
                                    }
                                }
                            }
                        }

                        // expanded detail: 
modelData.info key/values
                        ColumnLayout {
                            Layout.fillWidth
: true
                            Layout.leftMargi
n: 19
                            spacing: 2
                            visible: svc.exp
anded
                            Repeater {
                                model: svc.e
xpanded ? svc.modelData.info ?? [] : []
                                delegate: Ro
wLayout {
                                    required
 property var modelData
                                    Layout.f
illWidth: true
                                    spacing:
 12
                                    Text {
                                        Layo
ut.fillWidth: true
                                        text
: modelData.key
                                        elid
e: Text.ElideRight
                                        font
.family: Config.fontFamily
                                        font
.pixelSize: Config.fontSize - 3
                                        colo
r: Config.text
                                        opac
ity: 0.45
                                    }
                                    Text {
                                        Layo
ut.maximumWidth: svc.width * 0.45
                                        text
: modelData.value
                                        hori
zontalAlignment: Text.AlignRight
                                        elid
e: Text.ElideRight
                                        font
.family: Config.fontFamily
                                        font
.pixelSize: Config.fontSize - 3
                                        colo
r: Config.text
                                        opac
ity: 0.7
                                    }
                                }
                            }
                        }
                    }

                    MouseArea {
                        anchors.fill: parent
                        onClicked: svc.expan
ded = !svc.expanded
                    }
                }
            }

            // notification history view
            ListView {
                visible: Monitor.view === "n
otifications"
                onVisibleChanged: if (visibl
e)
                    NotifHistory.load()
                Layout.fillWidth: true
                Layout.fillHeight: true
                clip: true
                spacing: 6
                model: visible ? NotifHistor
y.items : []

                delegate: Rectangle {
                    id: note
                    required property var mo
delData
                    width: ListView.view.wid
th
                    implicitHeight: noteCol.
implicitHeight + 16
                    radius: 6
                    color: Qt.rgba(1, 1, 1, 
0.04)
                    border.width: 1
                    border.color: Config.bor
der

                    RowLayout {
                        anchors.fill: parent
                        anchors.margins: 8
                        spacing: 8

                        // urgency dot: crit
ical -> urgent, low -> dim, else good
                        Rectangle {
                            Layout.alignment
: Qt.AlignTop
                            Layout.topMargin
: 4
                            width: 9
                            height: 9
                            radius: 4.5
                            color: note.mode
lData.urgency === "critical" ? Config.urgent
 : Config.text
                            opacity: note.mo
delData.urgency === "low" ? 0.3 : 1
                        }

                        ColumnLayout {
                            id: noteCol
                            Layout.fillWidth
: true
                            spacing: 2

                            RowLayout {
                                Layout.fillW
idth: true
                                Text {
                                    Layout.f
illWidth: true
                                    text: wi
n.clean(note.modelData.app) || "?"
                                    elide: T
ext.ElideRight
                                    font.fam
ily: Config.fontFamily
                                    font.pix
elSize: Config.fontSize - 2
                                    color: C
onfig.primary
                                }
                                Text {
                                    text: wi
n.notifTime(note.modelData.ts)
                                    font.fam
ily: Config.fontFamily
                                    font.pix
elSize: Config.fontSize - 3
                                    color: C
onfig.text
                                    opacity:
 0.45
                                }
                            }

                            Text {
                                Layout.fillW
idth: true
                                visible: !!t
ext
                                text: win.cl
ean(note.modelData.summary)
                                wrapMode: Te
xt.Wrap
                                maximumLineC
ount: 2
                                elide: Text.
ElideRight
                                font.family:
 Config.fontFamily
                                font.pixelSi
ze: Config.fontSize
                                font.bold: t
rue
                                color: Confi
g.text
                            }

                            Text {
                                Layout.fillW
idth: true
                                visible: !!t
ext
                                text: win.cl
ean(note.modelData.body)
                                wrapMode: Te
xt.Wrap
                                maximumLineC
ount: 3
                                elide: Text.
ElideRight
                                font.family:
 Config.fontFamily
                                font.pixelSi
ze: Config.fontSize - 2
                                color: Confi
g.text
                                opacity: 0.6
                            }
                        }
                    }
                }
            }
        }
    }
}
 
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET