WIP: Visual console client

This commit is contained in:
Alejandro Gallardo Escobar 2019-07-29 11:33:11 +02:00
parent 30491a307c
commit 5c5d40cfd4
6 changed files with 229 additions and 64 deletions

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

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