Skip to content

Conversation

@nicomiguelino
Copy link
Contributor

@nicomiguelino nicomiguelino commented Jan 16, 2026

PR Type

Enhancement


Description

  • Parse embed URL or iframe snippet

  • Load dashboard in full-screen iframe

  • Auto-refresh dashboard at set interval

  • Add HTML, CSS, scripts, and manifest


Diagram Walkthrough

flowchart LR
  Settings["Get settings (`embed_url`, `refresh_interval`)"]
  Extract["extractUrlFromEmbedSetting"]
  Load["Load URL into iframe"]
  Onload["iframe.onload event"]
  Ready["signalReady"]
  Timer["setupRefreshTimer"]
  Settings --> Extract
  Extract --> Load
  Load --> Onload
  Onload --> Ready
  Onload --> Timer
  Timer --> Load
Loading

File Walkthrough

Relevant files
Enhancement
2 files
main.ts
Implement iframe embed and auto-refresh logic                       
+67/-0   
index.html
Add HTML template for Looker Studio dashboard                       
+22/-0   
Formatting
1 files
style.css
Add full-screen iframe styling                                                     
+19/-0   
Configuration changes
3 files
.ignore
Ignore node_modules directory                                                       
+1/-0     
screenly.yml
Define manifest and settings schema                                           
+26/-0   
screenly_qc.yml
Add QC manifest configuration                                                       
+26/-0   
Documentation
1 files
README.md
Add deployment and configuration instructions                       
+31/-0   
Dependencies
1 files
package.json
Configure dependencies and build scripts                                 
+35/-0   

- Add embed_url setting to accept Looker Studio URLs or iframe embed code
- Parse iframe HTML snippets to extract src attribute
- Add refresh_interval setting (default: 60 seconds)
@github-actions
Copy link

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Setting Type Mismatch

The refresh_interval setting is declared as type string in the manifest but retrieved as a number in code, which may lead to unexpected type coercion or runtime errors.

const embedSettingValue = getSettingWithDefault<string>('embed_url', '')
const refreshInterval = getSettingWithDefault<number>('refresh_interval', 60)
const embedUrl = extractUrlFromEmbedSetting(embedSettingValue)
Documentation Outdated

README still references a message setting with default "Hello, Mars!" that isn’t used by this app; update docs to reflect the actual embed_url and refresh_interval settings.

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

- `message` - The message to display on the screen (defaults to "Hello, Mars!")

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new Edge App for displaying Looker Studio dashboards. The app embeds Looker Studio content via an iframe with configurable URL and auto-refresh functionality.

Changes:

  • New Looker Studio Edge App with iframe-based dashboard embedding
  • Auto-refresh capability with configurable interval
  • URL extraction from iframe embed code snippets

Reviewed changes

Copilot reviewed 9 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
edge-apps/looker-studio/static/img/icon.svg SVG icon for the Looker Studio app
edge-apps/looker-studio/src/main.ts Core functionality for iframe loading and refresh logic
edge-apps/looker-studio/src/css/style.css Styling for fullscreen iframe display
edge-apps/looker-studio/screenly_qc.yml QC manifest configuration
edge-apps/looker-studio/screenly.yml Production manifest configuration
edge-apps/looker-studio/package.json Package dependencies and build scripts
edge-apps/looker-studio/index.html HTML structure with iframe element
edge-apps/looker-studio/bun.lock Lockfile for dependencies
edge-apps/looker-studio/README.md Documentation for deployment and configuration
edge-apps/looker-studio/.ignore Screenly ignore patterns
edge-apps/looker-studio/.gitignore Git ignore patterns

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


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

- `message` - The message to display on the screen (defaults to "Hello, Mars!")
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation incorrectly references a message setting. Based on the manifest files, the actual settings are embed_url and refresh_interval. This should be updated to reflect the correct configuration options.

Suggested change
- `message` - The message to display on the screen (defaults to "Hello, Mars!")
- `embed_url` - The Looker Studio embed URL to display on the screen.
- `refresh_interval` - How often to refresh the embed (in seconds).

Copilot uses AI. Check for mistakes.
type: string
schema_version: 1
refresh_interval:
type: string
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The refresh_interval setting has type 'string' but the code in main.ts expects a number and performs numerical operations (line 22 uses it as number, line 57 multiplies by 1000). The type should be 'number' to match the code's expectations.

Suggested change
type: string
type: number

Copilot uses AI. Check for mistakes.
src="about:blank"
width="100%"
height="100%"
frameborder="0"
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The frameborder attribute is deprecated in HTML5. Use CSS border: none; instead, which is already applied in the stylesheet.

Suggested change
frameborder="0"

Copilot uses AI. Check for mistakes.
@github-actions
Copy link

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Security
Sanitize and validate embed URL

Validate and sanitize the extracted URL to ensure it’s well-formed and uses a secure
protocol before assigning it to the iframe src, preventing invalid or insecure URLs
from being used.

edge-apps/looker-studio/src/main.ts [9-18]

 function extractUrlFromEmbedSetting(settingValue: string): string | null {
+  let urlValue: string | null = null
   if (settingValue.includes('<iframe')) {
     const match = settingValue.match(/<iframe.*?src=["'](.*?)["']/)
-    if (match && match[1]) {
-      return match[1]
-    }
+    urlValue = match && match[1] ? match[1] : null
+  } else {
+    urlValue = settingValue
+  }
+  if (!urlValue) {
     return null
   }
-  return settingValue
+  try {
+    const parsed = new URL(urlValue)
+    if (parsed.protocol !== 'https:') {
+      console.error('Embed URL must use HTTPS')
+      return null
+    }
+    return parsed.toString()
+  } catch {
+    console.error('Embed URL is not a valid URL')
+    return null
+  }
 }
Suggestion importance[1-10]: 8

__

Why: Validating the URL format and enforcing https: prevents invalid or insecure URLs from being loaded in the iframe, improving security.

Medium
Possible issue
Parse refresh interval correctly

The refresh_interval setting is defined as a string in the manifest, so you should
parse it into a number to avoid type mismatches. Use parseInt with a fallback to
ensure it’s always numeric.

edge-apps/looker-studio/src/main.ts [22]

-const refreshInterval = getSettingWithDefault<number>('refresh_interval', 60)
+const refreshIntervalStr = getSettingWithDefault<string>('refresh_interval', '60')
+const refreshInterval = parseInt(refreshIntervalStr, 10) || 0
Suggestion importance[1-10]: 6

__

Why: The setting refresh_interval is defined as a string in the manifest but retrieved as a number, so parsing it ensures type consistency and prevents runtime mismatches.

Low

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant