WIP: Visual console client
This commit is contained in:
parent
30491a307c
commit
5c5d40cfd4
|
@ -147,7 +147,7 @@ export class FormContainer {
|
|||
}
|
||||
|
||||
public removeInputGroup(inputGroupName: string): FormContainer {
|
||||
// delete this.inputGroupsByName[inputGroupName];
|
||||
delete this.inputGroupsByName[inputGroupName];
|
||||
// Remove the current stored name.
|
||||
this.enabledInputGroupNames = this.enabledInputGroupNames.filter(
|
||||
name => name === inputGroupName
|
||||
|
|
|
@ -17,7 +17,8 @@ import {
|
|||
addMovementListener,
|
||||
debounce,
|
||||
addResizementListener,
|
||||
t
|
||||
t,
|
||||
helpTip
|
||||
} from "./lib";
|
||||
import TypedEvent, { Listener, Disposable } from "./lib/TypedEvent";
|
||||
import { FormContainer, InputGroup } from "./Form";
|
||||
|
@ -84,7 +85,76 @@ export interface ItemResizedEvent {
|
|||
}
|
||||
|
||||
// TODO: Document
|
||||
class PositionInputGroup extends InputGroup<ItemProps> {
|
||||
class LinkInputGroup extends InputGroup<Partial<ItemProps>> {
|
||||
protected createContent(): HTMLElement | HTMLElement[] {
|
||||
const linkLabel = document.createElement("label");
|
||||
linkLabel.textContent = t("Link enabled");
|
||||
|
||||
const linkInputChkbx = document.createElement("input");
|
||||
linkInputChkbx.id = "checkbox-switch";
|
||||
linkInputChkbx.className = "checkbox-switch";
|
||||
linkInputChkbx.type = "checkbox";
|
||||
linkInputChkbx.name = "checkbox-enable-link";
|
||||
linkInputChkbx.value = "1";
|
||||
linkInputChkbx.checked =
|
||||
this.currentData.isLinkEnabled || this.initialData.isLinkEnabled || false;
|
||||
linkInputChkbx.addEventListener("change", e =>
|
||||
this.updateData({
|
||||
isLinkEnabled: (e.target as HTMLInputElement).checked
|
||||
})
|
||||
);
|
||||
|
||||
const linkInputLabel = document.createElement("label");
|
||||
linkInputLabel.className = "label-switch";
|
||||
linkInputLabel.htmlFor = "checkbox-switch";
|
||||
|
||||
linkLabel.appendChild(linkInputChkbx);
|
||||
linkLabel.appendChild(linkInputLabel);
|
||||
|
||||
return linkLabel;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Document
|
||||
class OnTopInputGroup extends InputGroup<Partial<ItemProps>> {
|
||||
protected createContent(): HTMLElement | HTMLElement[] {
|
||||
const onTopLabel = document.createElement("label");
|
||||
onTopLabel.textContent = t("Show on top");
|
||||
|
||||
const onTopInputChkbx = document.createElement("input");
|
||||
onTopInputChkbx.id = "checkbox-switch";
|
||||
onTopInputChkbx.className = "checkbox-switch";
|
||||
onTopInputChkbx.type = "checkbox";
|
||||
onTopInputChkbx.name = "checkbox-show-on-top";
|
||||
onTopInputChkbx.value = "1";
|
||||
onTopInputChkbx.checked =
|
||||
this.currentData.isOnTop || this.initialData.isOnTop || false;
|
||||
onTopInputChkbx.addEventListener("change", e =>
|
||||
this.updateData({
|
||||
isOnTop: (e.target as HTMLInputElement).checked
|
||||
})
|
||||
);
|
||||
|
||||
const onTopInputLabel = document.createElement("label");
|
||||
onTopInputLabel.className = "label-switch";
|
||||
onTopInputLabel.htmlFor = "checkbox-switch";
|
||||
|
||||
onTopLabel.appendChild(
|
||||
helpTip(
|
||||
t(
|
||||
"It allows the element to be superimposed to the rest of items of the visual console"
|
||||
)
|
||||
)
|
||||
);
|
||||
onTopLabel.appendChild(onTopInputChkbx);
|
||||
onTopLabel.appendChild(onTopInputLabel);
|
||||
|
||||
return onTopLabel;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Document
|
||||
class PositionInputGroup extends InputGroup<Partial<ItemProps>> {
|
||||
protected createContent(): HTMLElement | HTMLElement[] {
|
||||
const positionLabel = document.createElement("label");
|
||||
positionLabel.textContent = t("Position");
|
||||
|
@ -118,8 +188,54 @@ class PositionInputGroup extends InputGroup<ItemProps> {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Document
|
||||
class SizeInputGroup extends InputGroup<Partial<ItemProps>> {
|
||||
protected createContent(): HTMLElement | HTMLElement[] {
|
||||
const sizeLabel = document.createElement("label");
|
||||
sizeLabel.textContent = t("Size");
|
||||
|
||||
const sizeInputWidth = document.createElement("input");
|
||||
sizeInputWidth.type = "number";
|
||||
sizeInputWidth.min = "0";
|
||||
sizeInputWidth.required = true;
|
||||
sizeInputWidth.value = `${this.currentData.width ||
|
||||
this.initialData.width ||
|
||||
0}`;
|
||||
sizeInputWidth.addEventListener("change", e =>
|
||||
this.updateData({
|
||||
width: parseIntOr((e.target as HTMLInputElement).value, 0)
|
||||
})
|
||||
);
|
||||
|
||||
const sizeInputHeight = document.createElement("input");
|
||||
sizeInputHeight.type = "number";
|
||||
sizeInputHeight.min = "0";
|
||||
sizeInputHeight.required = true;
|
||||
sizeInputHeight.value = `${this.currentData.height ||
|
||||
this.initialData.height ||
|
||||
0}`;
|
||||
sizeInputHeight.addEventListener("change", e =>
|
||||
this.updateData({
|
||||
height: parseIntOr((e.target as HTMLInputElement).value, 0)
|
||||
})
|
||||
);
|
||||
|
||||
sizeLabel.appendChild(
|
||||
helpTip(
|
||||
t(
|
||||
"In order to use the original image file size, set width and height to 0."
|
||||
)
|
||||
)
|
||||
);
|
||||
sizeLabel.appendChild(sizeInputWidth);
|
||||
sizeLabel.appendChild(sizeInputHeight);
|
||||
|
||||
return sizeLabel;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a valid enum value from a raw label positi9on value.
|
||||
* Extract a valid enum value from a raw label position value.
|
||||
* @param labelPosition Raw value.
|
||||
*/
|
||||
const parseLabelPosition = (
|
||||
|
@ -380,7 +496,8 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
|
|||
this.childElementRef = this.createDomElement();
|
||||
|
||||
// Insert the elements into the container.
|
||||
this.elementRef.append(this.childElementRef, this.labelElementRef);
|
||||
this.elementRef.appendChild(this.childElementRef);
|
||||
this.elementRef.appendChild(this.labelElementRef);
|
||||
|
||||
// Resize element.
|
||||
this.resizeElement(this.itemProps.width, this.itemProps.height);
|
||||
|
@ -468,8 +585,10 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
|
|||
const cell = document.createElement("td");
|
||||
|
||||
cell.innerHTML = label;
|
||||
row.append(cell);
|
||||
table.append(emptyRow1, row, emptyRow2);
|
||||
row.appendChild(cell);
|
||||
table.appendChild(emptyRow1);
|
||||
table.appendChild(row);
|
||||
table.appendChild(emptyRow2);
|
||||
table.style.textAlign = "center";
|
||||
|
||||
// Change the table size depending on its position.
|
||||
|
@ -491,7 +610,7 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
|
|||
}
|
||||
|
||||
// element.innerHTML = this.props.label;
|
||||
element.append(table);
|
||||
element.appendChild(table);
|
||||
}
|
||||
|
||||
return element;
|
||||
|
@ -897,15 +1016,6 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
|
|||
};
|
||||
}
|
||||
|
||||
// TODO: Document
|
||||
public getFormContainer(): FormContainer {
|
||||
return new FormContainer(
|
||||
t("Item"),
|
||||
[new PositionInputGroup("position", this.props)],
|
||||
["position"]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* To add an event handler to the click of the linked visual console elements.
|
||||
* @param listener Function which is going to be executed when a linked console is clicked.
|
||||
|
@ -985,6 +1095,25 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
|
|||
|
||||
return disposable;
|
||||
}
|
||||
|
||||
// TODO: Document
|
||||
public getFormContainer(): FormContainer {
|
||||
return VisualConsoleItem.getFormContainer(this.props);
|
||||
}
|
||||
|
||||
// TODO: Document
|
||||
public static getFormContainer(props: Partial<ItemProps>): FormContainer {
|
||||
return new FormContainer(
|
||||
t("Item"),
|
||||
[
|
||||
new PositionInputGroup("position", props),
|
||||
new SizeInputGroup("size", props),
|
||||
new LinkInputGroup("link", props),
|
||||
new OnTopInputGroup("show-on-top", props)
|
||||
],
|
||||
["position", "size", "link", "show-on-top"]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default VisualConsoleItem;
|
||||
|
|
|
@ -314,24 +314,7 @@ export default class VisualConsole {
|
|||
});
|
||||
|
||||
// Initialize the items.
|
||||
items.forEach(item => {
|
||||
try {
|
||||
const itemInstance = itemInstanceFrom(item);
|
||||
// Add the item to the list.
|
||||
this.elementsById[itemInstance.props.id] = itemInstance;
|
||||
this.elementIds.push(itemInstance.props.id);
|
||||
// Item event handlers.
|
||||
itemInstance.onClick(this.handleElementClick);
|
||||
itemInstance.onDblClick(this.handleElementDblClick);
|
||||
itemInstance.onMoved(this.handleElementMovement);
|
||||
itemInstance.onResized(this.handleElementResizement);
|
||||
itemInstance.onRemove(this.handleElementRemove);
|
||||
// Add the item to the DOM.
|
||||
this.containerRef.append(itemInstance.elementRef);
|
||||
} catch (error) {
|
||||
console.log("Error creating a new element:", error.message);
|
||||
}
|
||||
});
|
||||
items.forEach(item => this.addElement(item, this));
|
||||
|
||||
// Create lines.
|
||||
this.buildRelations();
|
||||
|
@ -350,6 +333,29 @@ export default class VisualConsole {
|
|||
.filter(_ => _ != null) as Item<ItemProps>[];
|
||||
}
|
||||
|
||||
/**
|
||||
* To create a new element add it to the DOM.
|
||||
* @param item. Raw representation of the item's data.
|
||||
*/
|
||||
public addElement(item: AnyObject, context: this = this): void {
|
||||
try {
|
||||
const itemInstance = itemInstanceFrom(item);
|
||||
// Add the item to the list.
|
||||
context.elementsById[itemInstance.props.id] = itemInstance;
|
||||
context.elementIds.push(itemInstance.props.id);
|
||||
// Item event handlers.
|
||||
itemInstance.onClick(context.handleElementClick);
|
||||
itemInstance.onDblClick(context.handleElementDblClick);
|
||||
itemInstance.onMoved(context.handleElementMovement);
|
||||
itemInstance.onResized(context.handleElementResizement);
|
||||
itemInstance.onRemove(context.handleElementRemove);
|
||||
// Add the item to the DOM.
|
||||
context.containerRef.append(itemInstance.elementRef);
|
||||
} catch (error) {
|
||||
console.log("Error creating a new element:", error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter of the `elements` property.
|
||||
* @param items.
|
||||
|
@ -376,18 +382,7 @@ export default class VisualConsole {
|
|||
if (item.id) {
|
||||
if (this.elementsById[item.id] == null) {
|
||||
// New item.
|
||||
try {
|
||||
const itemInstance = itemInstanceFrom(item);
|
||||
// Add the item to the list.
|
||||
this.elementsById[itemInstance.props.id] = itemInstance;
|
||||
// Item event handlers.
|
||||
itemInstance.onClick(this.handleElementClick);
|
||||
itemInstance.onRemove(this.handleElementRemove);
|
||||
// Add the item to the DOM.
|
||||
this.containerRef.append(itemInstance.elementRef);
|
||||
} catch (error) {
|
||||
console.log("Error creating a new element:", error.message);
|
||||
}
|
||||
this.addElement(item);
|
||||
} else {
|
||||
// Update item.
|
||||
try {
|
||||
|
@ -519,6 +514,8 @@ export default class VisualConsole {
|
|||
this.elementIds = [];
|
||||
// Clear relations.
|
||||
this.clearRelations();
|
||||
// Remove the click event listener.
|
||||
this.containerRef.removeEventListener("click", this.handleContainerClick);
|
||||
// Clean container.
|
||||
this.containerRef.innerHTML = "";
|
||||
}
|
||||
|
@ -526,7 +523,7 @@ export default class VisualConsole {
|
|||
/**
|
||||
* Create line elements which connect the elements with their parents.
|
||||
*/
|
||||
private buildRelations(): void {
|
||||
public buildRelations(): void {
|
||||
// Clear relations.
|
||||
this.clearRelations();
|
||||
// Add relations.
|
||||
|
@ -846,4 +843,29 @@ export default class VisualConsole {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Document.
|
||||
public static items = {
|
||||
[ItemType.STATIC_GRAPH]: StaticGraph,
|
||||
[ItemType.MODULE_GRAPH]: ModuleGraph,
|
||||
[ItemType.SIMPLE_VALUE]: SimpleValue,
|
||||
[ItemType.SIMPLE_VALUE_MAX]: SimpleValue,
|
||||
[ItemType.SIMPLE_VALUE_MIN]: SimpleValue,
|
||||
[ItemType.SIMPLE_VALUE_AVG]: SimpleValue,
|
||||
[ItemType.PERCENTILE_BAR]: Percentile,
|
||||
[ItemType.PERCENTILE_BUBBLE]: Percentile,
|
||||
[ItemType.CIRCULAR_PROGRESS_BAR]: Percentile,
|
||||
[ItemType.CIRCULAR_INTERIOR_PROGRESS_BAR]: Percentile,
|
||||
[ItemType.LABEL]: Label,
|
||||
[ItemType.ICON]: Icon,
|
||||
[ItemType.SERVICE]: Service,
|
||||
[ItemType.GROUP_ITEM]: Group,
|
||||
[ItemType.BOX_ITEM]: Box,
|
||||
[ItemType.LINE_ITEM]: Line,
|
||||
[ItemType.AUTO_SLA_GRAPH]: EventsHistory,
|
||||
[ItemType.DONUT_GRAPH]: DonutGraph,
|
||||
[ItemType.BARS_GRAPH]: BarsGraph,
|
||||
[ItemType.CLOCK]: Clock,
|
||||
[ItemType.COLOR_CLOUD]: ColorCloud
|
||||
};
|
||||
}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 376 B |
|
@ -10,6 +10,8 @@ import {
|
|||
ItemMeta
|
||||
} from "./types";
|
||||
|
||||
import helpTipIcon from "./help-tip.png";
|
||||
|
||||
/**
|
||||
* Return a number or a default value from a raw value.
|
||||
* @param value Raw value from which we will try to extract a valid number.
|
||||
|
@ -463,13 +465,9 @@ export function addMovementListener(
|
|||
let borderFix = Number.parseInt(borderWidth) * 2;
|
||||
|
||||
// Will run onMoved 32ms after its last execution.
|
||||
const debouncedMovement = debounce(32, (x: Position["x"], y: Position["y"]) =>
|
||||
onMoved(x, y)
|
||||
);
|
||||
const debouncedMovement = debounce(32, onMoved);
|
||||
// Will run onMoved one time max every 16ms.
|
||||
const throttledMovement = throttle(16, (x: Position["x"], y: Position["y"]) =>
|
||||
onMoved(x, y)
|
||||
);
|
||||
const throttledMovement = throttle(16, onMoved);
|
||||
|
||||
const handleMove = (e: MouseEvent) => {
|
||||
// Calculate the new element coordinates.
|
||||
|
@ -641,15 +639,9 @@ export function addResizementListener(
|
|||
let borderFix = Number.parseInt(borderWidth);
|
||||
|
||||
// Will run onResized 32ms after its last execution.
|
||||
const debouncedResizement = debounce(
|
||||
32,
|
||||
(width: Size["width"], height: Size["height"]) => onResized(width, height)
|
||||
);
|
||||
const debouncedResizement = debounce(32, onResized);
|
||||
// Will run onResized one time max every 16ms.
|
||||
const throttledResizement = throttle(
|
||||
16,
|
||||
(width: Size["width"], height: Size["height"]) => onResized(width, height)
|
||||
);
|
||||
const throttledResizement = throttle(16, onResized);
|
||||
|
||||
const handleResize = (e: MouseEvent) => {
|
||||
// Calculate the new element coordinates.
|
||||
|
@ -754,6 +746,22 @@ export function addResizementListener(
|
|||
};
|
||||
}
|
||||
|
||||
// TODO: Document and code
|
||||
export function t(text: string): string {
|
||||
return text;
|
||||
}
|
||||
|
||||
export function helpTip(text: string): HTMLElement {
|
||||
const container = document.createElement("a");
|
||||
container.className = "tip";
|
||||
const icon = document.createElement("img");
|
||||
icon.src = helpTipIcon;
|
||||
icon.className = "forced_title";
|
||||
icon.setAttribute("alt", text);
|
||||
icon.setAttribute("data-title", text);
|
||||
icon.setAttribute("data-use_title_for_force_title", "1");
|
||||
|
||||
container.appendChild(icon);
|
||||
|
||||
return container;
|
||||
}
|
||||
|
|
|
@ -132,7 +132,10 @@ describe("itemMetaDecoder function", () => {
|
|||
isFromCache: false,
|
||||
isFetching: false,
|
||||
isUpdating: false,
|
||||
editMode: false
|
||||
editMode: false,
|
||||
isBeingMoved: false,
|
||||
isBeingResized: false,
|
||||
isSelected: false
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -149,7 +152,10 @@ describe("itemMetaDecoder function", () => {
|
|||
isFromCache: false,
|
||||
isFetching: false,
|
||||
isUpdating: false,
|
||||
editMode: true
|
||||
editMode: true,
|
||||
isBeingMoved: false,
|
||||
isBeingResized: false,
|
||||
isSelected: false
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue