import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kcmutils as KCM
import "Grafana.js" as G
// Which panels' values sit in the panel next to the logo. Any panel can be
// pinned; it shows its first series, reduced the way the panel reduces it.
KCM.SimpleKCM {
id: configPinned
property string cfg_pinned: "[]"
property string cfg_dashboards: "[]"
property string cfg_instanceUrl: ""
property string cfg_accessToken: ""
property alias cfg_pinnedLabels: labelsCheckBox.checked
readonly property var pinned: parse(cfg_pinned)
readonly property var dashboardsChosen: parse(cfg_dashboards)
property string browsing: ""
property var panels: []
property bool isLoading: false
property string loadError: ""
function parse(text) {
try {
var v = JSON.parse(text || "[]")
return Array.isArray(v) ? v : []
} catch (e) {
return []
}
}
GrafanaAPI {
id: api
baseUrl: configPinned.cfg_instanceUrl
accessToken: configPinned.cfg_accessToken
}
function browse(uid) {
browsing = uid
panels = []
if (!uid) return
isLoading = true
loadError = ""
api.dashboard(uid, function(ok, data) {
isLoading = false
if (!ok) { loadError = data; return }
panels = G.allPanels(data.dashboard).filter(function(p) { return p.type !== "text" && !p.repeat })
.map(function(p) { return { id: p.id, title: p.title || i18n("(untitled)"), type: p.type } })
})
}
function save(list) { cfg_pinned = JSON.stringify(list) }
function isPinned(uid, id) { return pinned.some(function(p) { return p.uid === uid && p.panelId === id }) }
function titleOf(uid) {
for (var i = 0; i < dashboardsChosen.length; i++) if (dashboardsChosen[i].uid === uid) return dashboardsChosen[i].title
return uid
}
function pin(p) {
if (isPinned(browsing, p.id)) return
save(pinned.concat([{ uid: browsing, panelId: p.id, title: p.title, dashboardTitle: titleOf(browsing) }]))
}
function removeAt(i) { var l = pinned.slice(); l.splice(i, 1); save(l) }
function move(i, delta) {
var t = i + delta
if (t < 0 || t >= pinned.length) return
var l = pinned.slice()
var item = l.splice(i, 1)[0]
l.splice(t, 0, item)
save(l)
}
function setLabel(i, label) {
var l = pinned.slice()
l[i] = Object.assign({}, l[i], { label: label })
if (!label) delete l[i].label
save(l)
}
Component.onCompleted: if (dashboardsChosen.length) browse(dashboardsChosen[0].uid)
ColumnLayout {
spacing: Kirigami.Units.largeSpacing
Kirigami.Heading {
level: 3
text: i18n("Pinned to the panel")
}
QQC2.Label {
visible: pinned.length === 0
Layout.fillWidth: true
wrapMode: Text.WordWrap
opacity: 0.7
text: i18n("Nothing pinned: the panel shows just the logo. Pin a stat (or any panel) below to keep its value in view.")
}
Repeater {
model: pinned
delegate: RowLayout {
required property var modelData
required property int index
Layout.fillWidth: true
spacing: Kirigami.Units.smallSpacing
Kirigami.Icon {
source: "window-pin"
Layout.preferredWidth: Kirigami.Units.iconSizes.small
Layout.preferredHeight: Kirigami.Units.iconSizes.small
}
QQC2.Label {
Layout.fillWidth: true
elide: Text.ElideRight
text: modelData.title + " · " + (modelData.dashboardTitle || modelData.uid)
}
QQC2.TextField {
Layout.preferredWidth: Kirigami.Units.gridUnit * 7
placeholderText: i18n("Label")
text: modelData.label || ""
onEditingFinished: if (text !== (modelData.label || "")) setLabel(index, text)
QQC2.ToolTip.text: i18n("Shown above the value instead of the panel title")
QQC2.ToolTip.visible: hovered
}
QQC2.ToolButton { icon.name: "go-up"; enabled: index > 0; onClicked: move(index, -1) }
QQC2.ToolButton { icon.name: "go-down"; enabled: index < pinned.length - 1; onClicked: move(index, 1) }
QQC2.ToolButton { icon.name: "list-remove"; onClicked: removeAt(index) }
}
}
QQC2.CheckBox {
id: labelsCheckBox
text: i18n("Show titles above the values in a horizontal panel")
}
Kirigami.Heading {
level: 3
text: i18n("Panels")
}
QQC2.Label {
visible: dashboardsChosen.length === 0
Layout.fillWidth: true
wrapMode: Text.WordWrap
opacity: 0.7
text: i18n("Add dashboards on the General page first.")
}
RowLayout {
visible: dashboardsChosen.length > 0
Layout.fillWidth: true
QQC2.ComboBox {
id: dashPicker
Layout.fillWidth: true
model: dashboardsChosen
textRole: "title"
onActivated: function(i) { browse(dashboardsChosen[i].uid) }
}
QQC2.BusyIndicator {
visible: isLoading
Layout.preferredWidth: Kirigami.Units.iconSizes.smallMedium
Layout.preferredHeight: Kirigami.Units.iconSizes.smallMedium
}
}
QQC2.Label {
visible: loadError !== ""
Layout.fillWidth: true
wrapMode: Text.WordWrap
color: Kirigami.Theme.negativeTextColor
text: loadError
}
Repeater {
model: panels
delegate: RowLayout {
required property var modelData
Layout.fillWidth: true
Kirigami.Icon {
source: modelData.type === "stat" ? "format-number-percent"
: modelData.type === "timeseries" ? "office-chart-line"
: modelData.type === "table" ? "table" : "office-chart-bar"
Layout.preferredWidth: Kirigami.Units.iconSizes.small
Layout.preferredHeight: Kirigami.Units.iconSizes.small
}
QQC2.Label {
Layout.fillWidth: true
elide: Text.ElideRight
text: modelData.title + " <font color=\"" + Kirigami.Theme.disabledTextColor + "\">" + modelData.type + "</font>"
textFormat: Text.StyledText
}
QQC2.Button {
text: isPinned(browsing, modelData.id) ? i18n("Pinned") : i18n("Pin")
icon.name: isPinned(browsing, modelData.id) ? "checkmark" : "window-pin"
enabled: !isPinned(browsing, modelData.id)
onClicked: pin(modelData)
}
}
}
}
}
neiam
/grafana-plasmoid
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
Log in to mark this repository.
7.2 KiB · text
History
7a88816