mirror of
https://github.com/timberjoegithub/grafana-statusmap.git
synced 2026-07-22 15:53:09 +00:00
Merge pull request #22 from flant/separate_vertical_and_horizontal_spacing
Separate options for vertical and horizontal spacing of cards
This commit is contained in:
@@ -146,6 +146,7 @@ This plugin is based on "Heatmap" panel by Grafana and partly inspired by ideas
|
|||||||
|
|
||||||
##### v0.0.3
|
##### v0.0.3
|
||||||
|
|
||||||
|
- Separate options for vertical and horizontal spacing for cards
|
||||||
- Add simple sort options for Y axis
|
- Add simple sort options for Y axis
|
||||||
- Fix display null values as zero
|
- Fix display null values as zero
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
@@ -146,6 +146,7 @@ This plugin is based on "Heatmap" panel by Grafana and partly inspired by ideas
|
|||||||
|
|
||||||
##### v0.0.3
|
##### v0.0.3
|
||||||
|
|
||||||
|
- Separate options for vertical and horizontal spacing for cards
|
||||||
- Add simple sort options for Y axis
|
- Add simple sort options for Y axis
|
||||||
- Fix display null values as zero
|
- Fix display null values as zero
|
||||||
|
|
||||||
|
|||||||
Vendored
+6
-2
@@ -151,8 +151,12 @@
|
|||||||
<input type="number" class="gf-form-input width-5" placeholder="5" data-placement="right" bs-tooltip="'Minimal card width for 1/1 resolution in pixels'" ng-model="ctrl.panel.cards.cardMinWidth" ng-change="ctrl.refresh()" ng-model-onblur>
|
<input type="number" class="gf-form-input width-5" placeholder="5" data-placement="right" bs-tooltip="'Minimal card width for 1/1 resolution in pixels'" ng-model="ctrl.panel.cards.cardMinWidth" ng-change="ctrl.refresh()" ng-model-onblur>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label width-9">Spacing</label>
|
<label class="gf-form-label width-9">V spacing</label>
|
||||||
<input type="number" class="gf-form-input width-5" placeholder="2" data-placement="right" bs-tooltip="'Card spacing in pixels'" ng-model="ctrl.panel.cards.cardSpacing" ng-change="ctrl.refresh()" ng-model-onblur>
|
<input type="number" class="gf-form-input width-5" placeholder="2" data-placement="right" bs-tooltip="'Cards vertical spacing in pixels'" ng-model="ctrl.panel.cards.cardVSpacing" ng-change="ctrl.refresh()" ng-model-onblur>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form">
|
||||||
|
<label class="gf-form-label width-9">H spacing</label>
|
||||||
|
<input type="number" class="gf-form-input width-5" placeholder="2" data-placement="right" bs-tooltip="'Cards horizontal spacing in pixels'" ng-model="ctrl.panel.cards.cardHSpacing" ng-change="ctrl.refresh()" ng-model-onblur>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label width-9">Rounding</label>
|
<label class="gf-form-label width-9">Rounding</label>
|
||||||
|
|||||||
Vendored
+15
-12
@@ -3,7 +3,7 @@
|
|||||||
System.register(['lodash', 'jquery', 'moment', 'app/core/utils/kbn', 'app/core/core', 'app/core/utils/ticks', 'd3', './libs/d3-scale-chromatic/index', './tooltip'], function (_export, _context) {
|
System.register(['lodash', 'jquery', 'moment', 'app/core/utils/kbn', 'app/core/core', 'app/core/utils/ticks', 'd3', './libs/d3-scale-chromatic/index', './tooltip'], function (_export, _context) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var _, $, moment, kbn, appEvents, contextSrv, tickStep, getScaledDecimals, getFlotTickSize, d3, d3ScaleChromatic, StatusHeatmapTooltip, MIN_CARD_SIZE, CARD_SPACING, CARD_ROUND, DATA_RANGE_WIDING_FACTOR, DEFAULT_X_TICK_SIZE_PX, DEFAULT_Y_TICK_SIZE_PX, X_AXIS_TICK_PADDING, Y_AXIS_TICK_PADDING, MIN_SELECTION_WIDTH;
|
var _, $, moment, kbn, appEvents, contextSrv, tickStep, getScaledDecimals, getFlotTickSize, d3, d3ScaleChromatic, StatusHeatmapTooltip, MIN_CARD_SIZE, CARD_H_SPACING, CARD_V_SPACING, CARD_ROUND, DATA_RANGE_WIDING_FACTOR, DEFAULT_X_TICK_SIZE_PX, DEFAULT_Y_TICK_SIZE_PX, X_AXIS_TICK_PADDING, Y_AXIS_TICK_PADDING, MIN_SELECTION_WIDTH;
|
||||||
|
|
||||||
function link(scope, elem, attrs, ctrl) {
|
function link(scope, elem, attrs, ctrl) {
|
||||||
var data = void 0,
|
var data = void 0,
|
||||||
@@ -26,7 +26,8 @@ System.register(['lodash', 'jquery', 'moment', 'app/core/utils/kbn', 'app/core/c
|
|||||||
chartBottom = void 0,
|
chartBottom = void 0,
|
||||||
yAxisWidth = void 0,
|
yAxisWidth = void 0,
|
||||||
xAxisHeight = void 0,
|
xAxisHeight = void 0,
|
||||||
cardSpacing = void 0,
|
cardVSpacing = void 0,
|
||||||
|
cardHSpacing = void 0,
|
||||||
cardRound = void 0,
|
cardRound = void 0,
|
||||||
cardWidth = void 0,
|
cardWidth = void 0,
|
||||||
cardHeight = void 0,
|
cardHeight = void 0,
|
||||||
@@ -228,12 +229,13 @@ System.register(['lodash', 'jquery', 'moment', 'app/core/utils/kbn', 'app/core/c
|
|||||||
chartTop = margin.top;
|
chartTop = margin.top;
|
||||||
chartBottom = chartTop + chartHeight;
|
chartBottom = chartTop + chartHeight;
|
||||||
|
|
||||||
cardSpacing = panel.cards.cardSpacing !== null ? panel.cards.cardSpacing : CARD_SPACING;
|
cardHSpacing = panel.cards.cardHSpacing !== null ? panel.cards.cardHSpacing : CARD_H_SPACING;
|
||||||
|
cardVSpacing = panel.cards.cardVSpacing !== null ? panel.cards.cardVSpacing : CARD_V_SPACING;
|
||||||
cardRound = panel.cards.cardRound !== null ? panel.cards.cardRound : CARD_ROUND;
|
cardRound = panel.cards.cardRound !== null ? panel.cards.cardRound : CARD_ROUND;
|
||||||
|
|
||||||
// calculate yOffset for YAxis
|
// calculate yOffset for YAxis
|
||||||
yGridSize = Math.floor(chartHeight / cardsData.yBucketSize);
|
yGridSize = Math.floor(chartHeight / cardsData.yBucketSize);
|
||||||
cardHeight = yGridSize ? yGridSize - cardSpacing : 0;
|
cardHeight = yGridSize ? yGridSize - cardVSpacing : 0;
|
||||||
yOffset = cardHeight / 2;
|
yOffset = cardHeight / 2;
|
||||||
|
|
||||||
addYAxis();
|
addYAxis();
|
||||||
@@ -243,7 +245,7 @@ System.register(['lodash', 'jquery', 'moment', 'app/core/utils/kbn', 'app/core/c
|
|||||||
|
|
||||||
// we need to fill chartWidth with xBucketSize cards.
|
// we need to fill chartWidth with xBucketSize cards.
|
||||||
xGridSize = chartWidth / (cardsData.xBucketSize + 1);
|
xGridSize = chartWidth / (cardsData.xBucketSize + 1);
|
||||||
cardWidth = xGridSize - cardSpacing;
|
cardWidth = xGridSize - cardHSpacing;
|
||||||
|
|
||||||
addXAxis();
|
addXAxis();
|
||||||
xAxisHeight = getXAxisHeight(heatmap);
|
xAxisHeight = getXAxisHeight(heatmap);
|
||||||
@@ -333,7 +335,7 @@ System.register(['lodash', 'jquery', 'moment', 'app/core/utils/kbn', 'app/core/c
|
|||||||
var cx = xScale(d.x);
|
var cx = xScale(d.x);
|
||||||
|
|
||||||
if (cx - cardWidth / 2 < 0) {
|
if (cx - cardWidth / 2 < 0) {
|
||||||
x = yAxisWidth + cardSpacing / 2;
|
x = yAxisWidth + cardHSpacing / 2;
|
||||||
} else {
|
} else {
|
||||||
x = yAxisWidth + cx - cardWidth / 2;
|
x = yAxisWidth + cx - cardWidth / 2;
|
||||||
}
|
}
|
||||||
@@ -349,11 +351,11 @@ System.register(['lodash', 'jquery', 'moment', 'app/core/utils/kbn', 'app/core/c
|
|||||||
if (cx < cardWidth / 2) {
|
if (cx < cardWidth / 2) {
|
||||||
// Center should not exceed half of card.
|
// Center should not exceed half of card.
|
||||||
// Cut card to the left to prevent overlay of y axis.
|
// Cut card to the left to prevent overlay of y axis.
|
||||||
var cutted_width = cx - cardSpacing / 2 + cardWidth / 2;
|
var cutted_width = cx - cardHSpacing / 2 + cardWidth / 2;
|
||||||
w = cutted_width > 0 ? cutted_width : 0;
|
w = cutted_width > 0 ? cutted_width : 0;
|
||||||
} else if (chartWidth - cx < cardWidth / 2) {
|
} else if (chartWidth - cx < cardWidth / 2) {
|
||||||
// Cut card to the right to prevent overlay of right graph edge.
|
// Cut card to the right to prevent overlay of right graph edge.
|
||||||
w = cardWidth / 2 + (chartWidth - cx - cardSpacing / 2);
|
w = cardWidth / 2 + (chartWidth - cx - cardHSpacing / 2);
|
||||||
} else {
|
} else {
|
||||||
w = cardWidth;
|
w = cardWidth;
|
||||||
}
|
}
|
||||||
@@ -365,17 +367,17 @@ System.register(['lodash', 'jquery', 'moment', 'app/core/utils/kbn', 'app/core/c
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getCardY(d) {
|
function getCardY(d) {
|
||||||
return yScale(d.y) + chartTop - cardHeight - cardSpacing / 2;
|
return yScale(d.y) + chartTop - cardHeight - cardVSpacing / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCardHeight(d) {
|
function getCardHeight(d) {
|
||||||
var ys = yScale(d.y);
|
var ys = yScale(d.y);
|
||||||
var y = ys + chartTop - cardHeight - cardSpacing / 2;
|
var y = ys + chartTop - cardHeight - cardVSpacing / 2;
|
||||||
var h = cardHeight;
|
var h = cardHeight;
|
||||||
|
|
||||||
// Cut card height to prevent overlay
|
// Cut card height to prevent overlay
|
||||||
if (y < chartTop) {
|
if (y < chartTop) {
|
||||||
h = ys - cardSpacing / 2;
|
h = ys - cardVSpacing / 2;
|
||||||
} else if (ys > chartBottom) {
|
} else if (ys > chartBottom) {
|
||||||
h = chartBottom - y;
|
h = chartBottom - y;
|
||||||
} else if (y + cardHeight > chartBottom) {
|
} else if (y + cardHeight > chartBottom) {
|
||||||
@@ -637,7 +639,8 @@ System.register(['lodash', 'jquery', 'moment', 'app/core/utils/kbn', 'app/core/c
|
|||||||
}],
|
}],
|
||||||
execute: function () {
|
execute: function () {
|
||||||
MIN_CARD_SIZE = 5;
|
MIN_CARD_SIZE = 5;
|
||||||
CARD_SPACING = 2;
|
CARD_H_SPACING = 2;
|
||||||
|
CARD_V_SPACING = 2;
|
||||||
CARD_ROUND = 0;
|
CARD_ROUND = 0;
|
||||||
DATA_RANGE_WIDING_FACTOR = 1.2;
|
DATA_RANGE_WIDING_FACTOR = 1.2;
|
||||||
DEFAULT_X_TICK_SIZE_PX = 100;
|
DEFAULT_X_TICK_SIZE_PX = 100;
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+3
-2
@@ -71,7 +71,8 @@ System.register(['app/plugins/sdk', 'lodash', 'app/core/core', 'app/core/utils/k
|
|||||||
},
|
},
|
||||||
cards: {
|
cards: {
|
||||||
cardMinWidth: 5,
|
cardMinWidth: 5,
|
||||||
cardSpacing: 2,
|
cardVSpacing: 2,
|
||||||
|
cardHSpacing: 2,
|
||||||
cardRound: null
|
cardRound: null
|
||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
@@ -133,7 +134,7 @@ System.register(['app/plugins/sdk', 'lodash', 'app/core/core', 'app/core/utils/k
|
|||||||
var chartWidth = _.max([panelWidth - 200, panelWidth / 2]);
|
var chartWidth = _.max([panelWidth - 200, panelWidth / 2]);
|
||||||
|
|
||||||
var minCardWidth = _this.panel.cards.cardMinWidth;
|
var minCardWidth = _this.panel.cards.cardMinWidth;
|
||||||
var minSpacing = _this.panel.cards.cardSpacing;
|
var minSpacing = _this.panel.cards.cardHSpacing;
|
||||||
var maxCardsCount = Math.ceil((chartWidth - minCardWidth) / (minCardWidth + minSpacing));
|
var maxCardsCount = Math.ceil((chartWidth - minCardWidth) / (minCardWidth + minSpacing));
|
||||||
|
|
||||||
var intervalMs = void 0;
|
var intervalMs = void 0;
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -151,8 +151,12 @@
|
|||||||
<input type="number" class="gf-form-input width-5" placeholder="5" data-placement="right" bs-tooltip="'Minimal card width for 1/1 resolution in pixels'" ng-model="ctrl.panel.cards.cardMinWidth" ng-change="ctrl.refresh()" ng-model-onblur>
|
<input type="number" class="gf-form-input width-5" placeholder="5" data-placement="right" bs-tooltip="'Minimal card width for 1/1 resolution in pixels'" ng-model="ctrl.panel.cards.cardMinWidth" ng-change="ctrl.refresh()" ng-model-onblur>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label width-9">Spacing</label>
|
<label class="gf-form-label width-9">V spacing</label>
|
||||||
<input type="number" class="gf-form-input width-5" placeholder="2" data-placement="right" bs-tooltip="'Card spacing in pixels'" ng-model="ctrl.panel.cards.cardSpacing" ng-change="ctrl.refresh()" ng-model-onblur>
|
<input type="number" class="gf-form-input width-5" placeholder="2" data-placement="right" bs-tooltip="'Cards vertical spacing in pixels'" ng-model="ctrl.panel.cards.cardVSpacing" ng-change="ctrl.refresh()" ng-model-onblur>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form">
|
||||||
|
<label class="gf-form-label width-9">H spacing</label>
|
||||||
|
<input type="number" class="gf-form-input width-5" placeholder="2" data-placement="right" bs-tooltip="'Cards horizontal spacing in pixels'" ng-model="ctrl.panel.cards.cardHSpacing" ng-change="ctrl.refresh()" ng-model-onblur>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label width-9">Rounding</label>
|
<label class="gf-form-label width-9">Rounding</label>
|
||||||
|
|||||||
+13
-11
@@ -9,7 +9,8 @@ import * as d3ScaleChromatic from './libs/d3-scale-chromatic/index';
|
|||||||
import {StatusHeatmapTooltip} from './tooltip';
|
import {StatusHeatmapTooltip} from './tooltip';
|
||||||
|
|
||||||
let MIN_CARD_SIZE = 5,
|
let MIN_CARD_SIZE = 5,
|
||||||
CARD_SPACING = 2,
|
CARD_H_SPACING = 2,
|
||||||
|
CARD_V_SPACING = 2,
|
||||||
CARD_ROUND = 0,
|
CARD_ROUND = 0,
|
||||||
DATA_RANGE_WIDING_FACTOR = 1.2,
|
DATA_RANGE_WIDING_FACTOR = 1.2,
|
||||||
DEFAULT_X_TICK_SIZE_PX = 100,
|
DEFAULT_X_TICK_SIZE_PX = 100,
|
||||||
@@ -30,7 +31,7 @@ export default function link(scope, elem, attrs, ctrl) {
|
|||||||
chartWidth, chartHeight,
|
chartWidth, chartHeight,
|
||||||
chartTop, chartBottom,
|
chartTop, chartBottom,
|
||||||
yAxisWidth, xAxisHeight,
|
yAxisWidth, xAxisHeight,
|
||||||
cardSpacing, cardRound,
|
cardVSpacing, cardHSpacing, cardRound,
|
||||||
cardWidth, cardHeight,
|
cardWidth, cardHeight,
|
||||||
colorScale, opacityScale,
|
colorScale, opacityScale,
|
||||||
mouseUpHandler,
|
mouseUpHandler,
|
||||||
@@ -239,12 +240,13 @@ export default function link(scope, elem, attrs, ctrl) {
|
|||||||
chartTop = margin.top;
|
chartTop = margin.top;
|
||||||
chartBottom = chartTop + chartHeight;
|
chartBottom = chartTop + chartHeight;
|
||||||
|
|
||||||
cardSpacing = panel.cards.cardSpacing !== null ? panel.cards.cardSpacing : CARD_SPACING;
|
cardHSpacing = panel.cards.cardHSpacing !== null ? panel.cards.cardHSpacing : CARD_H_SPACING;
|
||||||
|
cardVSpacing = panel.cards.cardVSpacing !== null ? panel.cards.cardVSpacing : CARD_V_SPACING;
|
||||||
cardRound = panel.cards.cardRound !== null ? panel.cards.cardRound : CARD_ROUND;
|
cardRound = panel.cards.cardRound !== null ? panel.cards.cardRound : CARD_ROUND;
|
||||||
|
|
||||||
// calculate yOffset for YAxis
|
// calculate yOffset for YAxis
|
||||||
yGridSize = Math.floor(chartHeight / cardsData.yBucketSize);
|
yGridSize = Math.floor(chartHeight / cardsData.yBucketSize);
|
||||||
cardHeight = yGridSize ? yGridSize - cardSpacing : 0;
|
cardHeight = yGridSize ? yGridSize - cardVSpacing : 0;
|
||||||
yOffset = cardHeight / 2;
|
yOffset = cardHeight / 2;
|
||||||
|
|
||||||
addYAxis();
|
addYAxis();
|
||||||
@@ -254,7 +256,7 @@ export default function link(scope, elem, attrs, ctrl) {
|
|||||||
|
|
||||||
// we need to fill chartWidth with xBucketSize cards.
|
// we need to fill chartWidth with xBucketSize cards.
|
||||||
xGridSize = chartWidth / (cardsData.xBucketSize+1);
|
xGridSize = chartWidth / (cardsData.xBucketSize+1);
|
||||||
cardWidth = xGridSize - cardSpacing;
|
cardWidth = xGridSize - cardHSpacing;
|
||||||
|
|
||||||
addXAxis();
|
addXAxis();
|
||||||
xAxisHeight = getXAxisHeight(heatmap);
|
xAxisHeight = getXAxisHeight(heatmap);
|
||||||
@@ -364,7 +366,7 @@ export default function link(scope, elem, attrs, ctrl) {
|
|||||||
let cx = xScale(d.x);
|
let cx = xScale(d.x);
|
||||||
|
|
||||||
if (cx - cardWidth/2 < 0) {
|
if (cx - cardWidth/2 < 0) {
|
||||||
x = yAxisWidth + cardSpacing/2;
|
x = yAxisWidth + cardHSpacing/2;
|
||||||
} else {
|
} else {
|
||||||
x = yAxisWidth + cx - cardWidth/2;
|
x = yAxisWidth + cx - cardWidth/2;
|
||||||
}
|
}
|
||||||
@@ -380,11 +382,11 @@ export default function link(scope, elem, attrs, ctrl) {
|
|||||||
if (cx < cardWidth/2) {
|
if (cx < cardWidth/2) {
|
||||||
// Center should not exceed half of card.
|
// Center should not exceed half of card.
|
||||||
// Cut card to the left to prevent overlay of y axis.
|
// Cut card to the left to prevent overlay of y axis.
|
||||||
let cutted_width = (cx - cardSpacing/2) + cardWidth/2;
|
let cutted_width = (cx - cardHSpacing/2) + cardWidth/2;
|
||||||
w = cutted_width > 0 ? cutted_width : 0;
|
w = cutted_width > 0 ? cutted_width : 0;
|
||||||
} else if (chartWidth - cx < cardWidth/2) {
|
} else if (chartWidth - cx < cardWidth/2) {
|
||||||
// Cut card to the right to prevent overlay of right graph edge.
|
// Cut card to the right to prevent overlay of right graph edge.
|
||||||
w = cardWidth/2 + (chartWidth - cx - cardSpacing/2);
|
w = cardWidth/2 + (chartWidth - cx - cardHSpacing/2);
|
||||||
} else {
|
} else {
|
||||||
w = cardWidth;
|
w = cardWidth;
|
||||||
}
|
}
|
||||||
@@ -396,17 +398,17 @@ export default function link(scope, elem, attrs, ctrl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getCardY(d) {
|
function getCardY(d) {
|
||||||
return yScale(d.y) + chartTop - cardHeight - cardSpacing/2;
|
return yScale(d.y) + chartTop - cardHeight - cardVSpacing/2;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCardHeight(d) {
|
function getCardHeight(d) {
|
||||||
let ys = yScale(d.y);
|
let ys = yScale(d.y);
|
||||||
let y = ys + chartTop - cardHeight - cardSpacing/2;
|
let y = ys + chartTop - cardHeight - cardVSpacing/2;
|
||||||
let h = cardHeight;
|
let h = cardHeight;
|
||||||
|
|
||||||
// Cut card height to prevent overlay
|
// Cut card height to prevent overlay
|
||||||
if (y < chartTop) {
|
if (y < chartTop) {
|
||||||
h = ys - cardSpacing/2;
|
h = ys - cardVSpacing/2;
|
||||||
} else if (ys > chartBottom) {
|
} else if (ys > chartBottom) {
|
||||||
h = chartBottom - y;
|
h = chartBottom - y;
|
||||||
} else if (y + cardHeight > chartBottom) {
|
} else if (y + cardHeight > chartBottom) {
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ const panelDefaults = {
|
|||||||
},
|
},
|
||||||
cards: {
|
cards: {
|
||||||
cardMinWidth: 5,
|
cardMinWidth: 5,
|
||||||
cardSpacing: 2,
|
cardVSpacing: 2,
|
||||||
|
cardHSpacing: 2,
|
||||||
cardRound: null
|
cardRound: null
|
||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
@@ -153,7 +154,7 @@ export class StatusHeatmapCtrl extends MetricsPanelCtrl {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
let minCardWidth = this.panel.cards.cardMinWidth;
|
let minCardWidth = this.panel.cards.cardMinWidth;
|
||||||
let minSpacing = this.panel.cards.cardSpacing;
|
let minSpacing = this.panel.cards.cardHSpacing;
|
||||||
let maxCardsCount = Math.ceil((chartWidth-minCardWidth) / (minCardWidth + minSpacing));
|
let maxCardsCount = Math.ceil((chartWidth-minCardWidth) / (minCardWidth + minSpacing));
|
||||||
|
|
||||||
let intervalMs;
|
let intervalMs;
|
||||||
|
|||||||
Reference in New Issue
Block a user