azure-devops-extension-sdk
Version:
Azure DevOps web extension JavaScript library.
263 lines (260 loc) • 8.86 kB
JavaScript
import { channelManager } from './XDM.js';
/**
* Web SDK version number. Can be specified in an extension's set of demands like: vss-sdk-version/3.0
*/
const sdkVersion = 4.0;
const global = window;
if (global._AzureDevOpsSDKVersion) {
console.error("The AzureDevOps SDK is already loaded. Only one version of this module can be loaded in a given document.");
}
global._AzureDevOpsSDKVersion = sdkVersion;
/**
* DevOps host level
*/
var HostType;
(function (HostType) {
HostType[HostType["Unknown"] = 0] = "Unknown";
/**
* The Deployment host
*/
HostType[HostType["Deployment"] = 1] = "Deployment";
/**
* The Enterprise host
*/
HostType[HostType["Enterprise"] = 2] = "Enterprise";
/**
* The organization host
*/
HostType[HostType["Organization"] = 4] = "Organization";
})(HostType || (HostType = {}));
const hostControlId = "DevOps.HostControl";
const serviceManagerId = "DevOps.ServiceManager";
const parentChannel = channelManager.addChannel(window.parent);
let teamContext;
let webContext;
let hostPageContext;
let extensionContext;
let initialConfiguration;
let initialContributionId;
let userContext;
let hostContext;
let themeElement;
let resolveReady;
const readyPromise = new Promise((resolve) => {
resolveReady = resolve;
});
/**
* Register a method so that the host frame can invoke events
*/
function dispatchEvent(eventName, params) {
const global = window;
let evt;
if (typeof global.CustomEvent === "function") {
evt = new global.CustomEvent(eventName, params);
}
else {
params = params || { bubbles: false, cancelable: false };
evt = document.createEvent('CustomEvent');
evt.initCustomEvent(eventName, params.bubbles, params.cancelable, params.detail);
}
window.dispatchEvent(evt);
}
parentChannel.getObjectRegistry().register("DevOps.SdkClient", {
dispatchEvent: dispatchEvent
});
/**
* Initiates the handshake with the host window.
*
* @param options - Initialization options for the extension.
*/
function init(options) {
return new Promise((resolve) => {
const initOptions = { ...options, sdkVersion };
parentChannel.invokeRemoteMethod("initialHandshake", hostControlId, [initOptions]).then((handshakeData) => {
const context = handshakeData.context;
hostPageContext = context.pageContext;
webContext = hostPageContext ? hostPageContext.webContext : undefined;
teamContext = webContext ? webContext.team : undefined;
initialConfiguration = handshakeData.initialConfig || {};
initialContributionId = handshakeData.contributionId;
extensionContext = context.extension;
userContext = context.user;
hostContext = context.host;
if (handshakeData.themeData) {
applyTheme(handshakeData.themeData);
window.addEventListener("themeChanged", (ev) => {
applyTheme(ev.detail.data);
});
}
resolveReady();
resolve();
});
});
}
/**
* Register a callback that gets called once the initial setup/handshake has completed.
* If the initial setup is already completed, the callback is invoked at the end of the current call stack.
*/
async function ready() {
return readyPromise;
}
/**
* Notifies the host that the extension successfully loaded (stop showing the loading indicator)
*/
function notifyLoadSucceeded() {
return parentChannel.invokeRemoteMethod("notifyLoadSucceeded", hostControlId);
}
/**
* Notifies the host that the extension failed to load
*/
function notifyLoadFailed(e) {
return parentChannel.invokeRemoteMethod("notifyLoadFailed", hostControlId, [e]);
}
function getWaitForReadyError(method) {
return `Attempted to call ${method}() before init() was complete. Wait for init to complete or place within a ready() callback.`;
}
/**
* Get the configuration data passed in the initial handshake from the parent frame
*/
function getConfiguration() {
if (!initialConfiguration) {
throw new Error(getWaitForReadyError("getConfiguration"));
}
return initialConfiguration;
}
/**
* Gets the information about the contribution that first caused this extension to load.
*/
function getContributionId() {
if (!initialContributionId) {
throw new Error(getWaitForReadyError("getContributionId"));
}
return initialContributionId;
}
/**
* Gets information about the current user
*/
function getUser() {
if (!userContext) {
throw new Error(getWaitForReadyError("getUser"));
}
return userContext;
}
/**
* Gets information about the host (i.e. an Azure DevOps organization) that the page is targeting
*/
function getHost() {
if (!hostContext) {
throw new Error(getWaitForReadyError("getHost"));
}
return hostContext;
}
/**
* Get the context about the extension that owns the content that is being hosted
*/
function getExtensionContext() {
if (!extensionContext) {
throw new Error(getWaitForReadyError("getExtensionContext"));
}
return extensionContext;
}
/**
* Gets information about the team that the page is targeting
*/
function getTeamContext() {
if (!teamContext) {
throw new Error(getWaitForReadyError("getTeamContext"));
}
return teamContext;
}
/**
* Get the context about the host page
*/
function getPageContext() {
if (!hostPageContext) {
throw new Error(getWaitForReadyError("getPageContext"));
}
return hostPageContext;
}
/**
* Get the context about the web
*/
function getWebContext() {
if (!webContext) {
throw new Error(getWaitForReadyError("getWebContext"));
}
return webContext;
}
/**
* Get the contribution with the given contribution id. The returned contribution has a method to get a registered object within that contribution.
*
* @param contributionId - Id of the contribution to get
*/
async function getService(contributionId) {
return ready().then(() => {
return parentChannel.invokeRemoteMethod("getService", serviceManagerId, [contributionId]);
});
}
/**
* Register an object (instance or factory method) that this extension exposes to the host frame.
*
* @param instanceId - unique id of the registered object
* @param instance - Either: (1) an object instance, or (2) a function that takes optional context data and returns an object instance.
*/
function register(instanceId, instance) {
parentChannel.getObjectRegistry().register(instanceId, instance);
}
/**
* Removes an object that this extension exposed to the host frame.
*
* @param instanceId - unique id of the registered object
*/
function unregister(instanceId) {
parentChannel.getObjectRegistry().unregister(instanceId);
}
/**
* Fetch an access token which will allow calls to be made to other DevOps services
*/
async function getAccessToken() {
return parentChannel.invokeRemoteMethod("getAccessToken", hostControlId).then((tokenObj) => { return tokenObj.token; });
}
/**
* Fetch an token which can be used to identify the current user
*/
async function getAppToken() {
return parentChannel.invokeRemoteMethod("getAppToken", hostControlId).then((tokenObj) => { return tokenObj.token; });
}
/**
* Requests the parent window to resize the container for this extension based on the current extension size.
*
* @param width - Optional width, defaults to scrollWidth
* @param height - Optional height, defaults to scrollHeight
*/
function resize(width, height) {
const body = document.body;
if (body) {
const newWidth = typeof width === "number" ? width : (body ? body.scrollWidth : undefined);
const newHeight = typeof height === "number" ? height : (body ? body.scrollHeight : undefined);
parentChannel.invokeRemoteMethod("resize", hostControlId, [newWidth, newHeight]);
}
}
/**
* Applies theme variables to the current document
*/
function applyTheme(themeData) {
if (!themeElement) {
themeElement = document.createElement("style");
themeElement.type = "text/css";
document.head.appendChild(themeElement);
}
const cssVariables = [];
if (themeData) {
for (const varName in themeData) {
cssVariables.push("--" + varName + ": " + themeData[varName]);
}
}
themeElement.innerText = ":root { " + cssVariables.join("; ") + " } body { color: var(--text-primary-color) }";
dispatchEvent("themeApplied", { detail: themeData });
}
export { HostType, applyTheme, getAccessToken, getAppToken, getConfiguration, getContributionId, getExtensionContext, getHost, getPageContext, getService, getTeamContext, getUser, getWebContext, init, notifyLoadFailed, notifyLoadSucceeded, ready, register, resize, sdkVersion, unregister };
//# sourceMappingURL=SDK.js.map