Skip to content

Commit

Permalink
update react embed sample
Browse files Browse the repository at this point in the history
  • Loading branch information
pballai committed Nov 8, 2024
1 parent 7830cde commit 2b544a5
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 93 deletions.
7 changes: 0 additions & 7 deletions embed-sdk-react/docs/basic-examples/.env

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,29 +1,33 @@
// basic-example-wrapper.tsx
// The SignedIframe component is responsible for securely embedding a Sigma Computing dashboard into a React application.
// signEmbedUrl: This function is imported from the Sigma Embed SDK library and is used to generate a signed URL for secure access to a Sigma dashboard.
"use client"; // This directive tells Next.js to treat this as a Client Component

// Import the signEmbedUrl function from the utilities module
import { useEffect, useState } from "react";
import { signEmbedUrl } from "@/lib/utils";
// Import the BasicExample component, which is responsible for rendering the iframe
import BasicExample from "./basic-example-embed";

// Define an asynchronous component to sign the URL and render the iframe
export default async function SignedIframe() {
// Get the base URL from the environment variable
const src = process.env.EMBED_URL || ""; // Use the value from the .env file
export default function SignedIframe() {
const [signedSrc, setSignedSrc] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
const src = "https://app.sigmacomputing.com/embed/1-24vP6WRI5BK8C8dLX4kzac"; // Hardcoded URL as discussed

try {
// Await the signed URL by passing the base URL to the signEmbedUrl function
const signedSrc = await signEmbedUrl(src);
useEffect(() => {
const getSignedUrl = async () => {
try {
const signedUrl = await signEmbedUrl(src);
console.log("Signed URL:", signedUrl);
setSignedSrc(signedUrl); // Set the signed URL in state
} catch (err) {
console.error("Error signing URL:", err);
setError("Error loading iframe");
}
};

// Log the base and signed URLs as output in server-side terminal session
console.log("Signed URL:", signedSrc);
getSignedUrl(); // Call the async function to sign the URL
}, [src]); // Empty dependency array since `src` is hardcoded and won't change

// Return the BasicExample component with the signed URL as a prop
return <BasicExample src={signedSrc} />;
} catch (error) {
// Log any errors encountered during signing
console.error("Error signing URL:", error);
return <p>Error loading iframe</p>;
}
}
// Conditional rendering based on signing state
if (error) return <p>{error}</p>;
if (!signedSrc) return <p>Loading...</p>;

return <BasicExample src={signedSrc} />; // Pass signed URL to the iframe component
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,14 @@ export default function ExamplePage() {
<div className="bg-gray-100 p-6 rounded-lg shadow-md mb-8">
<h2 className="text-xl font-bold">Example Embed</h2>
<p>
The embed shown below is provided free of charge by Sigma Computing, as an example only. The files that
have been customized are listed on your left.
</p>
<p>
While you will not be able to customize this example in terms of parameters that are
sent to Sigma by the Embed-SDK, you can review the files involved to see a working example of what is
minimally required.
The embed will be rendered below once section 8 of the QuickStart has been configured to completion and the server restarted.
</p>
</div>

{/*Files Involved*/}
<div className="bg-gray-50 p-6 rounded-lg shadow-md mb-8">
<h2 className="text-xl font-bold">Files Involved (all files in docs/basic-examples/..) </h2>
<ul className="list-disc pl-5 mt-2 space-y-2">
<li className="list-inside">
<TooltipComponent text="Application environment variables file. This is where we are storing the Sigma embed credentials">
.env
</TooltipComponent>
</li>
<li className="list-inside">
<TooltipComponent text="This file contains utility functions that facilitate the embedding of Sigma dashboards into a web application by generating signed URLs. These signed URLs ensure secure and authorized access to Sigma dashboards or visualizations.">
/lib/utils.ts
Expand All @@ -49,11 +38,6 @@ export default function ExamplePage() {
<TooltipComponent text="This file is a React component designed to embed a Sigma Computing dashboard using an iframe within a React application.">
/app/examples/basic-example/basic-example-embed.tsx
</TooltipComponent>
</li>
<li className="list-inside">
<TooltipComponent text="This file is a React component designed to embed a Sigma Computing dashboard using an iframe within a React application.">
/app/examples/basic-example/basic-example-embed.tsx
</TooltipComponent>
</li>
</ul>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ function PlugsLogo() {
return (

<svg xmlns="http://www.w3.org/2000/svg"
width="165" height="100" viewBox="-110 -60 600 300" enable-background="new 0 0 488 238"
width="165" height="100" viewBox="-110 -60 600 300" enableBackground="new 0 0 488 238"
preserveAspectRatio="xMidYMid meet">
<path fill="#EFF0F0" opacity="1.000000" stroke="none"

Expand Down
72 changes: 25 additions & 47 deletions embed-sdk-react/docs/basic-examples/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,84 +2,62 @@ import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
import { v4 as uuid } from "uuid";

// Hardcoded Embed Configuration and User-Specific Values
const EMBED_PATH = "your_sigma_url_to_embed";
const CLIENT_ID = "your_client_id";
const SECRET = "your_secret";
const EMAIL = "your_test_embed_user_email";
const EXTERNAL_USER_ID = "123";
const ACCOUNT_TYPE = “viewer";
const EXTERNAL_USER_TEAM = "your_team";
const SESSION_LENGTH = "3600"; // Default session length

export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}

/**
* Buffer to hex string:
* - convert buffer to byte array
* - convert bytes to hex string
* @see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#converting_a_digest_to_a_hex_string
*/
export function bufferToHex(buffer: ArrayBuffer) {
return Array.from(new Uint8Array(buffer))
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
}

/**
* Uses Web Crypto API to create a SHA256 HMAC hex string.
*/
async function simpleHmac({ key, data }: { key: string; data: string }) {
const encoder = new TextEncoder();
const encodedKey = encoder.encode(key);
const encodedData = encoder.encode(data);
/**
* @see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey
*/
const hmacKey = await crypto.subtle.importKey(
"raw",
encodedKey,
{
name: "HMAC",
hash: "SHA-256",
},
true,
["sign", "verify"],
);
/**
* @see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/sign#hmac_2
*/
const hmacKey = await crypto.subtle.importKey("raw", encodedKey, { name: "HMAC", hash: "SHA-256" }, true, ["sign"]);
const signature = await crypto.subtle.sign("HMAC", hmacKey, encodedData);

const hex = bufferToHex(signature);

return { hex };
return bufferToHex(signature);
}

export async function signEmbedUrl(dashboard: string): Promise<string> {
const { EMBED_SECRET, EMBED_CLIENT_ID } = process.env;
if (!EMBED_SECRET || !EMBED_CLIENT_ID) {
throw new Error("SIGMA_EMBED_SECRET is not set");
if (!SECRET || !CLIENT_ID) {
throw new Error("The Embed `SECRET` or `CLIENT_ID` is missing in the code");
}

const searchParamsObject = {
":mode": "userbacked",
":email": "[email protected]",
":external_user_team": "Sales_People",
":account_type": "viewer",
":email": EMAIL,
":external_user_id": EXTERNAL_USER_ID,
":account_type": ACCOUNT_TYPE,
":external_user_team": EXTERNAL_USER_TEAM,
":nonce": uuid(),
":time": `${Math.floor(new Date().getTime() / 1000)}`,
":session_length": "36000",
":client_id": EMBED_CLIENT_ID,
":external_user_id": "123",
":session_length": SESSION_LENGTH,
":client_id": CLIENT_ID,
};

const searchParams = new URLSearchParams(searchParamsObject);

// EMBED_PATH - Generated on your workbook
const urlWithSearchParams = `${dashboard}?${searchParams.toString()}`;

// EMBED_SECRET - Sigma Embed Secret generated in your admin portal
const SIGNATURE = await simpleHmac({
key: EMBED_SECRET,
const signature = await simpleHmac({
key: SECRET,
data: urlWithSearchParams,
});

searchParams.append(":signature", SIGNATURE.hex);
searchParams.append(":signature", signature);

const signedUrl = `${dashboard}?${searchParams.toString()}`;

return signedUrl;
}
return `${dashboard}?${searchParams.toString()}`;
}

0 comments on commit 2b544a5

Please sign in to comment.