mirror of
https://github.com/pandorafms/pandorafms.git
synced 2025-07-27 15:54:29 +02:00
Merge branch 'ent-3992-anadir-el-modo-de-edicion-a-la-vista-de-la-consola-visual' into 'develop'
Añadir el modo de edición a la vista de la consola visual Closes pandora_enterprise#3981 See merge request artica/pandorafms!2482
This commit is contained in:
commit
a583da3de3
@ -67,6 +67,13 @@ function createVisualConsole(
|
||||
? JSON.parse(data.items)
|
||||
: data.items;
|
||||
|
||||
// Add the datetime when the item was received.
|
||||
var receivedAt = new Date();
|
||||
items.map(function(item) {
|
||||
item["receivedAt"] = receivedAt;
|
||||
return item;
|
||||
});
|
||||
|
||||
var prevProps = visualConsole.props;
|
||||
// Update the data structure.
|
||||
visualConsole.props = props;
|
||||
|
@ -813,6 +813,15 @@ input.datos {
|
||||
* - VISUAL MAPS -
|
||||
* ---------------------------------------------------------------------
|
||||
*/
|
||||
.visual-console-edit-controls {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.visual-console-edit-controls > span {
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
input.vs_button_ghost {
|
||||
background-color: transparent !important;
|
||||
border: 1px solid #82b92e;
|
||||
|
@ -25,6 +25,12 @@
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.visual-console-item.is-editing {
|
||||
border: 2px dashed #33ccff;
|
||||
-webkit-transform: translateX(-2px) translateY(-2px);
|
||||
transform: translateX(-2px) translateY(-2px);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Alarm Clock;
|
||||
src: url(alarm-clock.ttf);
|
||||
|
@ -1 +1 @@
|
||||
{"version":3,"sources":["webpack:///main.css","webpack:///styles.css"],"names":[],"mappings":"AAAA;EACE,gBAAgB;EAChB,kBAAkB;EAClB,4BAA4B;EAC5B,0BAA0B;EAC1B,2BAA2B;AAC7B;;AAEA;EACE,kBAAkB;EAClB,oBAAa;EAAb,oBAAa;EAAb,aAAa;EACb,2BAAuB;EAAvB,8BAAuB;MAAvB,2BAAuB;UAAvB,uBAAuB;EACvB,qBAAqB;EACrB,yBAAmB;MAAnB,sBAAmB;UAAnB,mBAAmB;EACnB,yBAAiB;KAAjB,sBAAiB;MAAjB,qBAAiB;UAAjB,iBAAiB;AACnB;;ACfA;EACE,wBAAwB;EACxB,0BAA2B;AAC7B;;AAEA,kBAAkB;;AAElB;EACE,oBAAa;EAAb,oBAAa;EAAb,aAAa;EACb,4BAAsB;EAAtB,6BAAsB;MAAtB,0BAAsB;UAAtB,sBAAsB;EACtB,wBAAuB;MAAvB,qBAAuB;UAAvB,uBAAuB;EACvB,qBAAqB;EACrB,0BAAqB;MAArB,qBAAqB;EACrB,yBAAmB;MAAnB,sBAAmB;UAAnB,mBAAmB;AACrB;;AAEA;EACE,6DAA6D;EAC7D,eAAe;;EAEf,0BAA0B;EAC1B,mCAAmC;EACnC,kCAAkC;EAClC,kCAAkC;EAClC,wCAAwC;AAC1C;;AAEA;EACE,eAAe;AACjB;;AAEA;EACE,eAAe;AACjB;;AAEA,iBAAiB;;AAEjB;EACE,kBAAkB;AACpB;;AAEA;EACE,qDAA6C;UAA7C,6CAA6C;AAC/C;;AAEA;EACE,sDAA8C;UAA9C,8CAA8C;AAChD;;AAEA;EACE,oDAA4C;UAA5C,4CAA4C;AAC9C","file":"vc.main.css","sourcesContent":["#visual-console-container {\n margin: 0px auto;\n position: relative;\n background-repeat: no-repeat;\n background-size: 100% 100%;\n background-position: center;\n}\n\n.visual-console-item {\n position: absolute;\n display: flex;\n flex-direction: initial;\n justify-items: center;\n align-items: center;\n user-select: text;\n}\n","@font-face {\n font-family: Alarm Clock;\n src: url(./alarm-clock.ttf);\n}\n\n/* Digital clock */\n\n.visual-console-item .digital-clock {\n display: flex;\n flex-direction: column;\n justify-content: center;\n justify-items: center;\n align-content: center;\n align-items: center;\n}\n\n.visual-console-item .digital-clock > span {\n font-family: \"Alarm Clock\", \"Courier New\", Courier, monospace;\n font-size: 50px;\n\n /* To improve legibility */\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n text-rendering: optimizeLegibility;\n text-shadow: rgba(0, 0, 0, 0.01) 0 0 1px;\n}\n\n.visual-console-item .digital-clock > span.date {\n font-size: 25px;\n}\n\n.visual-console-item .digital-clock > span.timezone {\n font-size: 25px;\n}\n\n/* Analog clock */\n\n.visual-console-item .analogic-clock {\n text-align: center;\n}\n\n.visual-console-item .analogic-clock .hour-hand {\n animation: rotate-hour 43200s infinite linear;\n}\n\n.visual-console-item .analogic-clock .minute-hand {\n animation: rotate-minute 3600s infinite linear;\n}\n\n.visual-console-item .analogic-clock .second-hand {\n animation: rotate-second 60s infinite linear;\n}\n"],"sourceRoot":""}
|
||||
{"version":3,"sources":["webpack:///main.css","webpack:///styles.css"],"names":[],"mappings":"AAAA;EACE,gBAAgB;EAChB,kBAAkB;EAClB,4BAA4B;EAC5B,0BAA0B;EAC1B,2BAA2B;AAC7B;;AAEA;EACE,kBAAkB;EAClB,oBAAa;EAAb,oBAAa;EAAb,aAAa;EACb,2BAAuB;EAAvB,8BAAuB;MAAvB,2BAAuB;UAAvB,uBAAuB;EACvB,qBAAqB;EACrB,yBAAmB;MAAnB,sBAAmB;UAAnB,mBAAmB;EACnB,yBAAiB;KAAjB,sBAAiB;MAAjB,qBAAiB;UAAjB,iBAAiB;AACnB;;AAEA;EACE,0BAA0B;EAC1B,oDAA4C;UAA5C,4CAA4C;AAC9C;;ACpBA;EACE,wBAAwB;EACxB,0BAA2B;AAC7B;;AAEA,kBAAkB;;AAElB;EACE,oBAAa;EAAb,oBAAa;EAAb,aAAa;EACb,4BAAsB;EAAtB,6BAAsB;MAAtB,0BAAsB;UAAtB,sBAAsB;EACtB,wBAAuB;MAAvB,qBAAuB;UAAvB,uBAAuB;EACvB,qBAAqB;EACrB,0BAAqB;MAArB,qBAAqB;EACrB,yBAAmB;MAAnB,sBAAmB;UAAnB,mBAAmB;AACrB;;AAEA;EACE,6DAA6D;EAC7D,eAAe;;EAEf,0BAA0B;EAC1B,mCAAmC;EACnC,kCAAkC;EAClC,kCAAkC;EAClC,wCAAwC;AAC1C;;AAEA;EACE,eAAe;AACjB;;AAEA;EACE,eAAe;AACjB;;AAEA,iBAAiB;;AAEjB;EACE,kBAAkB;AACpB;;AAEA;EACE,qDAA6C;UAA7C,6CAA6C;AAC/C;;AAEA;EACE,sDAA8C;UAA9C,8CAA8C;AAChD;;AAEA;EACE,oDAA4C;UAA5C,4CAA4C;AAC9C","file":"vc.main.css","sourcesContent":["#visual-console-container {\n margin: 0px auto;\n position: relative;\n background-repeat: no-repeat;\n background-size: 100% 100%;\n background-position: center;\n}\n\n.visual-console-item {\n position: absolute;\n display: flex;\n flex-direction: initial;\n justify-items: center;\n align-items: center;\n user-select: text;\n}\n\n.visual-console-item.is-editing {\n border: 2px dashed #33ccff;\n transform: translateX(-2px) translateY(-2px);\n}\n","@font-face {\n font-family: Alarm Clock;\n src: url(./alarm-clock.ttf);\n}\n\n/* Digital clock */\n\n.visual-console-item .digital-clock {\n display: flex;\n flex-direction: column;\n justify-content: center;\n justify-items: center;\n align-content: center;\n align-items: center;\n}\n\n.visual-console-item .digital-clock > span {\n font-family: \"Alarm Clock\", \"Courier New\", Courier, monospace;\n font-size: 50px;\n\n /* To improve legibility */\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n text-rendering: optimizeLegibility;\n text-shadow: rgba(0, 0, 0, 0.01) 0 0 1px;\n}\n\n.visual-console-item .digital-clock > span.date {\n font-size: 25px;\n}\n\n.visual-console-item .digital-clock > span.timezone {\n font-size: 25px;\n}\n\n/* Analog clock */\n\n.visual-console-item .analogic-clock {\n text-align: center;\n}\n\n.visual-console-item .analogic-clock .hour-hand {\n animation: rotate-hour 43200s infinite linear;\n}\n\n.visual-console-item .analogic-clock .minute-hand {\n animation: rotate-minute 3600s infinite linear;\n}\n\n.visual-console-item .analogic-clock .second-hand {\n animation: rotate-second 60s infinite linear;\n}\n"],"sourceRoot":""}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -198,6 +198,14 @@ $visualConsoleItems = VisualConsole::getItemsFromDB(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the datetime when the item was received.
|
||||
var receivedAt = new Date();
|
||||
items.map(function(item) {
|
||||
item["receivedAt"] = receivedAt;
|
||||
return item;
|
||||
});
|
||||
|
||||
var visualConsoleManager = createVisualConsole(
|
||||
container,
|
||||
props,
|
||||
|
@ -155,6 +155,16 @@ if (!is_metaconsole()) {
|
||||
html_print_input_hidden('metaconsole', 1);
|
||||
}
|
||||
|
||||
if ($pure === false) {
|
||||
echo '<div class="visual-console-edit-controls">';
|
||||
echo '<span>'.__('Move and resize mode').'</span>';
|
||||
echo '<span>';
|
||||
echo html_print_checkbox_switch('edit-mode', 1, false, true);
|
||||
echo '</span>';
|
||||
echo '</div>';
|
||||
echo '<br />';
|
||||
}
|
||||
|
||||
echo '<div id="visual-console-container"></div>';
|
||||
|
||||
if ($pure === true) {
|
||||
@ -306,6 +316,14 @@ $visualConsoleItems = VisualConsole::getItemsFromDB(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the datetime when the item was received.
|
||||
var receivedAt = new Date();
|
||||
items.map(function(item) {
|
||||
item["receivedAt"] = receivedAt;
|
||||
return item;
|
||||
});
|
||||
|
||||
var visualConsoleManager = createVisualConsole(
|
||||
container,
|
||||
props,
|
||||
@ -315,6 +333,17 @@ $visualConsoleItems = VisualConsole::getItemsFromDB(
|
||||
handleUpdate
|
||||
);
|
||||
|
||||
// Enable/disable the edition mode.
|
||||
$('input[name=edit-mode]').change(function(event) {
|
||||
if ($(this).prop('checked')) {
|
||||
visualConsoleManager.visualConsole.enableEditMode();
|
||||
visualConsoleManager.changeUpdateInterval(0);
|
||||
} else {
|
||||
visualConsoleManager.visualConsole.disableEditMode();
|
||||
visualConsoleManager.changeUpdateInterval(<?php echo ($refr * 1000); ?>); // To ms.
|
||||
}
|
||||
});
|
||||
|
||||
// Update the data fetch interval.
|
||||
$('select#vc-refr').change(function(event) {
|
||||
var refr = Number.parseInt(event.target.value);
|
||||
|
@ -1,4 +1,10 @@
|
||||
import { Position, Size, UnknownObject, WithModuleProps } from "./types";
|
||||
import {
|
||||
Position,
|
||||
Size,
|
||||
AnyObject,
|
||||
WithModuleProps,
|
||||
ItemMeta
|
||||
} from "./lib/types";
|
||||
import {
|
||||
sizePropsDecoder,
|
||||
positionPropsDecoder,
|
||||
@ -9,7 +15,7 @@ import {
|
||||
humanDate,
|
||||
humanTime
|
||||
} from "./lib";
|
||||
import TypedEvent, { Listener, Disposable } from "./TypedEvent";
|
||||
import TypedEvent, { Listener, Disposable } from "./lib/TypedEvent";
|
||||
|
||||
// Enum: https://www.typescriptlang.org/docs/handbook/enums.html.
|
||||
export const enum ItemType {
|
||||
@ -52,14 +58,14 @@ export interface ItemProps extends Position, Size {
|
||||
// FIXME: Fix type compatibility.
|
||||
export interface ItemClickEvent<Props extends ItemProps> {
|
||||
// data: Props;
|
||||
data: UnknownObject;
|
||||
data: AnyObject;
|
||||
nativeEvent: Event;
|
||||
}
|
||||
|
||||
// FIXME: Fix type compatibility.
|
||||
export interface ItemRemoveEvent<Props extends ItemProps> {
|
||||
// data: Props;
|
||||
data: UnknownObject;
|
||||
data: AnyObject;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -89,7 +95,7 @@ const parseLabelPosition = (
|
||||
* @throws Will throw a TypeError if some property
|
||||
* is missing from the raw object or have an invalid type.
|
||||
*/
|
||||
export function itemBasePropsDecoder(data: UnknownObject): ItemProps | never {
|
||||
export function itemBasePropsDecoder(data: AnyObject): ItemProps | never {
|
||||
if (data.id == null || isNaN(parseInt(data.id))) {
|
||||
throw new TypeError("invalid id.");
|
||||
}
|
||||
@ -118,6 +124,8 @@ export function itemBasePropsDecoder(data: UnknownObject): ItemProps | never {
|
||||
abstract class VisualConsoleItem<Props extends ItemProps> {
|
||||
// Properties of the item.
|
||||
private itemProps: Props;
|
||||
// Metadata of the item.
|
||||
private _metadata: ItemMeta;
|
||||
// Reference to the DOM element which will contain the item.
|
||||
public elementRef: HTMLElement;
|
||||
public readonly labelElementRef: HTMLElement;
|
||||
@ -138,8 +146,9 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
|
||||
*/
|
||||
protected abstract createDomElement(): HTMLElement;
|
||||
|
||||
public constructor(props: Props) {
|
||||
public constructor(props: Props, metadata: ItemMeta) {
|
||||
this.itemProps = props;
|
||||
this._metadata = metadata;
|
||||
|
||||
/*
|
||||
* Get a HTMLElement which represents the container box
|
||||
@ -185,8 +194,14 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
|
||||
box.style.zIndex = this.props.isOnTop ? "2" : "1";
|
||||
box.style.left = `${this.props.x}px`;
|
||||
box.style.top = `${this.props.y}px`;
|
||||
box.onclick = e =>
|
||||
box.addEventListener("click", e => {
|
||||
if (this.meta.editMode) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
} else {
|
||||
this.clickEventManager.emit({ data: this.props, nativeEvent: e });
|
||||
}
|
||||
});
|
||||
|
||||
return box;
|
||||
}
|
||||
@ -310,7 +325,34 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
|
||||
// From this point, things which rely on this.props can access to the changes.
|
||||
|
||||
// Check if we should re-render.
|
||||
if (this.shouldBeUpdated(prevProps, newProps)) this.render(prevProps);
|
||||
if (this.shouldBeUpdated(prevProps, newProps))
|
||||
this.render(prevProps, this._metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Public accessor of the `meta` property.
|
||||
* @return Properties.
|
||||
*/
|
||||
public get meta(): ItemMeta {
|
||||
return { ...this._metadata }; // Return a copy.
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter of the `meta` property.
|
||||
* If the new meta are different enough than the
|
||||
* stored meta, a render would be fired.
|
||||
* @param newProps
|
||||
*/
|
||||
public set meta(newMetadata: ItemMeta) {
|
||||
const prevMetadata = this._metadata;
|
||||
// Update the internal meta.
|
||||
this._metadata = newMetadata;
|
||||
|
||||
// From this point, things which rely on this.props can access to the changes.
|
||||
|
||||
// Check if we should re-render.
|
||||
// if (this.shouldBeUpdated(prevMetadata, newMetadata))
|
||||
this.render(this.itemProps, prevMetadata);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -333,7 +375,10 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
|
||||
* To recreate or update the HTMLElement which represents the item into the DOM.
|
||||
* @param prevProps If exists it will be used to only perform DOM updates instead of a full replace.
|
||||
*/
|
||||
public render(prevProps: Props | null = null): void {
|
||||
public render(
|
||||
prevProps: Props | null = null,
|
||||
prevMeta: ItemMeta | null = null
|
||||
): void {
|
||||
this.updateDomElement(this.childElementRef);
|
||||
|
||||
// Move box.
|
||||
@ -378,6 +423,29 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
|
||||
// Changed the reference to the main element. It's ugly, but needed.
|
||||
this.elementRef = container;
|
||||
}
|
||||
|
||||
// Change metadata related things.
|
||||
if (!prevMeta || prevMeta.editMode !== this.meta.editMode) {
|
||||
if (this.meta.editMode) {
|
||||
this.elementRef.classList.add("is-editing");
|
||||
} else {
|
||||
this.elementRef.classList.remove("is-editing");
|
||||
}
|
||||
}
|
||||
if (!prevMeta || prevMeta.isFetching !== this.meta.isFetching) {
|
||||
if (this.meta.isFetching) {
|
||||
this.elementRef.classList.add("is-fetching");
|
||||
} else {
|
||||
this.elementRef.classList.remove("is-fetching");
|
||||
}
|
||||
}
|
||||
if (!prevMeta || prevMeta.isUpdating !== this.meta.isUpdating) {
|
||||
if (this.meta.isUpdating) {
|
||||
this.elementRef.classList.add("is-updating");
|
||||
} else {
|
||||
this.elementRef.classList.remove("is-updating");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { UnknownObject, Size } from "./types";
|
||||
import { AnyObject, Size } from "./lib/types";
|
||||
import {
|
||||
parseBoolean,
|
||||
sizePropsDecoder,
|
||||
parseIntOr,
|
||||
notEmptyStringOr
|
||||
notEmptyStringOr,
|
||||
itemMetaDecoder
|
||||
} from "./lib";
|
||||
import Item, {
|
||||
ItemType,
|
||||
@ -24,7 +25,7 @@ import EventsHistory, {
|
||||
eventsHistoryPropsDecoder
|
||||
} from "./items/EventsHistory";
|
||||
import Percentile, { percentilePropsDecoder } from "./items/Percentile";
|
||||
import TypedEvent, { Disposable, Listener } from "./TypedEvent";
|
||||
import TypedEvent, { Disposable, Listener } from "./lib/TypedEvent";
|
||||
import DonutGraph, { donutGraphPropsDecoder } from "./items/DonutGraph";
|
||||
import BarsGraph, { barsGraphPropsDecoder } from "./items/BarsGraph";
|
||||
import ModuleGraph, { moduleGraphPropsDecoder } from "./items/ModuleGraph";
|
||||
@ -32,47 +33,49 @@ import Service, { servicePropsDecoder } from "./items/Service";
|
||||
|
||||
// TODO: Document.
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
function itemInstanceFrom(data: UnknownObject) {
|
||||
function itemInstanceFrom(data: AnyObject) {
|
||||
const type = parseIntOr(data.type, null);
|
||||
if (type == null) throw new TypeError("missing item type.");
|
||||
|
||||
const meta = itemMetaDecoder(data);
|
||||
|
||||
switch (type as ItemType) {
|
||||
case ItemType.STATIC_GRAPH:
|
||||
return new StaticGraph(staticGraphPropsDecoder(data));
|
||||
return new StaticGraph(staticGraphPropsDecoder(data), meta);
|
||||
case ItemType.MODULE_GRAPH:
|
||||
return new ModuleGraph(moduleGraphPropsDecoder(data));
|
||||
return new ModuleGraph(moduleGraphPropsDecoder(data), meta);
|
||||
case ItemType.SIMPLE_VALUE:
|
||||
case ItemType.SIMPLE_VALUE_MAX:
|
||||
case ItemType.SIMPLE_VALUE_MIN:
|
||||
case ItemType.SIMPLE_VALUE_AVG:
|
||||
return new SimpleValue(simpleValuePropsDecoder(data));
|
||||
return new SimpleValue(simpleValuePropsDecoder(data), meta);
|
||||
case ItemType.PERCENTILE_BAR:
|
||||
case ItemType.PERCENTILE_BUBBLE:
|
||||
case ItemType.CIRCULAR_PROGRESS_BAR:
|
||||
case ItemType.CIRCULAR_INTERIOR_PROGRESS_BAR:
|
||||
return new Percentile(percentilePropsDecoder(data));
|
||||
return new Percentile(percentilePropsDecoder(data), meta);
|
||||
case ItemType.LABEL:
|
||||
return new Label(labelPropsDecoder(data));
|
||||
return new Label(labelPropsDecoder(data), meta);
|
||||
case ItemType.ICON:
|
||||
return new Icon(iconPropsDecoder(data));
|
||||
return new Icon(iconPropsDecoder(data), meta);
|
||||
case ItemType.SERVICE:
|
||||
return new Service(servicePropsDecoder(data));
|
||||
return new Service(servicePropsDecoder(data), meta);
|
||||
case ItemType.GROUP_ITEM:
|
||||
return new Group(groupPropsDecoder(data));
|
||||
return new Group(groupPropsDecoder(data), meta);
|
||||
case ItemType.BOX_ITEM:
|
||||
return new Box(boxPropsDecoder(data));
|
||||
return new Box(boxPropsDecoder(data), meta);
|
||||
case ItemType.LINE_ITEM:
|
||||
return new Line(linePropsDecoder(data));
|
||||
return new Line(linePropsDecoder(data), meta);
|
||||
case ItemType.AUTO_SLA_GRAPH:
|
||||
return new EventsHistory(eventsHistoryPropsDecoder(data));
|
||||
return new EventsHistory(eventsHistoryPropsDecoder(data), meta);
|
||||
case ItemType.DONUT_GRAPH:
|
||||
return new DonutGraph(donutGraphPropsDecoder(data));
|
||||
return new DonutGraph(donutGraphPropsDecoder(data), meta);
|
||||
case ItemType.BARS_GRAPH:
|
||||
return new BarsGraph(barsGraphPropsDecoder(data));
|
||||
return new BarsGraph(barsGraphPropsDecoder(data), meta);
|
||||
case ItemType.CLOCK:
|
||||
return new Clock(clockPropsDecoder(data));
|
||||
return new Clock(clockPropsDecoder(data), meta);
|
||||
case ItemType.COLOR_CLOUD:
|
||||
return new ColorCloud(colorCloudPropsDecoder(data));
|
||||
return new ColorCloud(colorCloudPropsDecoder(data), meta);
|
||||
default:
|
||||
throw new TypeError("item not found");
|
||||
}
|
||||
@ -80,7 +83,7 @@ function itemInstanceFrom(data: UnknownObject) {
|
||||
|
||||
// TODO: Document.
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
function decodeProps(data: UnknownObject) {
|
||||
function decodeProps(data: AnyObject) {
|
||||
const type = parseIntOr(data.type, null);
|
||||
if (type == null) throw new TypeError("missing item type.");
|
||||
|
||||
@ -147,7 +150,7 @@ export interface VisualConsoleProps extends Size {
|
||||
* is missing from the raw object or have an invalid type.
|
||||
*/
|
||||
export function visualConsolePropsDecoder(
|
||||
data: UnknownObject
|
||||
data: AnyObject
|
||||
): VisualConsoleProps | never {
|
||||
// Object destructuring: http://es6-features.org/#ObjectMatchingShorthandNotation
|
||||
const {
|
||||
@ -226,8 +229,8 @@ export default class VisualConsole {
|
||||
|
||||
public constructor(
|
||||
container: HTMLElement,
|
||||
props: UnknownObject,
|
||||
items: UnknownObject[]
|
||||
props: AnyObject,
|
||||
items: AnyObject[]
|
||||
) {
|
||||
this.containerRef = container;
|
||||
this._props = visualConsolePropsDecoder(props);
|
||||
@ -288,13 +291,13 @@ export default class VisualConsole {
|
||||
* Public setter of the `elements` property.
|
||||
* @param items.
|
||||
*/
|
||||
public updateElements(items: UnknownObject[]): void {
|
||||
const itemIds = items.map(item => item.id || null).filter(id => id != null);
|
||||
itemIds as number[]; // Tell the type system to rely on us.
|
||||
public updateElements(items: AnyObject[]): void {
|
||||
// Ensure the type cause Typescript doesn't know the filter removes null items.
|
||||
const itemIds = items
|
||||
.map(item => item.id || null)
|
||||
.filter(id => id != null) as number[];
|
||||
// Get the elements we should delete.
|
||||
const deletedIds: number[] = this.elementIds.filter(
|
||||
id => itemIds.indexOf(id) < 0
|
||||
);
|
||||
const deletedIds = this.elementIds.filter(id => itemIds.indexOf(id) < 0);
|
||||
// Delete the elements.
|
||||
deletedIds.forEach(id => {
|
||||
if (this.elementsById[id] != null) {
|
||||
@ -530,6 +533,9 @@ export default class VisualConsole {
|
||||
height: 0,
|
||||
lineWidth: this.props.relationLineWidth,
|
||||
color: "#CCCCCC"
|
||||
}),
|
||||
itemMetaDecoder({
|
||||
receivedAt: new Date()
|
||||
})
|
||||
);
|
||||
// Save a reference to the line item.
|
||||
@ -557,4 +563,22 @@ export default class VisualConsole {
|
||||
|
||||
return disposable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the edition mode.
|
||||
*/
|
||||
public enableEditMode(): void {
|
||||
this.elements.forEach(item => {
|
||||
item.meta = { ...item.meta, editMode: true };
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the edition mode.
|
||||
*/
|
||||
public disableEditMode(): void {
|
||||
this.elements.forEach(item => {
|
||||
item.meta = { ...item.meta, editMode: false };
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { UnknownObject, WithModuleProps } from "../types";
|
||||
import { AnyObject, WithModuleProps } from "../lib/types";
|
||||
import { modulePropsDecoder, decodeBase64, stringIsEmpty } from "../lib";
|
||||
import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
|
||||
|
||||
@ -17,9 +17,7 @@ export type BarsGraphProps = {
|
||||
* @throws Will throw a TypeError if some property
|
||||
* is missing from the raw object or have an invalid type.
|
||||
*/
|
||||
export function barsGraphPropsDecoder(
|
||||
data: UnknownObject
|
||||
): BarsGraphProps | never {
|
||||
export function barsGraphPropsDecoder(data: AnyObject): BarsGraphProps | never {
|
||||
if (stringIsEmpty(data.html) && stringIsEmpty(data.encodedHtml)) {
|
||||
throw new TypeError("missing html content.");
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { UnknownObject } from "../types";
|
||||
import { AnyObject } from "../lib/types";
|
||||
import { parseIntOr, notEmptyStringOr } from "../lib";
|
||||
import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
|
||||
|
||||
@ -24,7 +24,7 @@ interface BoxProps extends ItemProps {
|
||||
* @throws Will throw a TypeError if some property
|
||||
* is missing from the raw object or have an invalid type.
|
||||
*/
|
||||
export function boxPropsDecoder(data: UnknownObject): BoxProps | never {
|
||||
export function boxPropsDecoder(data: AnyObject): BoxProps | never {
|
||||
return {
|
||||
...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
|
||||
type: ItemType.BOX_ITEM,
|
||||
|
@ -1,6 +1,11 @@
|
||||
import "./styles.css";
|
||||
|
||||
import { LinkedVisualConsoleProps, UnknownObject, Size } from "../../types";
|
||||
import {
|
||||
LinkedVisualConsoleProps,
|
||||
AnyObject,
|
||||
Size,
|
||||
ItemMeta
|
||||
} from "../../lib/types";
|
||||
import {
|
||||
linkedVCPropsDecoder,
|
||||
parseIntOr,
|
||||
@ -60,7 +65,7 @@ const parseClockFormat = (clockFormat: unknown): ClockProps["clockFormat"] => {
|
||||
* @throws Will throw a TypeError if some property
|
||||
* is missing from the raw object or have an invalid type.
|
||||
*/
|
||||
export function clockPropsDecoder(data: UnknownObject): ClockProps | never {
|
||||
export function clockPropsDecoder(data: AnyObject): ClockProps | never {
|
||||
if (
|
||||
typeof data.clockTimezone !== "string" ||
|
||||
data.clockTimezone.length === 0
|
||||
@ -85,9 +90,9 @@ export default class Clock extends Item<ClockProps> {
|
||||
public static readonly TICK_INTERVAL = 1000; // In ms.
|
||||
private intervalRef: number | null = null;
|
||||
|
||||
public constructor(props: ClockProps) {
|
||||
public constructor(props: ClockProps, meta: ItemMeta) {
|
||||
// Call the superclass constructor.
|
||||
super(props);
|
||||
super(props, meta);
|
||||
|
||||
/* The item is already loaded and inserted into the DOM.
|
||||
* The class properties are now initialized.
|
||||
|
@ -1,4 +1,5 @@
|
||||
import Clock, { clockPropsDecoder } from ".";
|
||||
import { itemMetaDecoder } from "../../lib";
|
||||
|
||||
const genericRawProps = {
|
||||
id: 1,
|
||||
@ -46,6 +47,9 @@ describe("Clock item", () => {
|
||||
...sizeRawProps,
|
||||
...linkedModuleProps,
|
||||
...digitalClockProps
|
||||
}),
|
||||
itemMetaDecoder({
|
||||
receivedAt: new Date(1)
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import ColorCloud, { colorCloudPropsDecoder } from "./ColorCloud";
|
||||
import { itemMetaDecoder } from "../lib";
|
||||
|
||||
const genericRawProps = {
|
||||
id: 1,
|
||||
@ -41,6 +42,9 @@ describe("Color cloud item", () => {
|
||||
...sizeRawProps,
|
||||
...linkedModuleProps,
|
||||
...colorCloudProps
|
||||
}),
|
||||
itemMetaDecoder({
|
||||
receivedAt: new Date(1)
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import {
|
||||
WithModuleProps,
|
||||
LinkedVisualConsoleProps,
|
||||
UnknownObject
|
||||
} from "../types";
|
||||
AnyObject
|
||||
} from "../lib/types";
|
||||
import { modulePropsDecoder, linkedVCPropsDecoder } from "../lib";
|
||||
import Item, { itemBasePropsDecoder, ItemType, ItemProps } from "../Item";
|
||||
|
||||
@ -24,7 +24,7 @@ export type ColorCloudProps = {
|
||||
* is missing from the raw object or have an invalid type.
|
||||
*/
|
||||
export function colorCloudPropsDecoder(
|
||||
data: UnknownObject
|
||||
data: AnyObject
|
||||
): ColorCloudProps | never {
|
||||
// TODO: Validate the color.
|
||||
if (typeof data.color !== "string" || data.color.length === 0) {
|
||||
|
@ -1,8 +1,8 @@
|
||||
import {
|
||||
LinkedVisualConsoleProps,
|
||||
UnknownObject,
|
||||
AnyObject,
|
||||
WithModuleProps
|
||||
} from "../types";
|
||||
} from "../lib/types";
|
||||
import {
|
||||
linkedVCPropsDecoder,
|
||||
modulePropsDecoder,
|
||||
@ -28,7 +28,7 @@ export type DonutGraphProps = {
|
||||
* is missing from the raw object or have an invalid type.
|
||||
*/
|
||||
export function donutGraphPropsDecoder(
|
||||
data: UnknownObject
|
||||
data: AnyObject
|
||||
): DonutGraphProps | never {
|
||||
if (stringIsEmpty(data.html) && stringIsEmpty(data.encodedHtml)) {
|
||||
throw new TypeError("missing html content.");
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { UnknownObject, WithModuleProps } from "../types";
|
||||
import { AnyObject, WithModuleProps } from "../lib/types";
|
||||
import {
|
||||
modulePropsDecoder,
|
||||
parseIntOr,
|
||||
@ -24,7 +24,7 @@ export type EventsHistoryProps = {
|
||||
* is missing from the raw object or have an invalid type.
|
||||
*/
|
||||
export function eventsHistoryPropsDecoder(
|
||||
data: UnknownObject
|
||||
data: AnyObject
|
||||
): EventsHistoryProps | never {
|
||||
if (stringIsEmpty(data.html) && stringIsEmpty(data.encodedHtml)) {
|
||||
throw new TypeError("missing html content.");
|
||||
|
@ -1,4 +1,5 @@
|
||||
import Group, { groupPropsDecoder } from "./Group";
|
||||
import { itemMetaDecoder } from "../lib";
|
||||
|
||||
const genericRawProps = {
|
||||
id: 1,
|
||||
@ -33,6 +34,9 @@ describe("Group item", () => {
|
||||
...positionRawProps,
|
||||
...sizeRawProps,
|
||||
...groupRawProps
|
||||
}),
|
||||
itemMetaDecoder({
|
||||
receivedAt: new Date(1)
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { LinkedVisualConsoleProps, UnknownObject } from "../types";
|
||||
import { LinkedVisualConsoleProps, AnyObject } from "../lib/types";
|
||||
import {
|
||||
linkedVCPropsDecoder,
|
||||
parseIntOr,
|
||||
@ -19,7 +19,7 @@ export type GroupProps = {
|
||||
} & ItemProps &
|
||||
LinkedVisualConsoleProps;
|
||||
|
||||
function extractHtml(data: UnknownObject): string | null {
|
||||
function extractHtml(data: AnyObject): string | null {
|
||||
if (!stringIsEmpty(data.html)) return data.html;
|
||||
if (!stringIsEmpty(data.encodedHtml)) return decodeBase64(data.encodedHtml);
|
||||
return null;
|
||||
@ -34,7 +34,7 @@ function extractHtml(data: UnknownObject): string | null {
|
||||
* @throws Will throw a TypeError if some property
|
||||
* is missing from the raw object or have an invalid type.
|
||||
*/
|
||||
export function groupPropsDecoder(data: UnknownObject): GroupProps | never {
|
||||
export function groupPropsDecoder(data: AnyObject): GroupProps | never {
|
||||
if (
|
||||
(typeof data.imageSrc !== "string" || data.imageSrc.length === 0) &&
|
||||
data.encodedHtml === null
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { LinkedVisualConsoleProps, UnknownObject } from "../types";
|
||||
import { LinkedVisualConsoleProps, AnyObject } from "../lib/types";
|
||||
import { linkedVCPropsDecoder } from "../lib";
|
||||
import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
|
||||
|
||||
@ -17,7 +17,7 @@ export type IconProps = {
|
||||
* @throws Will throw a TypeError if some property
|
||||
* is missing from the raw object or have an invalid type.
|
||||
*/
|
||||
export function iconPropsDecoder(data: UnknownObject): IconProps | never {
|
||||
export function iconPropsDecoder(data: AnyObject): IconProps | never {
|
||||
if (typeof data.imageSrc !== "string" || data.imageSrc.length === 0) {
|
||||
throw new TypeError("invalid image src.");
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { LinkedVisualConsoleProps, UnknownObject } from "../types";
|
||||
import { LinkedVisualConsoleProps, AnyObject } from "../lib/types";
|
||||
import { linkedVCPropsDecoder } from "../lib";
|
||||
import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
|
||||
|
||||
@ -16,7 +16,7 @@ export type LabelProps = {
|
||||
* @throws Will throw a TypeError if some property
|
||||
* is missing from the raw object or have an invalid type.
|
||||
*/
|
||||
export function labelPropsDecoder(data: UnknownObject): LabelProps | never {
|
||||
export function labelPropsDecoder(data: AnyObject): LabelProps | never {
|
||||
return {
|
||||
...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
|
||||
type: ItemType.LABEL,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { UnknownObject, Position, Size } from "../types";
|
||||
import { AnyObject, Position, Size, ItemMeta } from "../lib/types";
|
||||
import { parseIntOr, notEmptyStringOr } from "../lib";
|
||||
import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
|
||||
|
||||
@ -25,7 +25,7 @@ interface LineProps extends ItemProps {
|
||||
* @throws Will throw a TypeError if some property
|
||||
* is missing from the raw object or have an invalid type.
|
||||
*/
|
||||
export function linePropsDecoder(data: UnknownObject): LineProps | never {
|
||||
export function linePropsDecoder(data: AnyObject): LineProps | never {
|
||||
const props: LineProps = {
|
||||
...itemBasePropsDecoder({ ...data, width: 1, height: 1 }), // Object spread. It will merge the properties of the two objects.
|
||||
type: ItemType.LINE_ITEM,
|
||||
@ -71,17 +71,20 @@ export default class Line extends Item<LineProps> {
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
public constructor(props: LineProps) {
|
||||
public constructor(props: LineProps, meta: ItemMeta) {
|
||||
/*
|
||||
* We need to override the constructor cause we need to obtain
|
||||
* the
|
||||
* box size and position from the start and finish points
|
||||
* of the line.
|
||||
*/
|
||||
super({
|
||||
super(
|
||||
{
|
||||
...props,
|
||||
...Line.extractBoxSizeAndPosition(props)
|
||||
});
|
||||
},
|
||||
meta
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,8 +1,8 @@
|
||||
import {
|
||||
LinkedVisualConsoleProps,
|
||||
UnknownObject,
|
||||
AnyObject,
|
||||
WithModuleProps
|
||||
} from "../types";
|
||||
} from "../lib/types";
|
||||
import {
|
||||
linkedVCPropsDecoder,
|
||||
modulePropsDecoder,
|
||||
@ -28,7 +28,7 @@ export type ModuleGraphProps = {
|
||||
* is missing from the raw object or have an invalid type.
|
||||
*/
|
||||
export function moduleGraphPropsDecoder(
|
||||
data: UnknownObject
|
||||
data: AnyObject
|
||||
): ModuleGraphProps | never {
|
||||
if (stringIsEmpty(data.html) && stringIsEmpty(data.encodedHtml)) {
|
||||
throw new TypeError("missing html content.");
|
||||
|
@ -2,9 +2,9 @@ import { arc as arcFactory } from "d3-shape";
|
||||
|
||||
import {
|
||||
LinkedVisualConsoleProps,
|
||||
UnknownObject,
|
||||
AnyObject,
|
||||
WithModuleProps
|
||||
} from "../types";
|
||||
} from "../lib/types";
|
||||
import {
|
||||
linkedVCPropsDecoder,
|
||||
modulePropsDecoder,
|
||||
@ -81,7 +81,7 @@ function extractValueType(valueType: unknown): PercentileProps["valueType"] {
|
||||
* is missing from the raw object or have an invalid type.
|
||||
*/
|
||||
export function percentilePropsDecoder(
|
||||
data: UnknownObject
|
||||
data: AnyObject
|
||||
): PercentileProps | never {
|
||||
return {
|
||||
...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { UnknownObject } from "../types";
|
||||
import { AnyObject } from "../lib/types";
|
||||
import {
|
||||
stringIsEmpty,
|
||||
notEmptyStringOr,
|
||||
@ -24,7 +24,7 @@ export type ServiceProps = {
|
||||
* @throws Will throw a TypeError if some property
|
||||
* is missing from the raw object or have an invalid type.
|
||||
*/
|
||||
export function servicePropsDecoder(data: UnknownObject): ServiceProps | never {
|
||||
export function servicePropsDecoder(data: AnyObject): ServiceProps | never {
|
||||
if (data.imageSrc !== null) {
|
||||
if (
|
||||
typeof data.statusImageSrc !== "string" ||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import {
|
||||
LinkedVisualConsoleProps,
|
||||
UnknownObject,
|
||||
AnyObject,
|
||||
WithModuleProps
|
||||
} from "../types";
|
||||
} from "../lib/types";
|
||||
import {
|
||||
linkedVCPropsDecoder,
|
||||
parseIntOr,
|
||||
@ -69,7 +69,7 @@ const parseProcessValue = (
|
||||
* is missing from the raw object or have an invalid type.
|
||||
*/
|
||||
export function simpleValuePropsDecoder(
|
||||
data: UnknownObject
|
||||
data: AnyObject
|
||||
): SimpleValueProps | never {
|
||||
if (typeof data.value !== "string" || data.value.length === 0) {
|
||||
throw new TypeError("invalid value");
|
||||
|
@ -1,8 +1,8 @@
|
||||
import {
|
||||
WithModuleProps,
|
||||
LinkedVisualConsoleProps,
|
||||
UnknownObject
|
||||
} from "../types";
|
||||
AnyObject
|
||||
} from "../lib/types";
|
||||
|
||||
import {
|
||||
modulePropsDecoder,
|
||||
@ -47,7 +47,7 @@ const parseShowLastValueTooltip = (
|
||||
* is missing from the raw object or have an invalid type.
|
||||
*/
|
||||
export function staticGraphPropsDecoder(
|
||||
data: UnknownObject
|
||||
data: AnyObject
|
||||
): StaticGraphProps | never {
|
||||
if (typeof data.imageSrc !== "string" || data.imageSrc.length === 0) {
|
||||
throw new TypeError("invalid image src.");
|
||||
|
@ -1,4 +1,4 @@
|
||||
import TypedEvent, { Disposable, Listener } from "../TypedEvent";
|
||||
import TypedEvent, { Disposable, Listener } from "./TypedEvent";
|
||||
|
||||
interface Cancellable {
|
||||
cancel(): void;
|
||||
|
@ -1,12 +1,14 @@
|
||||
import {
|
||||
UnknownObject,
|
||||
AnyObject,
|
||||
Position,
|
||||
Size,
|
||||
WithAgentProps,
|
||||
WithModuleProps,
|
||||
LinkedVisualConsoleProps,
|
||||
LinkedVisualConsolePropsStatus
|
||||
} from "../types";
|
||||
LinkedVisualConsolePropsStatus,
|
||||
UnknownObject,
|
||||
ItemMeta
|
||||
} from "./types";
|
||||
|
||||
/**
|
||||
* Return a number or a default value from a raw value.
|
||||
@ -72,6 +74,23 @@ export function parseBoolean(value: unknown): boolean {
|
||||
else return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a valid date or a default value from a raw value.
|
||||
* @param value Raw value from which we will try to extract a valid date.
|
||||
* @param defaultValue Default value to use if we cannot extract a valid date.
|
||||
* @return A valid date or the default value.
|
||||
*/
|
||||
export function parseDateOr<T>(value: unknown, defaultValue: T): Date | T {
|
||||
if (value instanceof Date) return value;
|
||||
else if (typeof value === "number") return new Date(value * 1000);
|
||||
else if (
|
||||
typeof value === "string" &&
|
||||
!Number.isNaN(new Date(value).getTime())
|
||||
)
|
||||
return new Date(value);
|
||||
else return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pad the current string with another string (multiple times, if needed)
|
||||
* until the resulting string reaches the given length.
|
||||
@ -113,7 +132,7 @@ export function leftPad(
|
||||
* @param data Raw object.
|
||||
* @return An object representing the position.
|
||||
*/
|
||||
export function positionPropsDecoder(data: UnknownObject): Position {
|
||||
export function positionPropsDecoder(data: AnyObject): Position {
|
||||
return {
|
||||
x: parseIntOr(data.x, 0),
|
||||
y: parseIntOr(data.y, 0)
|
||||
@ -126,7 +145,7 @@ export function positionPropsDecoder(data: UnknownObject): Position {
|
||||
* @return An object representing the size.
|
||||
* @throws Will throw a TypeError if the width and height are not valid numbers.
|
||||
*/
|
||||
export function sizePropsDecoder(data: UnknownObject): Size | never {
|
||||
export function sizePropsDecoder(data: AnyObject): Size | never {
|
||||
if (
|
||||
data.width == null ||
|
||||
isNaN(parseInt(data.width)) ||
|
||||
@ -147,7 +166,7 @@ export function sizePropsDecoder(data: UnknownObject): Size | never {
|
||||
* @param data Raw object.
|
||||
* @return An object representing the agent properties.
|
||||
*/
|
||||
export function agentPropsDecoder(data: UnknownObject): WithAgentProps {
|
||||
export function agentPropsDecoder(data: AnyObject): WithAgentProps {
|
||||
const agentProps: WithAgentProps = {
|
||||
agentId: parseIntOr(data.agent, null),
|
||||
agentName: notEmptyStringOr(data.agentName, null),
|
||||
@ -169,7 +188,7 @@ export function agentPropsDecoder(data: UnknownObject): WithAgentProps {
|
||||
* @param data Raw object.
|
||||
* @return An object representing the module and agent properties.
|
||||
*/
|
||||
export function modulePropsDecoder(data: UnknownObject): WithModuleProps {
|
||||
export function modulePropsDecoder(data: AnyObject): WithModuleProps {
|
||||
return {
|
||||
moduleId: parseIntOr(data.moduleId, null),
|
||||
moduleName: notEmptyStringOr(data.moduleName, null),
|
||||
@ -185,7 +204,7 @@ export function modulePropsDecoder(data: UnknownObject): WithModuleProps {
|
||||
* @throws Will throw a TypeError if the status calculation properties are invalid.
|
||||
*/
|
||||
export function linkedVCPropsDecoder(
|
||||
data: UnknownObject
|
||||
data: AnyObject
|
||||
): LinkedVisualConsoleProps | never {
|
||||
// Object destructuring: http://es6-features.org/#ObjectMatchingShorthandNotation
|
||||
const {
|
||||
@ -246,6 +265,29 @@ export function linkedVCPropsDecoder(
|
||||
: linkedLayoutBaseProps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a valid typed object from a raw object.
|
||||
* @param data Raw object.
|
||||
* @return An object representing the item's meta properties.
|
||||
*/
|
||||
export function itemMetaDecoder(data: UnknownObject): ItemMeta | never {
|
||||
const receivedAt = parseDateOr(data.receivedAt, null);
|
||||
if (receivedAt === null) throw new TypeError("invalid meta structure");
|
||||
|
||||
let error = null;
|
||||
if (data.error instanceof Error) error = data.error;
|
||||
else if (typeof data.error === "string") error = new Error(data.error);
|
||||
|
||||
return {
|
||||
receivedAt,
|
||||
error,
|
||||
editMode: parseBoolean(data.editMode),
|
||||
isFromCache: parseBoolean(data.isFromCache),
|
||||
isFetching: false,
|
||||
isUpdating: false
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* To get a CSS rule with the most used prefixes.
|
||||
* @param ruleName Name of the CSS rule.
|
||||
|
@ -7,7 +7,8 @@ import {
|
||||
decodeBase64,
|
||||
humanDate,
|
||||
humanTime,
|
||||
replaceMacros
|
||||
replaceMacros,
|
||||
itemMetaDecoder
|
||||
} from ".";
|
||||
|
||||
describe("function parseIntOr", () => {
|
||||
@ -72,14 +73,14 @@ describe("function prefixedCssRules", () => {
|
||||
|
||||
describe("function decodeBase64", () => {
|
||||
it("should decode the base64 without errors", () => {
|
||||
expect(decodeBase64("SGkgSSdtIGRlY29kZWQ=")).toEqual("Hi I'm decoded");
|
||||
expect(decodeBase64("Rk9PQkFSQkFa")).toEqual("FOOBARBAZ");
|
||||
expect(decodeBase64("eyJpZCI6MSwibmFtZSI6ImZvbyJ9")).toEqual(
|
||||
expect(decodeBase64("SGkgSSdtIGRlY29kZWQ=")).toBe("Hi I'm decoded");
|
||||
expect(decodeBase64("Rk9PQkFSQkFa")).toBe("FOOBARBAZ");
|
||||
expect(decodeBase64("eyJpZCI6MSwibmFtZSI6ImZvbyJ9")).toBe(
|
||||
'{"id":1,"name":"foo"}'
|
||||
);
|
||||
expect(
|
||||
decodeBase64("PGRpdj5Cb3ggPHA+UGFyYWdyYXBoPC9wPjxociAvPjwvZGl2Pg==")
|
||||
).toEqual("<div>Box <p>Paragraph</p><hr /></div>");
|
||||
).toBe("<div>Box <p>Paragraph</p><hr /></div>");
|
||||
});
|
||||
});
|
||||
|
||||
@ -118,3 +119,46 @@ describe("replaceMacros function", () => {
|
||||
expect(replaceMacros(macros, text)).toBe("Lorem foo Ipsum baz");
|
||||
});
|
||||
});
|
||||
|
||||
describe("itemMetaDecoder function", () => {
|
||||
it("should extract a default meta object", () => {
|
||||
expect(
|
||||
itemMetaDecoder({
|
||||
receivedAt: 1
|
||||
})
|
||||
).toEqual({
|
||||
receivedAt: new Date(1000),
|
||||
error: null,
|
||||
isFromCache: false,
|
||||
isFetching: false,
|
||||
isUpdating: false,
|
||||
editMode: false
|
||||
});
|
||||
});
|
||||
|
||||
it("should extract a valid meta object", () => {
|
||||
expect(
|
||||
itemMetaDecoder({
|
||||
receivedAt: new Date(1000),
|
||||
error: new Error("foo"),
|
||||
editMode: 1
|
||||
})
|
||||
).toEqual({
|
||||
receivedAt: new Date(1000),
|
||||
error: new Error("foo"),
|
||||
isFromCache: false,
|
||||
isFetching: false,
|
||||
isUpdating: false,
|
||||
editMode: true
|
||||
});
|
||||
});
|
||||
|
||||
it("should fail when a invalid structure is used", () => {
|
||||
expect(() => itemMetaDecoder({})).toThrowError(TypeError);
|
||||
expect(() =>
|
||||
itemMetaDecoder({
|
||||
receivedAt: "foo"
|
||||
})
|
||||
).toThrowError(TypeError);
|
||||
});
|
||||
});
|
||||
|
@ -1,7 +1,11 @@
|
||||
export interface UnknownObject {
|
||||
export interface AnyObject {
|
||||
[key: string]: any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
}
|
||||
|
||||
export interface UnknownObject {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface Position {
|
||||
x: number;
|
||||
y: number;
|
||||
@ -45,3 +49,12 @@ export type LinkedVisualConsoleProps = {
|
||||
linkedLayoutId: number | null;
|
||||
linkedLayoutAgentId: number | null;
|
||||
} & LinkedVisualConsolePropsStatus;
|
||||
|
||||
export interface ItemMeta {
|
||||
receivedAt: Date;
|
||||
error: Error | null;
|
||||
isFromCache: boolean;
|
||||
isFetching: boolean;
|
||||
isUpdating: boolean;
|
||||
editMode: boolean;
|
||||
}
|
@ -14,3 +14,8 @@
|
||||
align-items: center;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.visual-console-item.is-editing {
|
||||
border: 2px dashed #33ccff;
|
||||
transform: translateX(-2px) translateY(-2px);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user