mirror of
https://github.com/pandorafms/pandorafms.git
synced 2025-09-26 11:29:12 +02:00
223 lines
6.5 KiB
TypeScript
223 lines
6.5 KiB
TypeScript
import {
|
|
LinkedVisualConsoleProps,
|
|
AnyObject,
|
|
WithModuleProps
|
|
} from "../lib/types";
|
|
import {
|
|
linkedVCPropsDecoder,
|
|
modulePropsDecoder,
|
|
decodeBase64,
|
|
stringIsEmpty,
|
|
parseIntOr
|
|
} from "../lib";
|
|
import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
|
|
|
|
export type BasicChartProps = {
|
|
type: ItemType.BASIC_CHART;
|
|
html: string;
|
|
period: number | null;
|
|
value: number | null;
|
|
status: string;
|
|
moduleNameColor: string;
|
|
} & ItemProps &
|
|
WithModuleProps &
|
|
LinkedVisualConsoleProps;
|
|
|
|
/**
|
|
* Build a valid typed object from a raw object.
|
|
* This will allow us to ensure the type safety.
|
|
*
|
|
* @param data Raw object.
|
|
* @return An object representing the basic chart props.
|
|
* @throws Will throw a TypeError if some property
|
|
* is missing from the raw object or have an invalid type.
|
|
*/
|
|
export function basicChartPropsDecoder(
|
|
data: AnyObject
|
|
): BasicChartProps | never {
|
|
if (stringIsEmpty(data.html) && stringIsEmpty(data.encodedHtml)) {
|
|
throw new TypeError("missing html content.");
|
|
}
|
|
|
|
return {
|
|
...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
|
|
type: ItemType.BASIC_CHART,
|
|
html: !stringIsEmpty(data.html)
|
|
? data.html
|
|
: decodeBase64(data.encodedHtml),
|
|
period: parseIntOr(data.period, null),
|
|
value: parseFloat(data.value),
|
|
status: stringIsEmpty(data.status) ? "#B2B2B2" : data.status,
|
|
moduleNameColor: stringIsEmpty(data.moduleNameColor)
|
|
? "#3f3f3f"
|
|
: data.moduleNameColor,
|
|
...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
|
|
...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.
|
|
};
|
|
}
|
|
|
|
export default class BasicChart extends Item<BasicChartProps> {
|
|
protected createDomElement(): HTMLElement {
|
|
const element = document.createElement("div");
|
|
|
|
const header = document.createElement("div");
|
|
header.className = "basic-chart-header";
|
|
|
|
const moduleName = document.createElement("h2");
|
|
moduleName.className = "basic-chart-header-name";
|
|
moduleName.textContent = this.props.moduleName;
|
|
moduleName.style.color = `${this.props.moduleNameColor}`;
|
|
header.appendChild(moduleName);
|
|
|
|
let value = "";
|
|
if (this.props.value !== null) {
|
|
value = this.number_format(this.props.value, false, "", 2, 1000);
|
|
}
|
|
|
|
const moduleValue = document.createElement("h2");
|
|
moduleValue.className = "basic-chart-header-value";
|
|
moduleValue.textContent = `${value}`;
|
|
moduleValue.style.color = this.props.status;
|
|
header.appendChild(moduleValue);
|
|
|
|
element.innerHTML = this.props.html;
|
|
element.className = "basic-chart";
|
|
if (
|
|
this.props.agentDisabled === true ||
|
|
this.props.moduleDisabled === true
|
|
) {
|
|
element.style.opacity = "0.2";
|
|
}
|
|
|
|
// Remove the overview graph.
|
|
const legendP = element.getElementsByTagName("p");
|
|
for (let i = 0; i < legendP.length; i++) {
|
|
legendP[i].style.margin = "0px";
|
|
}
|
|
|
|
// Remove the overview graph.
|
|
const overviewGraphs = element.getElementsByClassName("overview_graph");
|
|
for (let i = 0; i < overviewGraphs.length; i++) {
|
|
overviewGraphs[i].remove();
|
|
}
|
|
|
|
// Hack to execute the JS after the HTML is added to the DOM.
|
|
const scripts = element.getElementsByTagName("script");
|
|
for (let i = 0; i < scripts.length; i++) {
|
|
if (scripts[i].src.length === 0) {
|
|
setTimeout(() => {
|
|
try {
|
|
eval(scripts[i].innerHTML.trim());
|
|
} catch (ignored) {} // eslint-disable-line no-empty
|
|
}, 0);
|
|
}
|
|
}
|
|
|
|
element.innerHTML = this.props.html;
|
|
element.insertBefore(header, element.firstChild);
|
|
|
|
return element;
|
|
}
|
|
|
|
protected updateDomElement(element: HTMLElement): void {
|
|
const header = document.createElement("div");
|
|
header.className = "basic-chart-header";
|
|
|
|
const moduleName = document.createElement("h2");
|
|
moduleName.className = "basic-chart-header-name";
|
|
moduleName.textContent = this.props.moduleName;
|
|
moduleName.style.color = `${this.props.moduleNameColor}`;
|
|
header.appendChild(moduleName);
|
|
|
|
let value = "";
|
|
if (this.props.value !== null) {
|
|
value = this.number_format(this.props.value, false, "", 2, 1000);
|
|
}
|
|
|
|
const moduleValue = document.createElement("h2");
|
|
moduleValue.className = "basic-chart-header-value";
|
|
moduleValue.textContent = `${value}`;
|
|
moduleValue.style.color = this.props.status;
|
|
header.appendChild(moduleValue);
|
|
|
|
element.innerHTML = this.props.html;
|
|
element.insertBefore(header, element.firstChild);
|
|
|
|
// Remove the overview graph.
|
|
const legendP = element.getElementsByTagName("p");
|
|
for (let i = 0; i < legendP.length; i++) {
|
|
legendP[i].style.margin = "0px";
|
|
}
|
|
|
|
// Remove the overview graph.
|
|
const overviewGraphs = element.getElementsByClassName("overview_graph");
|
|
for (let i = 0; i < overviewGraphs.length; i++) {
|
|
overviewGraphs[i].remove();
|
|
}
|
|
|
|
// Hack to execute the JS after the HTML is added to the DOM.
|
|
const scripts = element.getElementsByTagName("script");
|
|
for (let i = 0; i < scripts.length; i++) {
|
|
if (scripts[i].src.length === 0) {
|
|
eval(scripts[i].innerHTML.trim());
|
|
}
|
|
}
|
|
}
|
|
|
|
protected number_format(
|
|
number: number,
|
|
force_integer: boolean,
|
|
unit: string,
|
|
short_data: number,
|
|
divisor: number
|
|
) {
|
|
divisor = typeof divisor !== "undefined" ? divisor : 1000;
|
|
var decimals = 2;
|
|
|
|
// Set maximum decimal precision to 99 in case short_data is not set.
|
|
if (!short_data) {
|
|
short_data = 99;
|
|
}
|
|
|
|
if (force_integer) {
|
|
if (Math.round(number) != number) {
|
|
return "";
|
|
}
|
|
} else {
|
|
short_data++;
|
|
const aux_decimals = this.pad("1", short_data, 0);
|
|
number =
|
|
Math.round(number * Number.parseInt(aux_decimals)) /
|
|
Number.parseInt(aux_decimals);
|
|
}
|
|
|
|
var shorts = ["", "K", "M", "G", "T", "P", "E", "Z", "Y"];
|
|
var pos = 0;
|
|
|
|
while (Math.abs(number) >= divisor) {
|
|
// As long as the number can be divided by 1000 or 1024.
|
|
pos++;
|
|
number = number / divisor;
|
|
}
|
|
|
|
if (divisor) {
|
|
number = Math.round(number * decimals) / decimals;
|
|
} else {
|
|
number = Math.round(number * decimals);
|
|
}
|
|
|
|
if (isNaN(number)) {
|
|
number = 0;
|
|
}
|
|
|
|
return number + " " + shorts[pos] + unit;
|
|
}
|
|
|
|
protected pad(input: string, length: number, padding: number): string {
|
|
var str = input + "";
|
|
return length <= str.length
|
|
? str
|
|
: this.pad(str + padding, length, padding);
|
|
}
|
|
}
|