looker-open-source / embed-sdk

The Looker browser embedding SDK
MIT License
72 stars 47 forks source link

Unable to get event handlers working #156

Closed Jack-Barry closed 1 year ago

Jack-Barry commented 1 year ago

When setting up dashboards or looks with an SSO embed URL using LookerEmbedSDK.createLookWithUrl or LookerEmbedSDK.createDashboardWithUrl, none of the event handlers seem to do anything in our app. The embed loads just fine and renders a report, but nothing gets logged to console, even with something where all of the documented event types are handled:

const logEventForDebugging = (event) => { console.log(event) }

LookerEmbedSDK.createDashboardWithUrl(url)
  .appendTo("report")
  .withClassName("looker-embed")
  .withNext()
  .withFilters({})
  .on("dashboard:run:start", logEventForDebugging)
  .on("dashboard:run:complete", logEventForDebugging)
  .on("dashboard:filters:changed", logEventForDebugging)
  .on("dashboard:edit:start", logEventForDebugging)
  .on("dashboard:edit:cancel", logEventForDebugging)
  .on("dashboard:save:complete", logEventForDebugging)
  .on("dashboard:delete:complete", logEventForDebugging)
  .on("dashboard:tile:start", logEventForDebugging)
  .on("dashboard:tile:complete", logEventForDebugging)
  .on("dashboard:tile:download", logEventForDebugging)
  .on("dashboard:tile:explore", logEventForDebugging)
  .on("dashboard:tile:view", logEventForDebugging)
  .on("drillmenu:click", logEventForDebugging)
  .on("drillmodal:explore", logEventForDebugging)
  .on("explore:run:start", logEventForDebugging)
  .on("explore:run:complete", logEventForDebugging)
  .on("explore:ready", logEventForDebugging)
  .on("explore:state:changed", logEventForDebugging)
  .on("look:run:start", logEventForDebugging)
  .on("look:run:complete", logEventForDebugging)
  .on("look:save:complete", logEventForDebugging)
  .on("look:delete:complete", logEventForDebugging)
  .on("look:ready", logEventForDebugging)
  .on("look:state:changed", logEventForDebugging)
  .on("page:changed", logEventForDebugging)
  .on("page:properties:changed", logEventForDebugging)
  .on("session:token:request", logEventForDebugging)
  .on("session:status", logEventForDebugging)
  .on("env:client:dialog", logEventForDebugging)
  .build()
  .connect()
  .then((embed) => {
    // do stuff with embed
  })
  .catch((error) => {
    // handle error
  });

Is there anything we could be doing wrong/missing that prevents those event handlers from being invoked?

williamtsoi1 commented 1 year ago

+1 on this, I've been battling this for the last week too!

Here's my bit of code, looks fairly similar to yours:

LookerEmbedSDK.createDashboardWithId(1)
      .appendTo(document.getElementById("dashboard"))
      .withClassName("embeddedDashboard")
      .on("dashboard:loaded", (e) => {
        console.log(
          "LookerEmbedSDK.createDashboardWithId()::Successfully Loaded!"
        );
      })
      .on("page:properties:changed", (e) => {
        pagePropertiesChangedHandler(e, el);
      })
      .on("dashboard:run:start", (e) => {
        console.log("Dashboard started");
      })
      .on("dashboard:run:complete", (e) => {
        console.log("Dashboard complete");
      })
      .build()
      .connect()
      .then((dashboard) => {
        setDashboardEmbedded(true);
        console.log("LookerEmbedSDK.createDashboardWithId()::Connected!");
      })
      .catch((error) => {
        console.error("An unexpected error occurred", error);
      });
williamtsoi1 commented 1 year ago

I actually resolved this by looking at this comment from another issue.

I needed to add a .withApiHost( ... ) and then it started working for me. I can't find this anywhere in the SDK docs which was a bit frustrating to be honest

Jack-Barry commented 1 year ago

I saw the .withApiHost() comment before opening this issue, and gave it a shot, but no luck. I wonder if it's a difference between createDashboardWithId vs. createDashboardWithUrl (creating with ID vs. URL)

jarrettch commented 1 year ago

