Skip to content

Instantly share code, notes, and snippets.

@marcantoine
Last active June 13, 2022 08:15
Show Gist options
  • Save marcantoine/bedbb41189a8384b9ecf635fbd5fa67b to your computer and use it in GitHub Desktop.
Save marcantoine/bedbb41189a8384b9ecf635fbd5fa67b to your computer and use it in GitHub Desktop.
showMetabaseQuestiontAsiOSWidget.js
// Modified from @mutsuda's https://medium.com/@mutsuda/create-an-ios-widget-showing-google-spreadsheets-data-856767a9447e
// and @levelsio's https://gist.github.com/levelsio/a1ca0dd434b77ef26f6a7c403beff4d0
// HOW TO
// 1) Make a new Metabase Question
// 2) Make the result an unique number and choose Visualization > Number
// 3) Write your metabase domain, your email and password below
const domain = "https://metabase.endpoint.com"
const username = "[email protected]"
const password = "p@ssw0rd"
// 4) copy the id of the question below. The ID can be found in the url of the question /question/42
const question = '42'
// 5) Install Scriptable @ https://apps.apple.com/us/app/scriptable/id1405459188
// 6) Copy this entire script in to Scriptable (tip: you can send it to your iPhone via Whatsapp/Messenger/Telegram etc)
// 7) Add a widget on your Home screen, choose scriptable and select your new script.
// 8) Style the widget - you can change the text font / size / color, the background, and also add image using base64
// function to connect to metabase with email and password
async function getSessionId() {
let req = new Request(domain+'/api/session')
req.method = "POST"
req.headers = { 'Content-Type': 'application/json'}
req.body = JSON.stringify({username, password})
let res = await req.loadJSON()
return res.id
}
// function to retrieve data from a Question based on its number
async function getCardData(card, id){
let req = new Request(endpoint+'/api/card/'+card+'/query')
req.method = 'POST'
req.headers = { 'X-Metabase-Session': id}
req.body = {ignore_caches: true, parameters: []}
let res = await req.loadJSON()
return res.data.rows[0][0];
}
const id = await getSessionId() // we get the session id
const data = await getCardData(question,id) // we get the result from question 42
const value = data.toLocaleString() // transform the number in a nice locale string
let w = new ListWidget() // Create the widget
w.backgroundColor = new Color("#132660")
w.url= "https://url.com" // an url to open on click
t = w.addText(`${value} €`) // Add the value to the widget
t.textColor = new Color("#ffffff")
t.font = new Font("AvenirNext-DemiBold",42)
// add a small subtext
t2 = w.addText(`Invested this month`)
t2.textColor = new Color("#F0F3F8")
t2.font = new Font("AvenirNext-DemiBold",14)
// add a small spacer
s = w.addSpacer(8)
// load an image from base64 to Data
let dataImg = Data.fromBase64String("iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAIOSURBVHgBxdHLaxNRGAXwM4/m0Yl5mUdtHrZUqiDEtgsRdOEDrSDqVgS7VQqC/gOiuFHpQhA3It24UAsq7cqAgq1QF5WCVEqCaUPrNJiMmUwmM8nM5E7GGaVZqCs3fovLdw/8uAcu8I9D/R7M3b+UZol4l2aY4xTFmKDop5oVunf+2uPyX+HazJ3Aejk32mlXngXC8bhnRwxWx4TWqKAuCisWopOZvYeXE2cvN7tw4dHEsPyVzKtUuS89OAhXbwhcMAaTGDCaMlqKgM1CCW7Su8UlgwdPXZ0u0Q6sCO0LIW+qjwvHEd49asMIZEmCorTAekIIJUfg4nyI+Ib6RbF2zDE/oU65P25UixgeOwpvIAqaoWF5/CC0Cz0uN3zxNPaMHMKmyEM3e0pdKPHqghlki95wAgznR1OtY8CunEyn0CZtMB4ffLEURLb1eeLW83eOYZ1j8uGM+uD6CeND9gV2JVIwNR08z4O0CRoCj3JVglQtQ6pJPEVRVvdF5/JNVPPrX1YxOzsH2ejANDQQokNUOnibfY3c6gpqivFp+xfY7UWqt54MJSPn1vgGtvgqXk29Acux2D++DzW5hXR/1BJk8vIPGPQzYw1VhyA2sxRN4+KNMyftuLm0XFj8Lmle07SOoCNn7GypW/XXQu20Ub5aV29fuTl9urChHMgV5czi/PtxVdOn7EZ5N0sP4L/NDz4x4196PfxhAAAAAElFTkSuQmCC");
let img = Image.fromData(dataImg) // Use the data to create an image
let image = w.addImage(img)
// align everyting
t2.centerAlignText()
t.centerAlignText()
image.centerAlignImage();
image.imageSize = new Size(20,20)
Script.setWidget(w)
Script.complete()
@0xcaff
Copy link

0xcaff commented Jan 25, 2021

This doesn't seem like it re-runs the query underlying the question, only gets the value at the last run. Quick change to the last part of this to get this to refresh the underlying query every time.

// function to retrieve data from a Question based on its number
async function getCardData(card, id){
  let req = new Request(domain+'/api/card/'+card+'/query')
  req.method = 'POST'
  req.headers = { 'X-Metabase-Session': id}
  req.body = {ignore_caches: true, parameters: []}
  let res = await req.loadJSON()
  return res.data.rows[0][0];
}

const id = await getSessionId() // we get the session id
const value = await getCardData(question,id) // we get the result from question 42

@marcantoine
Copy link
Author

Thank you @0xcaff, It makes senses, I’ve updated the gist !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment