Merge pull request #181 from Cryptkeeper/release-551
5.5.1 release preview
This commit is contained in:
commit
b7ed5fdd93
@ -20,7 +20,7 @@ export class FavoritesManager {
|
|||||||
serverRegistration.isFavorite = true
|
serverRegistration.isFavorite = true
|
||||||
|
|
||||||
// Update icon since by default it is unfavorited
|
// Update icon since by default it is unfavorited
|
||||||
document.getElementById('favorite-toggle_' + serverRegistration.serverId).setAttribute('class', this.getIconClass(serverRegistration.isFavorite))
|
document.getElementById(`favorite-toggle_${serverRegistration.serverId}`).setAttribute('class', this.getIconClass(serverRegistration.isFavorite))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,7 +47,7 @@ export class FavoritesManager {
|
|||||||
serverRegistration.isFavorite = !serverRegistration.isFavorite
|
serverRegistration.isFavorite = !serverRegistration.isFavorite
|
||||||
|
|
||||||
// Update the displayed favorite icon
|
// Update the displayed favorite icon
|
||||||
document.getElementById('favorite-toggle_' + serverRegistration.serverId).setAttribute('class', this.getIconClass(serverRegistration.isFavorite))
|
document.getElementById(`favorite-toggle_${serverRegistration.serverId}`).setAttribute('class', this.getIconClass(serverRegistration.isFavorite))
|
||||||
|
|
||||||
// Request the app controller instantly re-sort the server listing
|
// Request the app controller instantly re-sort the server listing
|
||||||
// This handles the favorite sorting logic internally
|
// This handles the favorite sorting logic internally
|
||||||
|
@ -3,7 +3,7 @@ import uPlot from 'uplot'
|
|||||||
import { RelativeScale } from './scale'
|
import { RelativeScale } from './scale'
|
||||||
|
|
||||||
import { formatNumber, formatTimestampSeconds } from './util'
|
import { formatNumber, formatTimestampSeconds } from './util'
|
||||||
import { uPlotTooltipPlugin } from './tooltip'
|
import { uPlotTooltipPlugin, uPlotIsZoomedPlugin } from './plugins'
|
||||||
|
|
||||||
import { FAVORITE_SERVERS_STORAGE_KEY } from './favorites'
|
import { FAVORITE_SERVERS_STORAGE_KEY } from './favorites'
|
||||||
|
|
||||||
@ -18,6 +18,7 @@ export class GraphDisplayManager {
|
|||||||
this._hasLoadedSettings = false
|
this._hasLoadedSettings = false
|
||||||
this._initEventListenersOnce = false
|
this._initEventListenersOnce = false
|
||||||
this._showOnlyFavorites = false
|
this._showOnlyFavorites = false
|
||||||
|
this._isPlotZoomed = false
|
||||||
}
|
}
|
||||||
|
|
||||||
addGraphPoint (timestamp, playerCounts) {
|
addGraphPoint (timestamp, playerCounts) {
|
||||||
@ -49,11 +50,14 @@ export class GraphDisplayManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paint updated data structure
|
// If not zoomed, paint updated data structure
|
||||||
this._plotInstance.setData([
|
// Otherwise flag the plot data as dirty with repainting to be handled by #handlePlotZoomOut
|
||||||
this._graphTimestamps,
|
// This prevents #addGraphPoint calls from resetting the graph's zoom state
|
||||||
...this._graphData
|
if (!this._isPlotZoomed) {
|
||||||
])
|
this._plotInstance.setData(this.getGraphData())
|
||||||
|
} else {
|
||||||
|
this._isPlotZoomedDataDirty = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadLocalStorage () {
|
loadLocalStorage () {
|
||||||
@ -127,6 +131,13 @@ export class GraphDisplayManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getGraphData () {
|
||||||
|
return [
|
||||||
|
this._graphTimestamps,
|
||||||
|
...this._graphData
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
getGraphDataPoint (serverId, index) {
|
getGraphDataPoint (serverId, index) {
|
||||||
const graphData = this._graphData[serverId]
|
const graphData = this._graphData[serverId]
|
||||||
if (graphData && index < graphData.length && typeof graphData[index] === 'number') {
|
if (graphData && index < graphData.length && typeof graphData[index] === 'number') {
|
||||||
@ -134,6 +145,37 @@ export class GraphDisplayManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getClosestPlotSeriesIndex (idx) {
|
||||||
|
let closestSeriesIndex = -1
|
||||||
|
let closestSeriesDist = Number.MAX_VALUE
|
||||||
|
|
||||||
|
const plotHeight = this._plotInstance.bbox.height / devicePixelRatio
|
||||||
|
|
||||||
|
for (let i = 1; i < this._plotInstance.series.length; i++) {
|
||||||
|
const series = this._plotInstance.series[i]
|
||||||
|
|
||||||
|
if (!series.show) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const point = this._plotInstance.data[i][idx]
|
||||||
|
|
||||||
|
if (typeof point === 'number') {
|
||||||
|
const scale = this._plotInstance.scales[series.scale]
|
||||||
|
const posY = (1 - ((point - scale.min) / (scale.max - scale.min))) * plotHeight
|
||||||
|
|
||||||
|
const dist = Math.abs(posY - this._plotInstance.cursor.top)
|
||||||
|
|
||||||
|
if (dist < closestSeriesDist) {
|
||||||
|
closestSeriesIndex = i
|
||||||
|
closestSeriesDist = dist
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closestSeriesIndex
|
||||||
|
}
|
||||||
|
|
||||||
buildPlotInstance (timestamps, data) {
|
buildPlotInstance (timestamps, data) {
|
||||||
// Lazy load settings from localStorage, if any and if enabled
|
// Lazy load settings from localStorage, if any and if enabled
|
||||||
if (!this._hasLoadedSettings) {
|
if (!this._hasLoadedSettings) {
|
||||||
@ -142,6 +184,19 @@ export class GraphDisplayManager {
|
|||||||
this.loadLocalStorage()
|
this.loadLocalStorage()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const playerCounts of data) {
|
||||||
|
// Each playerCounts value corresponds to a ServerRegistration
|
||||||
|
// Require each array is the length of timestamps, if not, pad at the start with null values to fit to length
|
||||||
|
// This ensures newer ServerRegistrations do not left align due to a lower length
|
||||||
|
const lengthDiff = timestamps.length - playerCounts.length
|
||||||
|
|
||||||
|
if (lengthDiff > 0) {
|
||||||
|
const padding = Array(lengthDiff).fill(null)
|
||||||
|
|
||||||
|
playerCounts.unshift(...padding)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this._graphTimestamps = timestamps
|
this._graphTimestamps = timestamps
|
||||||
this._graphData = data
|
this._graphData = data
|
||||||
|
|
||||||
@ -150,7 +205,7 @@ export class GraphDisplayManager {
|
|||||||
scale: 'Players',
|
scale: 'Players',
|
||||||
stroke: serverRegistration.data.color,
|
stroke: serverRegistration.data.color,
|
||||||
width: 2,
|
width: 2,
|
||||||
value: (_, raw) => formatNumber(raw) + ' Players',
|
value: (_, raw) => `${formatNumber(raw)} Players`,
|
||||||
show: serverRegistration.isVisible,
|
show: serverRegistration.isVisible,
|
||||||
spanGaps: true,
|
spanGaps: true,
|
||||||
points: {
|
points: {
|
||||||
@ -165,50 +220,39 @@ export class GraphDisplayManager {
|
|||||||
// eslint-disable-next-line new-cap
|
// eslint-disable-next-line new-cap
|
||||||
this._plotInstance = new uPlot({
|
this._plotInstance = new uPlot({
|
||||||
plugins: [
|
plugins: [
|
||||||
uPlotTooltipPlugin((pos, id) => {
|
uPlotTooltipPlugin((pos, idx) => {
|
||||||
if (pos) {
|
if (pos) {
|
||||||
let text = this._app.serverRegistry.getServerRegistrations()
|
const closestSeriesIndex = this.getClosestPlotSeriesIndex(idx)
|
||||||
|
|
||||||
|
const text = this._app.serverRegistry.getServerRegistrations()
|
||||||
.filter(serverRegistration => serverRegistration.isVisible)
|
.filter(serverRegistration => serverRegistration.isVisible)
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
if (a.isFavorite !== b.isFavorite) {
|
if (a.isFavorite !== b.isFavorite) {
|
||||||
return a.isFavorite ? -1 : 1
|
return a.isFavorite ? -1 : 1
|
||||||
}
|
|
||||||
|
|
||||||
const aPoint = this.getGraphDataPoint(a.serverId, id)
|
|
||||||
const bPoint = this.getGraphDataPoint(b.serverId, id)
|
|
||||||
|
|
||||||
if (typeof aPoint === typeof bPoint) {
|
|
||||||
if (typeof aPoint === 'undefined') {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return typeof aPoint === 'number' ? -1 : 1
|
return a.data.name.localeCompare(b.data.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return bPoint - aPoint
|
|
||||||
})
|
})
|
||||||
.map(serverRegistration => {
|
.map(serverRegistration => {
|
||||||
const point = this.getGraphDataPoint(serverRegistration.serverId, id)
|
const point = this.getGraphDataPoint(serverRegistration.serverId, idx)
|
||||||
|
|
||||||
let serverName = serverRegistration.data.name
|
let serverName = serverRegistration.data.name
|
||||||
|
if (closestSeriesIndex === serverRegistration.getGraphDataIndex()) {
|
||||||
|
serverName = `<strong>${serverName}</strong>`
|
||||||
|
}
|
||||||
if (serverRegistration.isFavorite) {
|
if (serverRegistration.isFavorite) {
|
||||||
serverName = '<span class="' + this._app.favoritesManager.getIconClass(true) + '"></span> ' + serverName
|
serverName = `<span class="${this._app.favoritesManager.getIconClass(true)}"></span> ${serverName}`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof point === 'number') {
|
return `${serverName}: ${formatNumber(point)}`
|
||||||
return serverName + ': ' + formatNumber(point)
|
}).join('<br>') + `<br><br><strong>${formatTimestampSeconds(this._graphTimestamps[idx])}</strong>`
|
||||||
} else {
|
|
||||||
return serverName + ': -'
|
|
||||||
}
|
|
||||||
}).join('<br>')
|
|
||||||
|
|
||||||
text += '<br><br><strong>' + formatTimestampSeconds(this._graphTimestamps[id]) + '</strong>'
|
|
||||||
|
|
||||||
this._app.tooltip.set(pos.left, pos.top, 10, 10, text)
|
this._app.tooltip.set(pos.left, pos.top, 10, 10, text)
|
||||||
} else {
|
} else {
|
||||||
this._app.tooltip.hide()
|
this._app.tooltip.hide()
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
|
uPlotIsZoomedPlugin(this.handlePlotZoomIn, this.handlePlotZoomOut)
|
||||||
],
|
],
|
||||||
...this.getPlotSize(),
|
...this.getPlotSize(),
|
||||||
cursor: {
|
cursor: {
|
||||||
@ -238,8 +282,8 @@ export class GraphDisplayManager {
|
|||||||
},
|
},
|
||||||
split: () => {
|
split: () => {
|
||||||
const visibleGraphData = this.getVisibleGraphData()
|
const visibleGraphData = this.getVisibleGraphData()
|
||||||
const [, max, scale] = RelativeScale.scaleMatrix(visibleGraphData, tickCount, maxFactor)
|
const { scaledMax, scale } = RelativeScale.scaleMatrix(visibleGraphData, tickCount, maxFactor)
|
||||||
const ticks = RelativeScale.generateTicks(0, max, scale)
|
const ticks = RelativeScale.generateTicks(0, scaledMax, scale)
|
||||||
return ticks
|
return ticks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -249,18 +293,15 @@ export class GraphDisplayManager {
|
|||||||
auto: false,
|
auto: false,
|
||||||
range: () => {
|
range: () => {
|
||||||
const visibleGraphData = this.getVisibleGraphData()
|
const visibleGraphData = this.getVisibleGraphData()
|
||||||
const [, scaledMax] = RelativeScale.scaleMatrix(visibleGraphData, tickCount, maxFactor)
|
const { scaledMin, scaledMax } = RelativeScale.scaleMatrix(visibleGraphData, tickCount, maxFactor)
|
||||||
return [0, scaledMax]
|
return [scaledMin, scaledMax]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
show: false
|
show: false
|
||||||
}
|
}
|
||||||
}, [
|
}, this.getGraphData(), document.getElementById('big-graph'))
|
||||||
this._graphTimestamps,
|
|
||||||
...this._graphData
|
|
||||||
], document.getElementById('big-graph'))
|
|
||||||
|
|
||||||
// Show the settings-toggle element
|
// Show the settings-toggle element
|
||||||
document.getElementById('settings-toggle').style.display = 'inline-block'
|
document.getElementById('settings-toggle').style.display = 'inline-block'
|
||||||
@ -273,7 +314,7 @@ export class GraphDisplayManager {
|
|||||||
|
|
||||||
// Copy application state into the series data used by uPlot
|
// Copy application state into the series data used by uPlot
|
||||||
for (const serverRegistration of this._app.serverRegistry.getServerRegistrations()) {
|
for (const serverRegistration of this._app.serverRegistry.getServerRegistrations()) {
|
||||||
this._plotInstance.series[serverRegistration.serverId + 1].show = serverRegistration.isVisible
|
this._plotInstance.series[serverRegistration.getGraphDataIndex()].show = serverRegistration.isVisible
|
||||||
}
|
}
|
||||||
|
|
||||||
this._plotInstance.redraw()
|
this._plotInstance.redraw()
|
||||||
@ -306,6 +347,21 @@ export class GraphDisplayManager {
|
|||||||
this._resizeRequestTimeout = undefined
|
this._resizeRequestTimeout = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handlePlotZoomIn = () => {
|
||||||
|
this._isPlotZoomed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePlotZoomOut = () => {
|
||||||
|
this._isPlotZoomed = false
|
||||||
|
|
||||||
|
// Test if the data has changed while the plot was zoomed in
|
||||||
|
if (this._isPlotZoomedDataDirty) {
|
||||||
|
this._isPlotZoomedDataDirty = false
|
||||||
|
|
||||||
|
this._plotInstance.setData(this.getGraphData())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
initEventListeners () {
|
initEventListeners () {
|
||||||
if (!this._initEventListenersOnce) {
|
if (!this._initEventListenersOnce) {
|
||||||
this._initEventListenersOnce = true
|
this._initEventListenersOnce = true
|
||||||
@ -413,6 +469,9 @@ export class GraphDisplayManager {
|
|||||||
this._graphData = []
|
this._graphData = []
|
||||||
this._hasLoadedSettings = false
|
this._hasLoadedSettings = false
|
||||||
|
|
||||||
|
this._isPlotZoomed = false
|
||||||
|
this._isPlotZoomedDataDirty = false
|
||||||
|
|
||||||
// Fire #clearTimeout if the timeout is currently defined
|
// Fire #clearTimeout if the timeout is currently defined
|
||||||
if (this._resizeRequestTimeout) {
|
if (this._resizeRequestTimeout) {
|
||||||
clearTimeout(this._resizeRequestTimeout)
|
clearTimeout(this._resizeRequestTimeout)
|
||||||
|
@ -13,8 +13,8 @@ export class MojangUpdater {
|
|||||||
|
|
||||||
updateServiceStatus (name, title) {
|
updateServiceStatus (name, title) {
|
||||||
// HACK: ensure mojang-status is added for alignment, replace existing class to swap status color
|
// HACK: ensure mojang-status is added for alignment, replace existing class to swap status color
|
||||||
document.getElementById('mojang-status_' + name).setAttribute('class', MOJANG_STATUS_BASE_CLASS + ' mojang-status-' + title.toLowerCase())
|
document.getElementById(`mojang-status_${name}`).setAttribute('class', `${MOJANG_STATUS_BASE_CLASS} mojang-status-${title.toLowerCase()}`)
|
||||||
document.getElementById('mojang-status-text_' + name).innerText = title
|
document.getElementById(`mojang-status-text_${name}`).innerText = title
|
||||||
}
|
}
|
||||||
|
|
||||||
reset () {
|
reset () {
|
||||||
|
@ -20,12 +20,15 @@ export class PercentageBar {
|
|||||||
|
|
||||||
// Update position/width
|
// Update position/width
|
||||||
// leftPadding is a sum of previous iterations width value
|
// leftPadding is a sum of previous iterations width value
|
||||||
const div = document.getElementById('perc-bar-part_' + serverRegistration.serverId) || this.createPart(serverRegistration)
|
const div = document.getElementById(`perc-bar-part_${serverRegistration.serverId}`) || this.createPart(serverRegistration)
|
||||||
|
|
||||||
|
const widthPixels = `${width}px`
|
||||||
|
const leftPaddingPixels = `${leftPadding}px`
|
||||||
|
|
||||||
// Only redraw if needed
|
// Only redraw if needed
|
||||||
if (div.style.width !== width + 'px' || div.style.left !== leftPadding + 'px') {
|
if (div.style.width !== widthPixels || div.style.left !== leftPaddingPixels) {
|
||||||
div.style.width = width + 'px'
|
div.style.width = widthPixels
|
||||||
div.style.left = leftPadding + 'px'
|
div.style.left = leftPaddingPixels
|
||||||
}
|
}
|
||||||
|
|
||||||
leftPadding += width
|
leftPadding += width
|
||||||
@ -35,7 +38,7 @@ export class PercentageBar {
|
|||||||
createPart (serverRegistration) {
|
createPart (serverRegistration) {
|
||||||
const div = document.createElement('div')
|
const div = document.createElement('div')
|
||||||
|
|
||||||
div.id = 'perc-bar-part_' + serverRegistration.serverId
|
div.id = `perc-bar-part_${serverRegistration.serverId}`
|
||||||
div.style.background = serverRegistration.data.color
|
div.style.background = serverRegistration.data.color
|
||||||
|
|
||||||
div.setAttribute('class', 'perc-bar-part')
|
div.setAttribute('class', 'perc-bar-part')
|
||||||
@ -55,10 +58,10 @@ export class PercentageBar {
|
|||||||
const serverRegistration = this._app.serverRegistry.getServerRegistration(serverId)
|
const serverRegistration = this._app.serverRegistry.getServerRegistration(serverId)
|
||||||
|
|
||||||
this._app.tooltip.set(event.target.offsetLeft, event.target.offsetTop, 10, this._parent.offsetTop + this._parent.offsetHeight + 10,
|
this._app.tooltip.set(event.target.offsetLeft, event.target.offsetTop, 10, this._parent.offsetTop + this._parent.offsetHeight + 10,
|
||||||
(typeof serverRegistration.rankIndex !== 'undefined' ? '#' + (serverRegistration.rankIndex + 1) + ' ' : '') +
|
`${typeof serverRegistration.rankIndex !== 'undefined' ? `#${serverRegistration.rankIndex + 1} ` : ''}
|
||||||
serverRegistration.data.name +
|
${serverRegistration.data.name}<br>
|
||||||
'<br>' + formatNumber(serverRegistration.playerCount) + ' Players<br>' +
|
${formatNumber(serverRegistration.playerCount)} Players<br>
|
||||||
'<strong>' + formatPercent(serverRegistration.playerCount, this._app.getTotalPlayerCount()) + '</strong>')
|
<strong>${formatPercent(serverRegistration.playerCount, this._app.getTotalPlayerCount())}</strong>`)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMouseOut = () => {
|
handleMouseOut = () => {
|
||||||
|
@ -26,3 +26,27 @@ export function uPlotTooltipPlugin (onHover) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function uPlotIsZoomedPlugin (onZoomIn, onZoomOut) {
|
||||||
|
return {
|
||||||
|
hooks: {
|
||||||
|
setSelect: u => {
|
||||||
|
u._zoomPluginIgnoreNextSetScale = true
|
||||||
|
|
||||||
|
if (onZoomIn) {
|
||||||
|
onZoomIn(u)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setScale: u => {
|
||||||
|
if (typeof u._zoomPluginIgnoreNextSetScale !== 'boolean') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (u._zoomPluginIgnoreNextSetScale) {
|
||||||
|
u._zoomPluginIgnoreNextSetScale = false
|
||||||
|
} else if (onZoomOut) {
|
||||||
|
onZoomOut(u)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
export class RelativeScale {
|
export class RelativeScale {
|
||||||
static scale (data, tickCount, maxFactor) {
|
static scale (data, tickCount, maxFactor) {
|
||||||
const [min, max] = RelativeScale.calculateBounds(data)
|
const { min, max } = RelativeScale.calculateBounds(data)
|
||||||
|
|
||||||
let factor = 1
|
let factor = 1
|
||||||
|
|
||||||
@ -12,8 +12,12 @@ export class RelativeScale {
|
|||||||
|
|
||||||
const ticks = (scaledMax - scaledMin) / scale
|
const ticks = (scaledMax - scaledMin) / scale
|
||||||
|
|
||||||
if (ticks < tickCount + 1 || (typeof maxFactor === 'number' && factor === maxFactor)) {
|
if (ticks <= tickCount || (typeof maxFactor === 'number' && factor === maxFactor)) {
|
||||||
return [scaledMin, scaledMax, scale]
|
return {
|
||||||
|
scaledMin,
|
||||||
|
scaledMax,
|
||||||
|
scale
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Too many steps between min/max, increase factor and try again
|
// Too many steps between min/max, increase factor and try again
|
||||||
factor++
|
factor++
|
||||||
@ -22,27 +26,9 @@ export class RelativeScale {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static scaleMatrix (data, tickCount, maxFactor) {
|
static scaleMatrix (data, tickCount, maxFactor) {
|
||||||
let max = Number.MIN_VALUE
|
const max = Math.max(...data.flat())
|
||||||
|
|
||||||
for (const row of data) {
|
return RelativeScale.scale([0, RelativeScale.isFiniteOrZero(max)], tickCount, maxFactor)
|
||||||
let testMax = Number.MIN_VALUE
|
|
||||||
|
|
||||||
for (const point of row) {
|
|
||||||
if (point > testMax) {
|
|
||||||
testMax = point
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (testMax > max) {
|
|
||||||
max = testMax
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (max === Number.MIN_VALUE) {
|
|
||||||
max = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return RelativeScale.scale([0, max], tickCount, maxFactor)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static generateTicks (min, max, step) {
|
static generateTicks (min, max, step) {
|
||||||
@ -55,30 +41,22 @@ export class RelativeScale {
|
|||||||
|
|
||||||
static calculateBounds (data) {
|
static calculateBounds (data) {
|
||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
return [0, 0]
|
return {
|
||||||
|
min: 0,
|
||||||
|
max: 0
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let min = Number.MAX_VALUE
|
const min = Math.min(...data)
|
||||||
let max = Number.MIN_VALUE
|
const max = Math.max(...data)
|
||||||
|
|
||||||
for (const point of data) {
|
return {
|
||||||
if (typeof point === 'number') {
|
min: RelativeScale.isFiniteOrZero(min),
|
||||||
if (point > max) {
|
max: RelativeScale.isFiniteOrZero(max)
|
||||||
max = point
|
|
||||||
}
|
|
||||||
if (point < min) {
|
|
||||||
min = point
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (min === Number.MAX_VALUE) {
|
|
||||||
min = 0
|
|
||||||
}
|
|
||||||
if (max === Number.MIN_VALUE) {
|
|
||||||
max = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return [min, max]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static isFiniteOrZero (val) {
|
||||||
|
return Number.isFinite(val) ? val : 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import uPlot from 'uplot'
|
|||||||
import { RelativeScale } from './scale'
|
import { RelativeScale } from './scale'
|
||||||
|
|
||||||
import { formatNumber, formatTimestampSeconds, formatDate, formatMinecraftServerAddress, formatMinecraftVersions } from './util'
|
import { formatNumber, formatTimestampSeconds, formatDate, formatMinecraftServerAddress, formatMinecraftVersions } from './util'
|
||||||
import { uPlotTooltipPlugin } from './tooltip'
|
import { uPlotTooltipPlugin } from './plugins'
|
||||||
|
|
||||||
import MISSING_FAVICON from '../images/missing_favicon.svg'
|
import MISSING_FAVICON from '../images/missing_favicon.svg'
|
||||||
|
|
||||||
@ -67,6 +67,10 @@ export class ServerRegistration {
|
|||||||
this._failedSequentialPings = 0
|
this._failedSequentialPings = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getGraphDataIndex () {
|
||||||
|
return this.serverId + 1
|
||||||
|
}
|
||||||
|
|
||||||
addGraphPoints (points, timestampPoints) {
|
addGraphPoints (points, timestampPoints) {
|
||||||
this._graphData = [
|
this._graphData = [
|
||||||
timestampPoints.slice(),
|
timestampPoints.slice(),
|
||||||
@ -87,9 +91,7 @@ export class ServerRegistration {
|
|||||||
if (typeof playerCount !== 'number') {
|
if (typeof playerCount !== 'number') {
|
||||||
this._app.tooltip.hide()
|
this._app.tooltip.hide()
|
||||||
} else {
|
} else {
|
||||||
const text = formatNumber(playerCount) + ' Players<br>' + formatTimestampSeconds(this._graphData[0][id])
|
this._app.tooltip.set(pos.left, pos.top, 10, 10, `${formatNumber(playerCount)} Players<br>${formatTimestampSeconds(this._graphData[0][id])}`)
|
||||||
|
|
||||||
this._app.tooltip.set(pos.left, pos.top, 10, 10, text)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this._app.tooltip.hide()
|
this._app.tooltip.hide()
|
||||||
@ -116,7 +118,7 @@ export class ServerRegistration {
|
|||||||
scale: 'Players',
|
scale: 'Players',
|
||||||
stroke: '#E9E581',
|
stroke: '#E9E581',
|
||||||
width: 2,
|
width: 2,
|
||||||
value: (_, raw) => formatNumber(raw) + ' Players',
|
value: (_, raw) => `${formatNumber(raw)} Players`,
|
||||||
spanGaps: true,
|
spanGaps: true,
|
||||||
points: {
|
points: {
|
||||||
show: false
|
show: false
|
||||||
@ -139,8 +141,8 @@ export class ServerRegistration {
|
|||||||
width: 1
|
width: 1
|
||||||
},
|
},
|
||||||
split: () => {
|
split: () => {
|
||||||
const [min, max, scale] = RelativeScale.scale(this._graphData[1], tickCount)
|
const { scaledMin, scaledMax, scale } = RelativeScale.scale(this._graphData[1], tickCount)
|
||||||
const ticks = RelativeScale.generateTicks(min, max, scale)
|
const ticks = RelativeScale.generateTicks(scaledMin, scaledMax, scale)
|
||||||
return ticks
|
return ticks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,7 +151,7 @@ export class ServerRegistration {
|
|||||||
Players: {
|
Players: {
|
||||||
auto: false,
|
auto: false,
|
||||||
range: () => {
|
range: () => {
|
||||||
const [scaledMin, scaledMax] = RelativeScale.scale(this._graphData[1], tickCount)
|
const { scaledMin, scaledMax } = RelativeScale.scale(this._graphData[1], tickCount)
|
||||||
return [scaledMin, scaledMax]
|
return [scaledMin, scaledMax]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,7 +159,7 @@ export class ServerRegistration {
|
|||||||
legend: {
|
legend: {
|
||||||
show: false
|
show: false
|
||||||
}
|
}
|
||||||
}, this._graphData, document.getElementById('chart_' + this.serverId))
|
}, this._graphData, document.getElementById(`chart_${this.serverId}`))
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePing (payload, timestamp) {
|
handlePing (payload, timestamp) {
|
||||||
@ -193,15 +195,15 @@ export class ServerRegistration {
|
|||||||
updateServerRankIndex (rankIndex) {
|
updateServerRankIndex (rankIndex) {
|
||||||
this.rankIndex = rankIndex
|
this.rankIndex = rankIndex
|
||||||
|
|
||||||
document.getElementById('ranking_' + this.serverId).innerText = '#' + (rankIndex + 1)
|
document.getElementById(`ranking_${this.serverId}`).innerText = `#${rankIndex + 1}`
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderValue (prefix, handler) {
|
_renderValue (prefix, handler) {
|
||||||
const labelElement = document.getElementById(prefix + '_' + this.serverId)
|
const labelElement = document.getElementById(`${prefix}_${this.serverId}`)
|
||||||
|
|
||||||
labelElement.style.display = 'block'
|
labelElement.style.display = 'block'
|
||||||
|
|
||||||
const valueElement = document.getElementById(prefix + '-value_' + this.serverId)
|
const valueElement = document.getElementById(`${prefix}-value_${this.serverId}`)
|
||||||
const targetElement = valueElement || labelElement
|
const targetElement = valueElement || labelElement
|
||||||
|
|
||||||
if (targetElement) {
|
if (targetElement) {
|
||||||
@ -214,7 +216,7 @@ export class ServerRegistration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_hideValue (prefix) {
|
_hideValue (prefix) {
|
||||||
const element = document.getElementById(prefix + '_' + this.serverId)
|
const element = document.getElementById(`${prefix}_${this.serverId}`)
|
||||||
|
|
||||||
element.style.display = 'none'
|
element.style.display = 'none'
|
||||||
}
|
}
|
||||||
@ -227,8 +229,8 @@ export class ServerRegistration {
|
|||||||
if (ping.recordData) {
|
if (ping.recordData) {
|
||||||
this._renderValue('record', (element) => {
|
this._renderValue('record', (element) => {
|
||||||
if (ping.recordData.timestamp > 0) {
|
if (ping.recordData.timestamp > 0) {
|
||||||
element.innerText = formatNumber(ping.recordData.playerCount) + ' (' + formatDate(ping.recordData.timestamp) + ')'
|
element.innerText = `${formatNumber(ping.recordData.playerCount)} (${formatDate(ping.recordData.timestamp)})`
|
||||||
element.title = 'At ' + formatDate(ping.recordData.timestamp) + ' ' + formatTimestampSeconds(ping.recordData.timestamp)
|
element.title = `At ${formatDate(ping.recordData.timestamp)} ${formatTimestampSeconds(ping.recordData.timestamp)}`
|
||||||
} else {
|
} else {
|
||||||
element.innerText = formatNumber(ping.recordData.playerCount)
|
element.innerText = formatNumber(ping.recordData.playerCount)
|
||||||
}
|
}
|
||||||
@ -240,7 +242,7 @@ export class ServerRegistration {
|
|||||||
if (ping.graphPeakData) {
|
if (ping.graphPeakData) {
|
||||||
this._renderValue('peak', (element) => {
|
this._renderValue('peak', (element) => {
|
||||||
element.innerText = formatNumber(ping.graphPeakData.playerCount)
|
element.innerText = formatNumber(ping.graphPeakData.playerCount)
|
||||||
element.title = 'At ' + formatTimestampSeconds(ping.graphPeakData.timestamp)
|
element.title = `At ${formatTimestampSeconds(ping.graphPeakData.timestamp)}`
|
||||||
})
|
})
|
||||||
|
|
||||||
this.lastPeakData = ping.graphPeakData
|
this.lastPeakData = ping.graphPeakData
|
||||||
@ -262,7 +264,7 @@ export class ServerRegistration {
|
|||||||
|
|
||||||
// An updated favicon has been sent, update the src
|
// An updated favicon has been sent, update the src
|
||||||
if (ping.favicon) {
|
if (ping.favicon) {
|
||||||
const faviconElement = document.getElementById('favicon_' + this.serverId)
|
const faviconElement = document.getElementById(`favicon_${this.serverId}`)
|
||||||
|
|
||||||
// Since favicons may be URLs, only update the attribute when it has changed
|
// Since favicons may be URLs, only update the attribute when it has changed
|
||||||
// Otherwise the browser may send multiple requests to the same URL
|
// Otherwise the browser may send multiple requests to the same URL
|
||||||
@ -275,20 +277,20 @@ export class ServerRegistration {
|
|||||||
initServerStatus (latestPing) {
|
initServerStatus (latestPing) {
|
||||||
const serverElement = document.createElement('div')
|
const serverElement = document.createElement('div')
|
||||||
|
|
||||||
serverElement.id = 'container_' + this.serverId
|
serverElement.id = `container_${this.serverId}`
|
||||||
serverElement.innerHTML = '<div class="column column-favicon">' +
|
serverElement.innerHTML = `<div class="column column-favicon">
|
||||||
'<img class="server-favicon" src="' + (latestPing.favicon || MISSING_FAVICON) + '" id="favicon_' + this.serverId + '" title="' + this.data.name + '\n' + formatMinecraftServerAddress(this.data.ip, this.data.port) + '">' +
|
<img class="server-favicon" src="${latestPing.favicon || MISSING_FAVICON}" id="favicon_${this.serverId}" title="${this.data.name}\n${formatMinecraftServerAddress(this.data.ip, this.data.port)}">
|
||||||
'<span class="server-rank" id="ranking_' + this.serverId + '"></span>' +
|
<span class="server-rank" id="ranking_${this.serverId}"></span>
|
||||||
'</div>' +
|
</div>
|
||||||
'<div class="column column-status">' +
|
<div class="column column-status">
|
||||||
'<h3 class="server-name"><span class="' + this._app.favoritesManager.getIconClass(this.isFavorite) + '" id="favorite-toggle_' + this.serverId + '"></span> ' + this.data.name + '</h3>' +
|
<h3 class="server-name"><span class="${this._app.favoritesManager.getIconClass(this.isFavorite)}" id="favorite-toggle_${this.serverId}"></span> ${this.data.name}</h3>
|
||||||
'<span class="server-error" id="error_' + this.serverId + '"></span>' +
|
<span class="server-error" id="error_${this.serverId}"></span>
|
||||||
'<span class="server-label" id="player-count_' + this.serverId + '">Players: <span class="server-value" id="player-count-value_' + this.serverId + '"></span></span>' +
|
<span class="server-label" id="player-count_${this.serverId}">Players: <span class="server-value" id="player-count-value_${this.serverId}"></span></span>
|
||||||
'<span class="server-label" id="peak_' + this.serverId + '">' + this._app.publicConfig.graphDurationLabel + ' Peak: <span class="server-value" id="peak-value_' + this.serverId + '">-</span></span>' +
|
<span class="server-label" id="peak_${this.serverId}">${this._app.publicConfig.graphDurationLabel} Peak: <span class="server-value" id="peak-value_${this.serverId}">-</span></span>
|
||||||
'<span class="server-label" id="record_' + this.serverId + '">Record: <span class="server-value" id="record-value_' + this.serverId + '">-</span></span>' +
|
<span class="server-label" id="record_${this.serverId}">Record: <span class="server-value" id="record-value_${this.serverId}">-</span></span>
|
||||||
'<span class="server-label" id="version_' + this.serverId + '"></span>' +
|
<span class="server-label" id="version_${this.serverId}"></span>
|
||||||
'</div>' +
|
</div>
|
||||||
'<div class="column column-graph" id="chart_' + this.serverId + '"></div>'
|
<div class="column column-graph" id="chart_${this.serverId}"></div>`
|
||||||
|
|
||||||
serverElement.setAttribute('class', 'server')
|
serverElement.setAttribute('class', 'server')
|
||||||
|
|
||||||
@ -297,8 +299,8 @@ export class ServerRegistration {
|
|||||||
|
|
||||||
updateHighlightedValue (selectedCategory) {
|
updateHighlightedValue (selectedCategory) {
|
||||||
['player-count', 'peak', 'record'].forEach((category) => {
|
['player-count', 'peak', 'record'].forEach((category) => {
|
||||||
const labelElement = document.getElementById(category + '_' + this.serverId)
|
const labelElement = document.getElementById(`${category}_${this.serverId}`)
|
||||||
const valueElement = document.getElementById(category + '-value_' + this.serverId)
|
const valueElement = document.getElementById(`${category}-value_${this.serverId}`)
|
||||||
|
|
||||||
if (selectedCategory && category === selectedCategory) {
|
if (selectedCategory && category === selectedCategory) {
|
||||||
labelElement.setAttribute('class', 'server-highlighted-label')
|
labelElement.setAttribute('class', 'server-highlighted-label')
|
||||||
@ -311,7 +313,7 @@ export class ServerRegistration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initEventListeners () {
|
initEventListeners () {
|
||||||
document.getElementById('favorite-toggle_' + this.serverId).addEventListener('click', () => {
|
document.getElementById(`favorite-toggle_${this.serverId}`).addEventListener('click', () => {
|
||||||
this._app.favoritesManager.handleFavoriteButtonClick(this)
|
this._app.favoritesManager.handleFavoriteButtonClick(this)
|
||||||
}, false)
|
}, false)
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ export class SocketManager {
|
|||||||
webSocketProtocol = 'wss:'
|
webSocketProtocol = 'wss:'
|
||||||
}
|
}
|
||||||
|
|
||||||
this._webSocket = new WebSocket(webSocketProtocol + '//' + location.host)
|
this._webSocket = new WebSocket(`${webSocketProtocol}//${location.host}`)
|
||||||
|
|
||||||
// The backend will automatically push data once connected
|
// The backend will automatically push data once connected
|
||||||
this._webSocket.onopen = () => {
|
this._webSocket.onopen = () => {
|
||||||
@ -119,10 +119,10 @@ export class SocketManager {
|
|||||||
.forEach(serverName => {
|
.forEach(serverName => {
|
||||||
const serverRegistration = this._app.serverRegistry.getServerRegistration(serverName)
|
const serverRegistration = this._app.serverRegistry.getServerRegistration(serverName)
|
||||||
|
|
||||||
controlsHTML += '<td>' +
|
controlsHTML += `<td>
|
||||||
'<input type="checkbox" class="graph-control" minetrack-server-id="' + serverRegistration.serverId + '" ' + (serverRegistration.isVisible ? 'checked' : '') + '>' +
|
<input type="checkbox" class="graph-control" minetrack-server-id="${serverRegistration.serverId}" ${serverRegistration.isVisible ? 'checked' : ''}>
|
||||||
' ' + serverName +
|
${serverName}
|
||||||
'</input></td>'
|
</input></td>`
|
||||||
|
|
||||||
// Occasionally break table rows using a magic number
|
// Occasionally break table rows using a magic number
|
||||||
if (++lastRowCounter % 6 === 0) {
|
if (++lastRowCounter % 6 === 0) {
|
||||||
@ -131,10 +131,7 @@ export class SocketManager {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Apply generated HTML and show controls
|
// Apply generated HTML and show controls
|
||||||
document.getElementById('big-graph-checkboxes').innerHTML = '<table><tr>' +
|
document.getElementById('big-graph-checkboxes').innerHTML = `<table><tr>${controlsHTML}</tr></table>`
|
||||||
controlsHTML +
|
|
||||||
'</tr></table>'
|
|
||||||
|
|
||||||
document.getElementById('big-graph-controls').style.display = 'block'
|
document.getElementById('big-graph-controls').style.display = 'block'
|
||||||
|
|
||||||
// Bind click event for updating graph data
|
// Bind click event for updating graph data
|
||||||
@ -171,7 +168,7 @@ export class SocketManager {
|
|||||||
this.createWebSocket()
|
this.createWebSocket()
|
||||||
} else if (this._reconnectDelaySeconds > 0) {
|
} else if (this._reconnectDelaySeconds > 0) {
|
||||||
// Update displayed text
|
// Update displayed text
|
||||||
this._app.caption.set('Reconnecting in ' + this._reconnectDelaySeconds + 's...')
|
this._app.caption.set(`Reconnecting in ${this._reconnectDelaySeconds}s...`)
|
||||||
}
|
}
|
||||||
}, 1000)
|
}, 1000)
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ const SORT_OPTIONS = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
getName: (app) => {
|
getName: (app) => {
|
||||||
return app.publicConfig.graphDurationLabel + ' Peak'
|
return `${app.publicConfig.graphDurationLabel} Peak`
|
||||||
},
|
},
|
||||||
sortFunc: (a, b) => {
|
sortFunc: (a, b) => {
|
||||||
if (!a.lastPeakData && !b.lastPeakData) {
|
if (!a.lastPeakData && !b.lastPeakData) {
|
||||||
@ -188,7 +188,7 @@ export class SortController {
|
|||||||
// Update the DOM structure
|
// Update the DOM structure
|
||||||
sortedServers.forEach(function (serverRegistration) {
|
sortedServers.forEach(function (serverRegistration) {
|
||||||
const parentElement = document.getElementById('server-list')
|
const parentElement = document.getElementById('server-list')
|
||||||
const serverElement = document.getElementById('container_' + serverRegistration.serverId)
|
const serverElement = document.getElementById(`container_${serverRegistration.serverId}`)
|
||||||
|
|
||||||
parentElement.appendChild(serverElement)
|
parentElement.appendChild(serverElement)
|
||||||
|
|
||||||
|
@ -19,8 +19,8 @@ export class Tooltip {
|
|||||||
offsetX *= -1
|
offsetX *= -1
|
||||||
}
|
}
|
||||||
|
|
||||||
this._div.style.top = (y + offsetY) + 'px'
|
this._div.style.top = `${y + offsetY}px`
|
||||||
this._div.style.left = (x + offsetX) + 'px'
|
this._div.style.left = `${x + offsetX}px`
|
||||||
}
|
}
|
||||||
|
|
||||||
hide = () => {
|
hide = () => {
|
||||||
@ -49,7 +49,7 @@ const MINECRAFT_DEFAULT_PORTS = [25565, 19132]
|
|||||||
|
|
||||||
export function formatMinecraftServerAddress (ip, port) {
|
export function formatMinecraftServerAddress (ip, port) {
|
||||||
if (port && !MINECRAFT_DEFAULT_PORTS.includes(port)) {
|
if (port && !MINECRAFT_DEFAULT_PORTS.includes(port)) {
|
||||||
return ip + ':' + port
|
return `${ip}:${port}`
|
||||||
}
|
}
|
||||||
return ip
|
return ip
|
||||||
}
|
}
|
||||||
@ -93,8 +93,7 @@ export function formatMinecraftVersions (versions, knownVersions) {
|
|||||||
return startVersion
|
return startVersion
|
||||||
} else {
|
} else {
|
||||||
const endVersion = knownVersions[versionGroup[versionGroup.length - 1]]
|
const endVersion = knownVersions[versionGroup[versionGroup.length - 1]]
|
||||||
|
return `${startVersion}-${endVersion}`
|
||||||
return startVersion + '-' + endVersion
|
|
||||||
}
|
}
|
||||||
}).join(', ')
|
}).join(', ')
|
||||||
}
|
}
|
||||||
@ -113,9 +112,13 @@ export function formatDate (secs) {
|
|||||||
|
|
||||||
export function formatPercent (x, over) {
|
export function formatPercent (x, over) {
|
||||||
const val = Math.round((x / over) * 100 * 10) / 10
|
const val = Math.round((x / over) * 100 * 10) / 10
|
||||||
return val + '%'
|
return `${val}%`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatNumber (x) {
|
export function formatNumber (x) {
|
||||||
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
if (typeof x !== 'number') {
|
||||||
|
return '-'
|
||||||
|
} else {
|
||||||
|
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,11 @@
|
|||||||
|
**5.5.1** *(June 10 2020)*
|
||||||
|
- New tooltip hover design on the historical graph. It will highlight the server closest to your cursor.
|
||||||
|
- Historical graph is now limited to 10,000 increments on the Y axis. This prevents servers with over 100,000 players forcing the graph into 100,000 increments.
|
||||||
|
- Fixed the historical graph zooming out when receiving new data points.
|
||||||
|
- Fixed newly added servers aligning to the left of the historical graph.
|
||||||
|
- Replaces manual string concats with template literals.
|
||||||
|
- Updated various dependencies.
|
||||||
|
|
||||||
**5.5.0** *(May 20 2020)*
|
**5.5.0** *(May 20 2020)*
|
||||||
|
|
||||||
**IMPORTANT**
|
**IMPORTANT**
|
||||||
|
1109
package-lock.json
generated
1109
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
20
package.json
20
package.json
@ -1,18 +1,18 @@
|
|||||||
{
|
{
|
||||||
"name": "minetrack",
|
"name": "minetrack",
|
||||||
"version": "5.5.0",
|
"version": "5.5.1",
|
||||||
"description": "A Minecraft server tracker that lets you focus on the basics.",
|
"description": "A Minecraft server tracker that lets you focus on the basics.",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"finalhandler": "^1.1.2",
|
"finalhandler": "^1.1.2",
|
||||||
"mcpe-ping-fixed": "0.0.3",
|
"mcpe-ping-fixed": "0.0.3",
|
||||||
"mcping-js": "^1.4.0",
|
"mcping-js": "^1.4.1",
|
||||||
"request": "2.88.2",
|
"request": "2.88.2",
|
||||||
"serve-static": "^1.14.1",
|
"serve-static": "^1.14.1",
|
||||||
"sqlite3": "4.1.1",
|
"sqlite3": "4.2.0",
|
||||||
"uplot": "^1.0.8",
|
"uplot": "1.0.8",
|
||||||
"winston": "^2.0.0",
|
"winston": "^2.4.4",
|
||||||
"ws": "^7.2.5"
|
"ws": "^7.3.0"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -31,12 +31,12 @@
|
|||||||
"node": ">=12.4.0"
|
"node": ">=12.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.9.0",
|
"@babel/core": "^7.10.2",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.8.3",
|
"@babel/plugin-proposal-class-properties": "^7.10.1",
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
"eslint": "^6.8.0",
|
"eslint": "^7.2.0",
|
||||||
"eslint-config-standard": "^14.1.1",
|
"eslint-config-standard": "^14.1.1",
|
||||||
"eslint-plugin-import": "^2.20.2",
|
"eslint-plugin-import": "^2.21.1",
|
||||||
"eslint-plugin-node": "^11.1.0",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
"eslint-plugin-promise": "^4.2.1",
|
"eslint-plugin-promise": "^4.2.1",
|
||||||
"eslint-plugin-standard": "^4.0.1",
|
"eslint-plugin-standard": "^4.0.1",
|
||||||
|
Loading…
Reference in New Issue
Block a user