5.8 KiB · text History 7a88816
import QtQuick
import QtQuick.Layouts
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.components as PlasmaComponents3
import org.kde.kirigami as Kirigami

import "Grafana.js" as G

// One panel: a card with its title, description, error and loading state,
// and the visualisation for its type underneath. The visualisation reads
// `series` / `result` from here rather than from the store, so it only
// recomputes when this panel's own data changes.
Rectangle {
    id: frame

    required property var store
    required property string uid
    required property var panel
    property var vars: ({})

    readonly property string key: store.panelKey(uid, panel.id)
    property var result: null
    readonly property var series: result && result.results ? G.seriesFromResults(result.results, panel) : []
    readonly property var range: result && result.range ? result.range : store.rangeFor(uid)
    readonly property bool loading: (store.dataRev, store.isLoading(uid, panel.id))
    readonly property string error: result && result.error ? String(result.error) : ""
    readonly property string title: G.panelTitle(panel, vars)
    readonly property bool transparent: !!panel.transparent

    function pull() {
        var r = store.resultFor(uid, panel.id)
        if (r !== result) result = r
    }

    Component.onCompleted: pull()
    Connections {
        target: frame.store
        function onDataRevChanged() { frame.pull() }
    }

    radius: Kirigami.Units.cornerRadius
    color: transparent ? "transparent" : Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.04)
    border.width: transparent ? 0 : 1
    border.color: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.12)
    clip: true

    // ── title ───────────────────────────────────────────────────────────
    RowLayout {
        id: header
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.top: parent.top
        anchors.margins: Kirigami.Units.smallSpacing
        height: titleLabel.implicitHeight
        spacing: Kirigami.Units.smallSpacing / 2
        visible: frame.title !== "" || frame.error !== "" || frame.loading

        PlasmaComponents3.Label {
            id: titleLabel
            Layout.fillWidth: true
            elide: Text.ElideRight
            font.bold: true
            font.pointSize: Kirigami.Theme.smallFont.pointSize
            text: frame.title
            horizontalAlignment: frame.panel.type === "stat" || frame.panel.type === "gauge" ? Text.AlignHCenter : Text.AlignLeft

            PlasmaCore.ToolTipArea {
                anchors.fill: parent
                active: !!frame.panel.description
                mainText: frame.title
                subText: frame.panel.description || ""
            }
        }

        PlasmaComponents3.BusyIndicator {
            visible: frame.loading
            running: visible
            Layout.preferredWidth: titleLabel.implicitHeight
            Layout.preferredHeight: titleLabel.implicitHeight
        }

        Kirigami.Icon {
            visible: frame.error !== ""
            source: "dialog-warning"
            color: Kirigami.Theme.negativeTextColor
            Layout.preferredWidth: titleLabel.implicitHeight
            Layout.preferredHeight: titleLabel.implicitHeight

            PlasmaCore.ToolTipArea {
                anchors.fill: parent
                mainText: i18n("Query error")
                subText: frame.error
            }
        }

        PlasmaComponents3.ToolButton {
            visible: hover.hovered
            icon.name: "internet-web-browser"
            Layout.preferredWidth: titleLabel.implicitHeight + 4
            Layout.preferredHeight: titleLabel.implicitHeight + 4
            onClicked: Qt.openUrlExternally(frame.store.api.dashboardUrl(frame.uid, frame.panel.id))
            PlasmaComponents3.ToolTip { text: i18n("View in Grafana") }
        }
    }

    HoverHandler { id: hover }

    // ── body ────────────────────────────────────────────────────────────
    Loader {
        id: body
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.top: header.visible ? header.bottom : parent.top
        anchors.bottom: parent.bottom
        anchors.margins: Kirigami.Units.smallSpacing
        anchors.topMargin: header.visible ? Kirigami.Units.smallSpacing / 2 : Kirigami.Units.smallSpacing

        source: {
            switch (frame.panel.type) {
            case "timeseries":
            case "graph": return "panels/TimeSeriesPanel.qml"
            case "stat":
            case "singlestat": return "panels/StatPanel.qml"
            case "gauge": return "panels/GaugePanel.qml"
            case "bargauge": return "panels/BarGaugePanel.qml"
            case "table": return "panels/TablePanel.qml"
            case "text": return "panels/TextPanel.qml"
            case "piechart": return "panels/PieChartPanel.qml"
            default: return "panels/UnsupportedPanel.qml"
            }
        }
        onLoaded: item.frame = frame
    }

    PlasmaComponents3.Label {
        anchors.centerIn: body
        visible: frame.result !== null && frame.series.length === 0 && frame.panel.type !== "text"
                 && frame.panel.type !== "table" && G.supported(frame.panel.type) && frame.error === ""
        opacity: 0.6
        text: frame.panel.options && frame.panel.fieldConfig && frame.panel.fieldConfig.defaults
              && frame.panel.fieldConfig.defaults.noValue ? frame.panel.fieldConfig.defaults.noValue : i18n("No data")
    }
}