Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions edge-apps/looker-studio/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules/
dist/
*.log
.DS_Store
static/js/*.js
static/js/*.js.map
1 change: 1 addition & 0 deletions edge-apps/looker-studio/.ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
32 changes: 32 additions & 0 deletions edge-apps/looker-studio/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Looker Studio

## Deployment

Create and deploy the Edge App:

```bash
screenly edge-app create --name my-looker-studio --repository
screenly edge-app deploy
screenly edge-app instance create
```

## Configuration

The app accepts the following settings via `screenly.yml`:

- `embed_url` - The Looker Studio embed URL to display on the screen.
- `refresh_interval` - How often to refresh the embed (in seconds).

## Development

```bash
bun install # Install dependencies
bun run build # Build the app
bun test # Run tests
```

## Testing

```bash
bun test
```
394 changes: 394 additions & 0 deletions edge-apps/looker-studio/bun.lock

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions edge-apps/looker-studio/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Looker Studio App</title>
<script src="screenly.js?version=1"></script>
<link rel="stylesheet" href="dist/css/style.css" />
</head>
<body>
<iframe
id="looker-studio-iframe"
title="Looker Studio Dashboard"
src="about:blank"
width="100%"
height="100%"
allowfullscreen
></iframe>
<script src="dist/js/main.js"></script>
</body>
</html>
35 changes: 35 additions & 0 deletions edge-apps/looker-studio/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "looker-studio",
"version": "1.0.0",
"devDependencies": {
"@screenly/edge-apps": "workspace:../edge-apps-library",
"@types/bun": "^1.3.6",
"@types/jsdom": "^27.0.0",
"@types/qrcode": "^1.5.6",
"bun-types": "^1.3.6",
"jsdom": "^27.4.0",
"npm-run-all2": "^8.0.4",
"prettier": "^3.8.0",
"typescript": "^5.9.3"
},
"prettier": "../edge-apps-library/.prettierrc.json",
"scripts": {
"prebuild": "bun run type-check",
"generate-mock-data": "screenly edge-app run --generate-mock-data",
"predev": "bun run generate-mock-data && edge-apps-scripts build",
"dev": "run-p build:dev edge-app-server",
"edge-app-server": "screenly edge-app run",
"build": "edge-apps-scripts build",
"build:dev": "edge-apps-scripts build:dev",
"build:prod": "edge-apps-scripts build",
"test": "bun test",
"test:unit": "bun test",
"lint": "edge-apps-scripts lint --fix",
"format": "prettier --write src/ README.md index.html",
"format:check": "prettier --check src/ README.md index.html",
"deploy": "bun run build && screenly edge-app deploy",
"type-check": "edge-apps-scripts type-check",
"prepare": "cd ../edge-apps-library && bun install && bun run build"
},
"type": "module"
}
26 changes: 26 additions & 0 deletions edge-apps/looker-studio/screenly.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
syntax: manifest_v1
description: Looker Studio edge app for displaying dashboards
icon: https://playground.srly.io/edge-apps/looker-studio/static/img/icon.svg
author: Screenly, Inc.
ready_signal: true
settings:
embed_url:
type: string
title: Embed URL
optional: false
help_text:
properties:
help_text: Enter the Looker Studio embed URL or paste the full iframe embed code.
type: string
schema_version: 1
refresh_interval:
type: string
default_value: '60'
title: Refresh Interval (seconds)
optional: true
help_text:
properties:
help_text: How often to refresh the dashboard in seconds. Set to 0 to disable auto-refresh.
type: number
schema_version: 1
26 changes: 26 additions & 0 deletions edge-apps/looker-studio/screenly_qc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
syntax: manifest_v1
description: Looker Studio edge app for displaying dashboards
icon: https://playground.srly.io/edge-apps/looker-studio/static/img/icon.svg
author: Screenly, Inc.
ready_signal: true
settings:
embed_url:
type: string
title: Embed URL
optional: false
help_text:
properties:
help_text: "Enter the Looker Studio embed URL or paste the full iframe embed code."
type: string
schema_version: 1
refresh_interval:
type: string
title: Refresh Interval (seconds)
default_value: 60
optional: true
help_text:
properties:
help_text: "How often to refresh the dashboard in seconds. Set to 0 to disable auto-refresh."
type: number
schema_version: 1
19 changes: 19 additions & 0 deletions edge-apps/looker-studio/src/css/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@import 'tailwindcss';

html,
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
}

#looker-studio-iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: none;
}
67 changes: 67 additions & 0 deletions edge-apps/looker-studio/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import './css/style.css'

import {
setupTheme,
getSettingWithDefault,
signalReady,
} from '@screenly/edge-apps'

function extractUrlFromEmbedSetting(settingValue: string): string | null {
if (settingValue.includes('<iframe')) {
const match = settingValue.match(/<iframe.*?src=["'](.*?)["']/)
if (match && match[1]) {
return match[1]
}
return null
}
return settingValue
}

window.onload = function () {
const embedSettingValue = getSettingWithDefault<string>('embed_url', '')
const refreshInterval = getSettingWithDefault<number>('refresh_interval', 60)
const embedUrl = extractUrlFromEmbedSetting(embedSettingValue)
const iframeElement = document.getElementById(
'looker-studio-iframe',
) as HTMLIFrameElement | null

// Setup branding colors using the library
setupTheme()

if (!iframeElement) {
console.error('Iframe element not found')
signalReady()
return
}

if (!embedUrl) {
console.error('Embed URL not configured or invalid')
signalReady()
return
}

let refreshTimer: number | null = null

const loadIframe = () => {
iframeElement.src = embedUrl
}

const setupRefreshTimer = () => {
if (refreshTimer) {
clearInterval(refreshTimer)
}

if (refreshInterval > 0) {
refreshTimer = window.setInterval(() => {
loadIframe()
}, refreshInterval * 1000)
}
}

iframeElement.onload = () => {
signalReady()
setupRefreshTimer()
}

loadIframe()
}
1 change: 1 addition & 0 deletions edge-apps/looker-studio/static/img/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.