I believe I'm running into a similar issue. I'm trying to resize the iFrame dynamically so that our Looker dashboard doesn't have a y scrollbar. I'm using .createDashboardWithUrl and attempting to use the .withDynamicIFrameHeight helper. I also tried using version 1.8.2 but this snippet from the docs didn't work:

  const pagePropertiesChangedHandler = ({height}, id) => {
    if (height && height > 100) {
      const el = document.querySelector(`#${id} iframe`)
      if (el) {
        el.style.height = `${height}px`;
      }
    }
  };

    LookerEmbedSDK.createDashboardWithUrl(url)
      .on('page:properties:changed', (event) => {
        pagePropertiesChangedHandler(event, 'dashboard')
      })
      .appendTo('#dashboard')
      .build()
      .connect()

I haven't found a workaround yet. Curious if you got things working @Jack-Barry ?

Jack-Barry commented 1 year ago

@jarrettch I haven't found anything yet, but still need to double-verify some things in our Looker configuration. There's quite a few moving parts for us, so I need to make sure this isn't just an issue because it's running on localhost vs. one of our other allowed domains

Also, I don't know yet if creating by ID absolutely has to be done first before calling create by URL, if that is maybe related to this issue. We generate the signed URL entirely via a backend service for all reports, so creating by ID on the frontend (AFAIK) is not viable for us. The docs say something here, so I donno if there's some magic done when creating by ID that is required for the event handlers to work properly

williamtsoi1 commented 1 year ago

A few things to check:

  1. Have you set the Embedded Domain Allowlist in your Looker instance? This is often overlooked for development environments such as https://localhost:3000. Note that the protocol http/https as well as port number needs to be exact.
  2. Have you ran LookerEmbedSDK.init('looker.example.com', '/auth'), ensuring that the domain of your Looker instance is set correctly? In my situation I found out that I was supposed to be loading it from an environment variable but it wasn't working properly and so the domain passed into the init() function was undefined.
  3. Assuming that the iframe renders correctly, then the /auth reference should not be a problem, else you would not be able to get the embedded URL.
  4. If you're using React, ensure that LookerEmbedSDK.createDashboardWithUrl() is run from inside a useEffect() hook (docs here). Here is a full React component that works and all the events are fired into the browser console:
import React, { useCallback, useEffect, useRef } from "react";
import styled from "styled-components";
import { LookerEmbedSDK } from "@looker/embed-sdk";

const LookerEmbedDashboard = () => {
  const [dashboardEmbedded, setDashboardEmbedded] = React.useState(false);
  const dashboardRef = useRef(false);
  useEffect(() => {
    if (dashboardRef.current) return;
    dashboardRef.current = true;
    makeDashboard();
  }, []);

  let makeDashboard = async () => {
    // LookerEmbedSDK.init(...) is already run at the page level
    LookerEmbedSDK.createDashboardWithId(1)
      .withDynamicIFrameHeight()
      .appendTo(document.getElementById("dashboard"))
      .withClassName("embeddedDashboard")
      .on("dashboard:loaded", (e) => {
        console.log(
          "LookerEmbedSDK.createDashboardWithId()::Successfully Loaded!"
        );
      })
      .on("dashboard:run:start", (e) => {
        console.log("Dashboard started");
        console.log(e.dashboard.dashboard_filters);
      })
      .on("dashboard:run:complete", (e) => {
        console.log("Dashboard complete");
      })
      .build()
      .connect()
      .then((dashboard) => {
        setDashboardEmbedded(true);
        console.log("LookerEmbedSDK.createDashboardWithId()::Connected!");
      })
      .catch((error) => {
        console.error("An unexpected error occurred", error);
      });
  };

  return (
    <>
      <Dashboard id="dashboard"></Dashboard>
    </>
  );
};

// A little bit of style here for heights and widths.
const Dashboard = styled.div`
  width: 100%;
  height: 100vh;
  min-height: 100vh;
  > iframe {
    width: 100%;
    height: 100%;
  }
`;

export default LookerEmbedDashboard;
Jack-Barry commented 1 year ago

Thanks @williamtsoi1, turns out step 1 was the missing part for us