Skip to content

Instantly share code, notes, and snippets.

@alexohneander
Forked from malesfth/widget_grafana.js
Created April 16, 2021 12:57
Show Gist options
  • Save alexohneander/12d9207671b7e5ed6b7569a24a9bf44f to your computer and use it in GitHub Desktop.
Save alexohneander/12d9207671b7e5ed6b7569a24a9bf44f to your computer and use it in GitHub Desktop.
iOS Scriptable Widget for Grafana
// Parameters:
// {"url":"http://grafana","bearer":"123abc"}
// Optional key in parameters: "theme": system|light|dark|grafana
let grafanaURL = "" //set the URL here for debug
let grafanaBearer = "" // set the API-key here for debug
let wTheme = "system" // set the theme for debug
if (config.runsInWidget) {
const widgetParams = (args.widgetParameter != null ? JSON.parse(args.widgetParameter) : null)
if (widgetParams==null) {
throw new Error("Please long press the widget and add the parameters.")
} else if (!widgetParams.hasOwnProperty("url") && !widgetParams.hasOwnProperty("bearer")) {
throw new Error("Wrong parameters.")
}
grafanaURL = widgetParams.url
grafanaBearer = widgetParams.bearer
if (widgetParams.hasOwnProperty("theme")) {
wTheme = widgetParams.theme
}
}
let wBackground = new LinearGradient()
let wColor = new Color("#ffffff")
let wColorOk = null
let wColorAlert = null
let wColorNeutral = null
setTheme()
let grafanaData = await fetchData()
let wSize = config.widgetFamily || "small" //set size of widget for debug
let widget = await createWidget() || null
if (!config.runsInWidget) {
if (wSize=="large") { await widget.presentLarge() }
else if (wSize=="medium") { await widget.presentMedium() }
else { await widget.presentSmall() }
}
Script.setWidget(widget)
Script.complete()
async function createWidget() {
let w = new ListWidget()
w.backgroundGradient = wBackground
const grafanaOK = (SFSymbol.named("suit.heart.fill")).image
const grafanaAlerting = (SFSymbol.named("heart.slash.fill")).image
const grafanaIMGpaused = (SFSymbol.named("pause")).image
const grafanaIMGnodata = (SFSymbol.named("questionmark")).image
const grafanaIMGpending = (SFSymbol.named("arrowshape.turn.up.right")).image
let content = w.addText("Grafana")
content.font = Font.blackSystemFont(16)
content.textColor = wColor
content.centerAlignText()
if (grafanaData==null) {
w.addSpacer();
content = w.addText("No connection")
content.font = Font.mediumSystemFont(12)
content.textColor = wColor
content.centerAlignText()
w.addSpacer()
return w
}
w.url = grafanaURL
let grafanaIsHealthyStr = "ok"
let grafanaIsHealthy = true
let grafanaHealth = {ok: 0, alerting: 0, paused: 0, pending: 0, no_data: 0}
for(var i = 0; i < grafanaData.length; i++) {
grafanaHealth[grafanaData[i].state] += 1
}
if (grafanaHealth.alerting>0) {
grafanaIsHealthy = false
grafanaIsHealthyStr = "alerting"
}
w.addSpacer(15);
if (wSize=="large") {
let maxRows = 6
let notShown = 0
let wStack = w.addStack()
wStack.centerAlignContent()
wStack.layoutVertically()
wStack.setPadding(5, 20, 0, 20)
for(var i = 0; i < grafanaData.length; i++) {
let gAlert = grafanaData[i]
let layoutStack = null
let rightStack = null
let img = null
let colr = wColorNeutral
switch(gAlert.state) {
case "ok":
img = grafanaOK
colr = wColorOk
break;
case "alerting":
img = grafanaAlerting
colr = wColorAlert
break;
case "paused":
img = grafanaIMGpaused
break;
case "pending":
img = grafanaIMGpending
break;
default:
img = grafanaIMGnodata
break;
}
if(i<maxRows) {
layoutStack = wStack.addStack()
layoutStack.centerAlignContent()
content = layoutStack.addImage(img)
content.imageSize = new Size(28,28)
content.tintColor = colr
layoutStack.addSpacer(15)
content = layoutStack.addText(gAlert.name)
content.font = Font.boldSystemFont(11)
content.textColor = wColor
wStack.addSpacer()
} else if (i==maxRows) {
notShown++
}
}
if (notShown>0) {
layoutStack = w.addStack()
layoutStack.setPadding(20, 0, 0, 20);
content = layoutStack.addText("+"+notShown+" more")
content.font = Font.boldSystemFont(11)
content.textColor = wColor
content.rightAlignText()
}
w.addSpacer()
} else if (wSize=="medium") {
let wStack = w.addStack()
wStack.centerAlignContent()
wStack.setPadding(5, 20, 0, 20);
let layoutStack = wStack.addStack()
layoutStack.centerAlignContent()
content = layoutStack.addImage(grafanaOK)
content.imageSize = new Size(32,32)
content.tintColor = wColorOk
content.centerAlignImage()
layoutStack.addSpacer(12)
content = layoutStack.addText((grafanaHealth.ok).toString())
content.font = Font.mediumSystemFont(16)
content.textColor = wColor
content.centerAlignText()
layoutStack = wStack.addStack()
layoutStack.centerAlignContent()
layoutStack.addSpacer()
content = layoutStack.addImage(grafanaAlerting)
content.imageSize = new Size(32,32)
content.tintColor = wColorAlert
content.centerAlignImage()
layoutStack.addSpacer(12)
content = layoutStack.addText((grafanaHealth.alerting).toString())
content.font = Font.mediumSystemFont(16)
content.textColor = wColor
content.centerAlignText()
layoutStack = wStack.addStack()
layoutStack.centerAlignContent()
layoutStack.addSpacer()
content = layoutStack.addImage(grafanaIMGpaused)
content.imageSize = new Size(32,32)
content.tintColor = wColorNeutral
content.centerAlignImage()
layoutStack.addSpacer(12)
content = layoutStack.addText((grafanaHealth.paused).toString())
content.font = Font.mediumSystemFont(16)
content.textColor = wColor
content.centerAlignText()
wStack = w.addStack()
wStack.centerAlignContent()
wStack.setPadding(20, 0, 0, 20)
layoutStack = wStack.addStack()
layoutStack.centerAlignContent()
layoutStack.addSpacer()
content = layoutStack.addImage(grafanaIMGpending)
content.imageSize = new Size(32,32)
content.tintColor = wColorNeutral
content.centerAlignImage()
layoutStack.addSpacer(12)
content = layoutStack.addText((grafanaHealth.pending).toString())
content.font = Font.mediumSystemFont(16)
content.textColor = wColor
content.centerAlignText()
layoutStack = wStack.addStack()
layoutStack.centerAlignContent()
layoutStack.addSpacer()
content = layoutStack.addImage(grafanaIMGnodata)
content.imageSize = new Size(32,32)
content.tintColor = wColorNeutral
content.centerAlignImage()
layoutStack.addSpacer(12)
content = layoutStack.addText((grafanaHealth.no_data).toString())
content.font = Font.mediumSystemFont(16)
content.textColor = wColor
content.centerAlignText()
layoutStack.addSpacer()
} else {
w.addSpacer()
content = w.addImage((grafanaIsHealthy ? grafanaOK : grafanaAlerting))
content.imageSize = new Size(52,52)
content.tintColor = (grafanaIsHealthy ? wColorOk : wColorAlert)
content.centerAlignImage()
w.addSpacer(5)
content = w.addText(grafanaIsHealthyStr.toUpperCase())
content.font = Font.mediumSystemFont(10)
content.textColor = (grafanaIsHealthy ? wColorOk : wColorAlert)
content.centerAlignText()
w.addSpacer()
}
w.addSpacer()
return w
}
function setTheme() {
wColorOk = Color.green()
wColorAlert = Color.red()
wColorNeutral = Color.gray()
if (wTheme=="system") {
if (Device.isUsingDarkAppearance()) {
wTheme = "dark"
} else {
wTheme = "white"
}
}
wBackground.locations = [0, 1]
if (wTheme=="grafana") {
wBackground.colors = [
Color.red(),
Color.yellow()
]
wColor = new Color("#ffffff")
wColorOk = Color.white()
wColorAlert = Color.white()
wColorNeutral = Color.white()
} else if (wTheme=="dark") {
wBackground.colors = [
new Color("#212121e6"),
new Color("#212121")
]
wColor = new Color("#ffffff")
} else {
wBackground.colors = [
new Color("#ffffffe6"),
new Color("#ffffff")
]
wColor = new Color("#000000")
}
}
async function fetchData() {
try {
let req = new Request(grafanaURL + "/api/alerts/")
req.headers = {"Authorization": "Bearer "+grafanaBearer}
let json = await req.loadJSON()
return json
} catch {
return null
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment