UNPKG

embed-dossier-mstr-react

Version:

This is a React component that allows you to embed a MicroStrategy Dossier in your React application.

545 lines (532 loc) 17 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { BotConsumptionPage: () => BotConsumptionPage, DashboardEmbed: () => DashboardEmbed, DashboardEmbedWithAuth: () => DashboardEmbedWithAuth, LibraryPageEmbed: () => LibraryPageEmbed, getAuthToken: () => getAuthToken, getInfoFromUrl: () => getInfoFromUrl, getServerUrl: () => getServerUrl, useCreateBotConsumptionPage: () => useCreateBotConsumptionPage, useCreateDashboard: () => useCreateDashboard, useCreateDashboardWithAuth: () => useCreateDashboardWithAuth, useCreateLibraryPage: () => useCreateLibraryPage, useLoadMstrSDK: () => useLoadMstrSDK }); module.exports = __toCommonJS(src_exports); // src/hooks/useCreateDashboard.ts var import_react2 = require("react"); // src/hooks/useLoadMstrSDK.ts var import_react = require("react"); var useLoadMstrSDK = ({ serverUrlLibrary }) => { const [isSdkLoaded, setIsSdkLoaded] = (0, import_react.useState)(false); const [isSdkError, setIsSdkError] = (0, import_react.useState)({ isError: false, message: "" }); (0, import_react.useEffect)(() => { const loadSdk = () => { if (!window.microstrategy) { const script = document.createElement("script"); script.type = "text/javascript"; script.src = serverUrlLibrary + "/javascript/embeddinglib.js"; script.onload = () => { setIsSdkLoaded(true); }; script.onerror = () => { setIsSdkError({ isError: true, message: "Error loading the SDK" }); }; document.head.appendChild(script); } }; loadSdk(); }, [serverUrlLibrary]); return { isSdkLoaded, isSdkError }; }; // src/hooks/useCreateDashboard.ts var useCreateDashboard = ({ serverUrlLibrary, config }) => { const containerRef = (0, import_react2.useRef)(null); const [dashboard, setDashboard] = (0, import_react2.useState)(null); const [isDashboardError, setIsDashboardError] = (0, import_react2.useState)(false); const { isSdkLoaded } = useLoadMstrSDK({ serverUrlLibrary }); (0, import_react2.useEffect)(() => { if (!isSdkLoaded) return; async function createDashboard() { try { const dossier = await window.microstrategy.dossier.create({ ...config, placeholder: containerRef.current }); setDashboard(dossier); } catch (error) { console.error(error); setIsDashboardError(true); } } createDashboard(); }, [isSdkLoaded]); return { dashboard, containerRef, isSdkLoaded, isDashboardError }; }; // src/utils.ts var getInfoFromUrl = (url) => { const urlParts = url.split("/").filter((part) => part !== ""); const serverUrl = urlParts[0] + "//" + urlParts[1]; const serverUrlLibrary = urlParts[0] + "//" + urlParts[1] + "/" + urlParts[2]; const libraryName = urlParts[2]; const projectId = urlParts[3]; const dossierId = urlParts[4]; return { serverUrl, serverUrlLibrary, libraryName, projectId, dossierId }; }; var getAuthToken = async ({ serverUrlLibrary }) => { const options = { method: "GET", credentials: "include", mode: "cors", headers: { "content-type": "application/json" } }; let mstrToken = ""; try { const response = await fetch(`${serverUrlLibrary}/api/auth/token`, options); if (response.ok) { const data = await response.json(); mstrToken = data.token; return mstrToken; } return response.json().then((json) => console.log(json)); } catch (error) { console.error(error); } }; var getServerUrl = (url) => { return url.split("/app/")[0]; }; // src/components/DashboardEmbed.tsx var import_classnames = __toESM(require("classnames")); var import_jsx_runtime = require("react/jsx-runtime"); var DashboardEmbed = ({ dossierUrl, className, style, config }) => { let serverUrlLibrary = ""; try { const urlInfo = getInfoFromUrl(dossierUrl); serverUrlLibrary = urlInfo.serverUrlLibrary; } catch (error) { console.error("Failed to parse dossier URL:", error); } const { containerRef } = useCreateDashboard({ serverUrlLibrary, config: { url: dossierUrl, ...config } }); return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: containerRef, className: (0, import_classnames.default)(className), style }); }; // src/hooks/useCreateLibraryPage.ts var import_react3 = require("react"); var useCreateLibraryPage = ({ serverUrlLibrary, config }) => { const libraryPageRef = (0, import_react3.useRef)(null); const [libraryPage, setLibraryPage] = (0, import_react3.useState)(null); const [libraryPageState, setLibraryPageState] = (0, import_react3.useState)({ isLoading: false, error: null }); const { isSdkLoaded } = useLoadMstrSDK({ serverUrlLibrary }); const prevConfigRef = (0, import_react3.useRef)(config); (0, import_react3.useEffect)(() => { if (!isSdkLoaded) return; if (!libraryPage && !libraryPageState.isLoading) { createLibraryPage(); } }, [isSdkLoaded]); (0, import_react3.useEffect)(() => { const configChanged = JSON.stringify(config) !== JSON.stringify(prevConfigRef.current); if (libraryPage && configChanged) { createLibraryPage(); } prevConfigRef.current = config; }, [config]); const createLibraryPage = async () => { setLibraryPageState((prev) => ({ ...prev, isLoading: true, error: null })); try { const embeddingContext = await window.microstrategy.embeddingContexts.embedLibraryPage({ placeholder: libraryPageRef.current, serverUrl: serverUrlLibrary, errorHandler: (error) => { console.error("Library page error:", error); setLibraryPageState((prev) => ({ ...prev, error: error.message || "Failed to load library page" })); }, sessionErrorHandler: (error) => { console.error("Session error:", error); setLibraryPageState((prev) => ({ ...prev, error: "Session expired. Please refresh the page." })); }, ...config }); setLibraryPage(embeddingContext); } catch (error) { setLibraryPageState((prev) => ({ ...prev, error: error instanceof Error ? error.message : "Failed to create library page" })); } finally { setLibraryPageState((prev) => ({ ...prev, isLoading: false })); } }; return { libraryPage, libraryPageRef, isSdkLoaded, isLoading: libraryPageState.isLoading, error: libraryPageState.error }; }; // src/components/LibraryPageEmbed.tsx var import_classnames2 = __toESM(require("classnames")); var import_jsx_runtime2 = require("react/jsx-runtime"); var LibraryPageEmbed = ({ serverUrlLibrary, config, className, style }) => { const { libraryPageRef } = useCreateLibraryPage({ serverUrlLibrary, config }); return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref: libraryPageRef, className: (0, import_classnames2.default)(className), style }); }; // src/hooks/useCreateBotConsumptionPage.ts var import_react4 = require("react"); var useCreateBotConsumptionPage = ({ serverUrlLibrary, projectId, objectId, config }) => { const botConsumptionPageRef = (0, import_react4.useRef)(null); const [botConsumptionPage, setBotConsumptionPage] = (0, import_react4.useState)(null); const [isBotConsumptionPageError, setIsBotConsumptionPageError] = (0, import_react4.useState)(false); const { isSdkLoaded, isSdkError } = useLoadMstrSDK({ serverUrlLibrary }); (0, import_react4.useEffect)(() => { if (!isSdkLoaded) return; async function createBotConsumptionPage() { try { const botConsumptionPage2 = await window.microstrategy.embeddingContexts.embedBotConsumptionPage({ ...config, placeholder: botConsumptionPageRef.current, serverUrl: serverUrlLibrary, projectId, objectId }); setBotConsumptionPage(botConsumptionPage2); } catch (error) { console.error(error); setIsBotConsumptionPageError(true); } } createBotConsumptionPage(); }, [isSdkLoaded]); return { botConsumptionPage, botConsumptionPageRef, isBotConsumptionPageError, isSdkError, isSdkLoaded }; }; // src/components/BotConsumptionPage.tsx var import_classnames3 = __toESM(require("classnames")); var import_jsx_runtime3 = require("react/jsx-runtime"); var BotConsumptionPage = ({ serverUrlLibrary, projectId, objectId, config, className, style }) => { const { botConsumptionPageRef } = useCreateBotConsumptionPage({ serverUrlLibrary, projectId, objectId, config }); return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)( "div", { ref: botConsumptionPageRef, className: (0, import_classnames3.default)(className), style } ); }; // src/hooks/useCreateDashboardWithAuth.ts var import_react5 = require("react"); var useCreateDashboardWithAuth = ({ serverUrlLibrary, placeholder, config, loginMode, username, password }) => { const [dashboard, setDashboard] = (0, import_react5.useState)(null); const [authState, setAuthState] = (0, import_react5.useState)({ isAuthenticated: false, isAuthenticating: false, error: null }); const { isSdkLoaded } = useLoadMstrSDK({ serverUrlLibrary }); (0, import_react5.useEffect)(() => { if (!isSdkLoaded || !placeholder) return; let mounted = true; const initializeDashboard = async () => { if (!mounted) return; setAuthState((prev) => ({ ...prev, isAuthenticating: true, error: null })); try { switch (loginMode) { case "standard": case "ldap": { if (!username || !password) { throw new Error( "Username and password are required for standard/LDAP authentication" ); } const standardOptions = { method: "POST", credentials: "include", mode: "cors", headers: { "content-type": "application/json" }, body: JSON.stringify({ loginMode: 1, username, password }) }; await fetch(`${serverUrlLibrary}/api/auth/login`, standardOptions); break; } case "guest": { const guestOptions = { method: "POST", credentials: "include", mode: "cors", headers: { "content-type": "application/json" }, body: JSON.stringify({ loginMode: 8 }) }; await fetch(`${serverUrlLibrary}/api/auth/login`, guestOptions); break; } case "saml": try { await window.microstrategy.auth.samlLogin(serverUrlLibrary); } catch (e) { if (e instanceof Error && e.message.includes("Failed to open a new tab")) { throw new Error( "Please enable popups to be directed to the SAML login site" ); } throw e; } break; case "oidc": try { await window.microstrategy.auth.oidcLogin(serverUrlLibrary); } catch (e) { if (e instanceof Error && e.message.includes("Failed to open a new tab")) { throw new Error( "Please enable popups to be directed to the OIDC login site" ); } throw e; } break; } const dossier = await window.microstrategy.dossier.create({ ...config, placeholder, enableCustomAuthentication: true, customAuthenticationType: window.microstrategy.dossier.CustomAuthenticationType.AUTH_TOKEN, getLoginToken: async () => { const options = { method: "GET", credentials: "include", mode: "cors", headers: { "content-type": "application/json" } }; const response = await fetch( `${serverUrlLibrary}/api/auth/token`, options ); return response.ok ? response.headers.get("x-mstr-authtoken") : null; } }); if (mounted) { setDashboard(dossier); setAuthState((prev) => ({ ...prev, isAuthenticated: true })); } } catch (error) { if (mounted) { console.error("Dashboard auth error:", error); setAuthState((prev) => ({ ...prev, error: error instanceof Error ? error.message : "Failed to initialize dashboard", isAuthenticated: false })); } } finally { if (mounted) { setAuthState((prev) => ({ ...prev, isAuthenticating: false })); } } }; initializeDashboard(); return () => { mounted = false; }; }, [ isSdkLoaded, placeholder, loginMode, serverUrlLibrary, config, username, password ]); return { dashboard, ...authState }; }; // src/components/DashboardEmbedWithAuth.tsx var import_classnames4 = __toESM(require("classnames")); var import_react6 = require("react"); var import_jsx_runtime4 = require("react/jsx-runtime"); var DashboardEmbedWithAuth = ({ dossierUrl, className, style, config, loginMode, username, password, loadingComponent = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { children: "Loading..." }), errorComponent = (error) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "text-center text-red-500 p-4 max-w-md", children: [ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { className: "text-lg font-semibold mb-2", children: "Authentication Error" }), /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: error }) ] }) }) => { const { serverUrlLibrary } = getInfoFromUrl(dossierUrl); const divRef = (0, import_react6.useRef)(null); const { isAuthenticating, error } = useCreateDashboardWithAuth({ serverUrlLibrary, placeholder: divRef.current, config: { url: dossierUrl, enableResponsive: true, enableCustomAuthentication: true, containerHeight: "600px", containerWidth: "100%", ...config }, loginMode, username, password }); if (isAuthenticating) { return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: loadingComponent }); } if (error) { return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: typeof errorComponent === "function" ? errorComponent(error) : errorComponent }); } return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)( "div", { ref: divRef, className: (0, import_classnames4.default)("w-full h-[600px]", className), style } ); }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { BotConsumptionPage, DashboardEmbed, DashboardEmbedWithAuth, LibraryPageEmbed, getAuthToken, getInfoFromUrl, getServerUrl, useCreateBotConsumptionPage, useCreateDashboard, useCreateDashboardWithAuth, useCreateLibraryPage, useLoadMstrSDK });