@netdata/charts
Version:
Netdata frontend SDK and chart utilities
317 lines • 17.3 kB
JavaScript
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
var _excluded = ["signal"];
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
import { getAlias } from "../../../helpers/units";
import { getPointValue } from "../../../sdk/makeChart/getPointValue";
var maxConcurrentRequests = 4;
var maxCachedResponses = 100;
var maxBatchDimensions = 50;
var maxSparklinePoints = 120;
var requestAttributeKeys = ["after", "agent", "aggregationMethod", "before", "context", "contextScope", "eliminateZeroDimensions", "groupBy", "groupByLabel", "groupingMethod", "groupingTime", "host", "liveAnchor", "nodesScope", "points", "postGroupBy", "postGroupByLabel", "renderedAt", "selectedContexts", "selectedDimensions", "selectedInstances", "selectedLabels", "selectedNodes", "showPostAggregations"];
var states = new WeakMap();
var batchesByDimensions = new WeakMap();
var hasOwn = function hasOwn(object, key) {
return Object.prototype.hasOwnProperty.call(object, key);
};
var uniqueSorted = function uniqueSorted(values) {
return _toConsumableArray(new Set(values)).sort();
};
var makeAbortError = function makeAbortError() {
var error = new Error("The sparkline request was aborted");
error.name = "AbortError";
return error;
};
export var getSparklineRequestKey = function getSparklineRequestKey(attrs) {
return JSON.stringify(requestAttributeKeys.reduce(function (result, key) {
result[key] = attrs[key];
return result;
}, {}));
};
var makeDimensionBatches = function makeDimensionBatches(dimensions) {
var groups = new Map();
var batchesByRowId = new Map();
dimensions.forEach(function (item) {
var groupKey = JSON.stringify([item.context, item.nodeId]);
var group = groups.get(groupKey) || [];
group.push(item);
groups.set(groupKey, group);
});
groups.forEach(function (group) {
var _loop = function _loop() {
var batch = group.slice(index, index + maxBatchDimensions);
batch.forEach(function (item) {
return batchesByRowId.set(item.rowId, batch);
});
};
for (var index = 0; index < group.length; index += maxBatchDimensions) {
_loop();
}
});
return batchesByRowId;
};
export var getSparklineBatchDimensions = function getSparklineBatchDimensions(target, dimensions) {
if (!Array.isArray(dimensions)) return [target];
var batches = batchesByDimensions.get(dimensions);
if (!batches) {
batches = makeDimensionBatches(dimensions);
batchesByDimensions.set(dimensions, batches);
}
return batches.get(target.rowId) || [target];
};
export var getSparklineBatchAttributes = function getSparklineBatchAttributes(chart, dimensions) {
var _ref, _overrides$points, _overrides$after, _overrides$aggregatio, _overrides$before, _overrides$liveAnchor, _overrides$renderedAt;
var overrides = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var _dimensions = _slicedToArray(dimensions, 1),
first = _dimensions[0];
if (!first) return null;
var points = (_ref = (_overrides$points = overrides.points) !== null && _overrides$points !== void 0 ? _overrides$points : chart.getAttribute("points")) !== null && _ref !== void 0 ? _ref : maxSparklinePoints;
return {
after: (_overrides$after = overrides.after) !== null && _overrides$after !== void 0 ? _overrides$after : chart.getAttribute("after"),
agent: chart.getAttribute("agent"),
aggregationMethod: (_overrides$aggregatio = overrides.aggregationMethod) !== null && _overrides$aggregatio !== void 0 ? _overrides$aggregatio : chart.getAttribute("correlate.aggregation", "average"),
before: (_overrides$before = overrides.before) !== null && _overrides$before !== void 0 ? _overrides$before : chart.getAttribute("before"),
context: null,
contextScope: [first.context],
eliminateZeroDimensions: false,
groupBy: ["dimension"],
groupByLabel: [],
groupingMethod: chart.getAttribute("groupingMethod"),
groupingTime: chart.getAttribute("groupingTime"),
host: chart.getAttribute("host"),
liveAnchor: (_overrides$liveAnchor = overrides.liveAnchor) !== null && _overrides$liveAnchor !== void 0 ? _overrides$liveAnchor : chart.getAttribute("liveAnchor"),
nodesScope: [first.nodeId],
points: Math.min(points || maxSparklinePoints, maxSparklinePoints),
postGroupBy: [],
postGroupByLabel: [],
renderedAt: (_overrides$renderedAt = overrides.renderedAt) !== null && _overrides$renderedAt !== void 0 ? _overrides$renderedAt : chart.getAttribute("renderedAt"),
selectedContexts: [],
selectedDimensions: uniqueSorted(dimensions.map(function (item) {
return item.dimension;
})),
selectedInstances: [],
selectedLabels: [],
selectedNodes: [],
showPostAggregations: false
};
};
export var normalizeSparklinePayload = function normalizeSparklinePayload(rawPayload) {
var _rawPayload$view, _rawPayload$view2, _rawPayload$db;
var result = rawPayload === null || rawPayload === void 0 ? void 0 : rawPayload.result;
if (!result || !Array.isArray(result.labels) || !Array.isArray(result.data)) throw new Error("Invalid sparkline response");
var dimensionUnits = ((_rawPayload$view = rawPayload.view) === null || _rawPayload$view === void 0 || (_rawPayload$view = _rawPayload$view.dimensions) === null || _rawPayload$view === void 0 ? void 0 : _rawPayload$view.units) || [];
var defaultUnit = ((_rawPayload$view2 = rawPayload.view) === null || _rawPayload$view2 === void 0 ? void 0 : _rawPayload$view2.units) || ((_rawPayload$db = rawPayload.db) === null || _rawPayload$db === void 0 ? void 0 : _rawPayload$db.units) || "";
var seriesByDimension = new Map();
for (var column = 1; column < result.labels.length; column++) {
var _values, _dimensionUnits;
var values = new Array(result.data.length);
var min = Infinity;
var max = -Infinity;
for (var rowIndex = 0; rowIndex < result.data.length; rowIndex++) {
var row = result.data[rowIndex];
var value = Array.isArray(row) ? getPointValue(row[column], result.point, "value") : undefined;
var normalizedValue = Number.isFinite(value) ? value : null;
values[rowIndex] = normalizedValue;
if (normalizedValue === null) continue;
if (normalizedValue < min) min = normalizedValue;
if (normalizedValue > max) max = normalizedValue;
}
seriesByDimension.set(result.labels[column], {
values: values,
min: min === Infinity ? null : min,
max: max === -Infinity ? null : max,
latest: (_values = values[values.length - 1]) !== null && _values !== void 0 ? _values : null,
unit: getAlias((_dimensionUnits = dimensionUnits[column - 1]) !== null && _dimensionUnits !== void 0 ? _dimensionUnits : defaultUnit)
});
}
return seriesByDimension;
};
var makeRequestChart = function makeRequestChart(ownerChart, attrs) {
return _objectSpread(_objectSpread({}, ownerChart), {}, {
getAttributes: function getAttributes() {
return _objectSpread(_objectSpread({}, ownerChart.getAttributes()), attrs);
},
getAttribute: function getAttribute(key, defaultValue) {
return hasOwn(attrs, key) ? attrs[key] : ownerChart.getAttribute(key, defaultValue);
},
getFilteredNodeIds: function getFilteredNodeIds() {
return attrs.selectedNodes;
}
});
};
var touchEntry = function touchEntry(state, entry) {
if (state.entries.get(entry.key) !== entry) return;
state.entries["delete"](entry.key);
state.entries.set(entry.key, entry);
};
var pruneCache = function pruneCache(state) {
if (state.entries.size <= maxCachedResponses) return;
var _iterator = _createForOfIteratorHelper(state.entries),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var _step$value = _slicedToArray(_step.value, 2),
key = _step$value[0],
entry = _step$value[1];
if (state.entries.size <= maxCachedResponses) break;
if (entry.status !== "fulfilled" || entry.consumers) continue;
state.entries["delete"](key);
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
};
var removeEntry = function removeEntry(state, entry) {
if (state.entries.get(entry.key) === entry) state.entries["delete"](entry.key);
};
var _drainQueue = function drainQueue(state) {
var _loop2 = function _loop2() {
var entry = state.queue.shift();
if (entry.status !== "queued") return 0; // continue
if (!entry.consumers) {
entry.status = "cancelled";
removeEntry(state, entry);
entry.reject(makeAbortError());
return 0; // continue
}
entry.status = "active";
state.active++;
state.ownerChart.getChart(entry.requestChart, _objectSpread(_objectSpread({}, entry.options), {}, {
attrs: entry.attrs,
signal: entry.controller.signal
})).then(normalizeSparklinePayload).then(function (value) {
entry.status = "fulfilled";
entry.resolve(value);
touchEntry(state, entry);
})["catch"](function (error) {
entry.status = "rejected";
removeEntry(state, entry);
entry.reject(error);
})["finally"](function () {
state.active--;
pruneCache(state);
_drainQueue(state);
});
},
_ret;
while (state.active < maxConcurrentRequests && state.queue.length) {
_ret = _loop2();
if (_ret === 0) continue;
}
};
var releaseConsumer = function releaseConsumer(state, entry) {
entry.consumers--;
if (entry.consumers || entry.status === "fulfilled") return;
if (entry.status === "queued") {
entry.status = "cancelled";
removeEntry(state, entry);
entry.reject(makeAbortError());
} else if (entry.status === "active") {
removeEntry(state, entry);
entry.controller.abort();
}
};
var consumeEntry = function consumeEntry(state, entry, signal) {
entry.consumers++;
touchEntry(state, entry);
return new Promise(function (resolve, reject) {
var settled = false;
var finish = function finish(callback) {
return function (value) {
if (settled) return;
settled = true;
signal === null || signal === void 0 || signal.removeEventListener("abort", onAbort);
releaseConsumer(state, entry);
callback(value);
};
};
var onResolve = finish(resolve);
var onReject = finish(reject);
var onAbort = function onAbort() {
return onReject(makeAbortError());
};
if (signal !== null && signal !== void 0 && signal.aborted) {
onAbort();
return;
}
signal === null || signal === void 0 || signal.addEventListener("abort", onAbort, {
once: true
});
entry.promise.then(onResolve, onReject);
});
};
var makeEntry = function makeEntry(state, attrs, options, key) {
var resolve;
var reject;
var promise = new Promise(function (resolvePromise, rejectPromise) {
resolve = resolvePromise;
reject = rejectPromise;
});
var entry = {
key: key,
attrs: attrs,
options: options,
requestChart: makeRequestChart(state.ownerChart, attrs),
promise: promise,
resolve: resolve,
reject: reject,
controller: new AbortController(),
consumers: 0,
status: "queued"
};
state.entries.set(key, entry);
state.queue.push(entry);
return entry;
};
var makeState = function makeState(ownerChart) {
var state = {
ownerChart: ownerChart,
entries: new Map(),
queue: [],
active: 0,
getData: null
};
state.getData = function (attrs) {
var _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
signal = _ref2.signal,
options = _objectWithoutProperties(_ref2, _excluded);
var key = getSparklineRequestKey(attrs);
var entry = state.entries.get(key) || makeEntry(state, attrs, options, key);
var result = consumeEntry(state, entry, signal);
_drainQueue(state);
return result;
};
return state;
};
export var getSparklineDataFetcher = function getSparklineDataFetcher(ownerChart) {
var state = states.get(ownerChart);
if (!state) {
state = makeState(ownerChart);
states.set(ownerChart, state);
}
return state.getData;
};
export var sparklineRequestLimits = {
batchDimensions: maxBatchDimensions,
cache: maxCachedResponses,
concurrency: maxConcurrentRequests,
points: maxSparklinePoints
};