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
JavaScript
;
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
});