plugin-api/MetaflowPluginAPI.js (138 lines of code) (raw):
const VERSION_INFO = {
api: '1.2.0',
};
const DataListeners = [];
const EventListeners = [];
let initialised = false;
let onReadyFn = () => null;
const PluginInfo = {
slot: null,
manifest: null,
};
function messageHandler(event) {
if (event.data && event.data.type) {
switch (event.data.type) {
case 'ReadyToRender': {
if (!initialised) {
Metaflow.parameters = event.data.config;
Metaflow.resource = event.data.resource;
Metaflow.settings = event.data.settings;
PluginInfo.manifest = event.data.config;
PluginInfo.slot = event.data.config?.config?.slot;
initialised = true;
if (onReadyFn) {
onReadyFn(Metaflow.parameters, Metaflow.resource, Metaflow.settings);
}
}
return;
}
case 'DataUpdate': {
for (const listener of DataListeners) {
if (event.data.path && listener.paths.includes(event.data.path)) {
listener.callback(event.data);
}
}
return;
}
case 'EventUpdate': {
for (const listener of EventListeners) {
listener(event.data);
}
return;
}
default:
return;
}
}
}
window.addEventListener('message', messageHandler);
const Metaflow = {
parameters: {},
resource: {},
/**
* onReady function will be called with basic info like resource ids and custom server parameters.
* @param {*} onready
*/
onReady(onready) {
onReadyFn = onready;
window.parent.postMessage(
{
name: window.name,
type: 'PluginRegisterEvent',
version: VERSION_INFO,
},
'*',
);
},
/**
* Alias for onReady
* @param {*} _settings Deprecated settings for register function
* @param {*} onready Callback to startup plugin.
*/
register(_settings, onready) {
if (onready) {
this.onReady(onready);
}
},
/**
* Update height of plugin to parent application. Useful if we want whole plugin to be visible
* @param {number} fixedHeight Optional fixed height in pixels for plugin. If not given, we try to calculate plugin height automatically.
*/
setHeight(fixedHeight) {
if (fixedHeight) {
window.parent.postMessage({ name: window.name, type: 'PluginHeightCheck', height: fixedHeight }, '*');
} else {
const body = document.body;
const height = Math.max(body.scrollHeight, body.offsetHeight, body.clientHeight);
window.parent.postMessage({ name: window.name, type: 'PluginHeightCheck', height: height }, '*');
}
},
/**
* Subscribe to data
* @param {string[]} paths
* @param {(event: { path: string, data: * }) => void} fn
*/
subscribe(paths, fn) {
DataListeners.push({ paths, callback: fn });
window.parent.postMessage({ name: window.name, type: 'PluginSubscribeToData', paths: paths }, '*');
},
/**
* Subscribe to events
* @param {string[]} events List of event name to subscribe to
* @param {(event: { type: string, data: * }) => void} fn Callback to trigger in case of event
*/
on(events, fn) {
EventListeners.push(fn);
window.parent.postMessage({ name: window.name, type: 'PluginSubscribeToEvent', events: events }, '*');
},
/**
* Call event with any name and payload. Other plugins or systems in app might subscribe to these events.
* @param {string} event
* @param {*} data
*/
call(event, data) {
window.parent.postMessage({ name: window.name, type: 'PluginCallEvent', event: event, data: data }, '*');
},
/**
* Send notification on main application
* @param {string | {type: string, message: string}} message
*/
sendNotification(message) {
window.parent.postMessage(
{
name: window.name,
type: 'PluginCallEvent',
event: 'SEND_NOTIFICATION',
data: message,
},
'*',
);
},
/**
* Update visibility of plugin. It will remain in DOM either way.
* @param {boolean} visible
*/
setVisibility(visible) {
window.parent.postMessage(
{
name: window.name,
type: 'PluginCallEvent',
event: 'UPDATE_PLUGIN',
data: {
slot: PluginInfo.slot,
name: PluginInfo.manifest?.name,
visible: visible,
},
},
'*',
);
},
//
// Request to be removed?
//
remove() {
window.parent.postMessage({ name: window.name, type: 'PluginRemoveRequest' }, '*');
},
subscribeToMetadata(fn) {
this.subscribe(['metadata'], (data) => fn(data));
},
subscribeToInfo(fn) {
this.subscribe(['info'], (data) => fn(data));
},
subscribeToTaskInfo(fn) {
this.subscribe(['task-info'], (data) => fn(data));
},
subscribeToRunMetadata(fn) {
this.subscribe(['run-metadata'], (data) => fn(data));
},
subscribeToRunInfo(fn) {
this.subscribe(['run-info'], (data) => fn(data));
},
};
if (typeof exports !== 'undefined') {
exports.Metaflow = Metaflow;
}
if (typeof window !== 'undefined') {
window.Metaflow = Metaflow;
}