diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/json/JSONFileStorage.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/json/JSONFileStorage.java index 61975cde6..4e0eb7802 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/json/JSONFileStorage.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/json/JSONFileStorage.java @@ -18,6 +18,8 @@ package com.djrapitops.plan.storage.json; import com.djrapitops.plan.DebugChannels; import com.djrapitops.plan.TaskSystem; +import com.djrapitops.plan.delivery.formatting.Formatter; +import com.djrapitops.plan.delivery.formatting.Formatters; import com.djrapitops.plan.settings.config.PlanConfig; import com.djrapitops.plan.settings.config.paths.WebserverSettings; import com.djrapitops.plan.storage.file.PlanFiles; @@ -60,11 +62,19 @@ public class JSONFileStorage implements JSONStorage { private static final String JSON_FILE_EXTENSION = ".json"; private final DebugLogger debugLogger; + private final Formatter dateFormatter; + @Inject - public JSONFileStorage(PlanFiles files, PluginLogger logger) { + public JSONFileStorage( + PlanFiles files, + Formatters formatters, + PluginLogger logger + ) { this.logger = logger; debugLogger = logger.getDebugLogger(); + dateFormatter = formatters.yearLong(); + jsonDirectory = files.getJSONStorageDirectory(); } @@ -77,7 +87,7 @@ public class JSONFileStorage implements JSONStorage { } catch (IOException e) { logger.warn("Could not write a file to " + writingTo.toFile().getAbsolutePath() + ": " + e.getMessage()); } - return new StoredJSON(json, timestamp); + return new StoredJSON(json, timestamp, dateFormatter); } @Override @@ -100,7 +110,7 @@ public class JSONFileStorage implements JSONStorage { long timestamp = Long.parseLong(timestampMatch.group(1)); StringBuilder json = new StringBuilder(); lines.forEach(json::append); - return new StoredJSON(json.toString(), timestamp); + return new StoredJSON(json.toString(), timestamp, dateFormatter); } catch (IOException e) { logger.warn(jsonDirectory.toFile().getAbsolutePath() + " file '" + from.getName() + "' could not be read: " + e.getMessage()); } catch (NumberFormatException e) { diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/json/JSONStorage.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/json/JSONStorage.java index 21d82e7f3..439ed53b9 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/json/JSONStorage.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/json/JSONStorage.java @@ -17,6 +17,7 @@ package com.djrapitops.plan.storage.json; import com.djrapitops.plan.SubSystem; +import com.djrapitops.plan.delivery.formatting.Formatter; import com.google.gson.Gson; import java.util.Objects; @@ -65,11 +66,13 @@ public interface JSONStorage extends SubSystem { public final String json; public final long timestamp; - public StoredJSON(String json, long timestamp) { + public StoredJSON(String json, long timestamp, Formatter dateFormatter) { if (!json.startsWith("{\"") || json.contains("timestamp")) { this.json = json; } else { - this.json = "{\"timestamp\": " + timestamp + ",\"" + json.substring(2); + this.json = "{\"timestamp\": " + timestamp + + ",\"timestamp_f\":\"" + dateFormatter.apply(timestamp) + + "\",\"" + json.substring(2); } this.timestamp = timestamp; } diff --git a/Plan/common/src/main/resources/assets/plan/web/css/style.css b/Plan/common/src/main/resources/assets/plan/web/css/style.css index cbf38d93e..54cf537e9 100644 --- a/Plan/common/src/main/resources/assets/plan/web/css/style.css +++ b/Plan/common/src/main/resources/assets/plan/web/css/style.css @@ -1252,4 +1252,9 @@ body.sidebar-hidden .navbar-nav { #filter-dropdown { max-height: 18rem; overflow-y: scroll; +} + +.refresh-element { + font-size: 1rem; + margin-left: 1rem; } \ No newline at end of file diff --git a/Plan/common/src/main/resources/assets/plan/web/js/server-values.js b/Plan/common/src/main/resources/assets/plan/web/js/server-values.js index a3a8c131e..e152fceb3 100644 --- a/Plan/common/src/main/resources/assets/plan/web/js/server-values.js +++ b/Plan/common/src/main/resources/assets/plan/web/js/server-values.js @@ -42,83 +42,83 @@ function displayError(element, error) { /* This function loads Server Overview tab */ function loadserverOverviewValues(json, error) { - tab = $('#server-overview'); + const tab = document.getElementById('server-overview'); if (error) { - displayError(tab, error); + displayError($('#server-overview'), error); return; } // Last 7 days - data = json.last_7_days; - element = $(tab).find('#data_7_days'); + let data = json.last_7_days; + let element = tab.querySelector('#data_7_days'); - $(element).find('#data_unique').text(data.unique_players); - $(element).find('#data_unique_day').text(data.unique_players_day); - $(element).find('#data_new').text(data.new_players); - $(element).find('#data_retention').text('(' + data.new_players_retention + '/' + data.new_players + ')'); - $(element).find('#data_retention_perc').text(data.new_players_retention_perc); + element.querySelector('#data_unique').innerText = data.unique_players; + element.querySelector('#data_unique_day').innerText = data.unique_players_day; + element.querySelector('#data_new').innerText = data.new_players; + element.querySelector('#data_retention').innerText = '(' + data.new_players_retention + '/' + data.new_players + ')'; + element.querySelector('#data_retention_perc').innerText = data.new_players_retention_perc; - $(element).find('#data_avg_tps').text(data.average_tps); - $(element).find('#data_low_tps_spikes').text(data.low_tps_spikes); - $(element).find('#data_downtime').text(data.downtime); + element.querySelector('#data_avg_tps').innerText = data.average_tps; + element.querySelector('#data_low_tps_spikes').innerText = data.low_tps_spikes; + element.querySelector('#data_downtime').innerText = data.downtime; // Server As Numbers data = json.numbers; - element = $(tab).find('#data_numbers'); + element = tab.querySelector('#data_numbers'); - $(element).find('#data_total').text(data.total_players); - $(element).find('#data_regular').text(data.regular_players); - $(element).find('#data_online').text(data.online_players); + element.querySelector('#data_total').innerText = data.total_players; + element.querySelector('#data_regular').innerText = data.regular_players; + element.querySelector('#data_online').innerText = data.online_players; - $(element).find('#data_last_peak_date').text(data.last_peak_date); - $(element).find('#data_last_peak_players').text(data.last_peak_players); - $(element).find('#data_best_peak_date').text(data.best_peak_date); - $(element).find('#data_best_peak_players').text(data.best_peak_players); + element.querySelector('#data_last_peak_date').innerText = data.last_peak_date; + element.querySelector('#data_last_peak_players').innerText = data.last_peak_players; + element.querySelector('#data_best_peak_date').innerText = data.best_peak_date; + element.querySelector('#data_best_peak_players').innerText = data.best_peak_players; - $(element).find('#data_playtime').text(data.playtime); - $(element).find('#data_player_playtime').text(data.player_playtime); - $(element).find('#data_sessions').text(data.sessions); + element.querySelector('#data_playtime').innerText = data.playtime; + element.querySelector('#data_player_playtime').innerText = data.player_playtime; + element.querySelector('#data_sessions').innerText = data.sessions; - $(element).find('#data_player_kills').text(data.player_kills); - $(element).find('#data_mob_kills').text(data.mob_kills); - $(element).find('#data_deaths').text(data.deaths); + element.querySelector('#data_player_kills').innerText = data.player_kills; + element.querySelector('#data_mob_kills').innerText = data.mob_kills; + element.querySelector('#data_deaths').innerText = data.deaths; // Week Comparison data = json.weeks; - element = $(tab).find('#data_weeks'); + element = tab.querySelector('#data_weeks'); - $(element).find('#data_start').text(data.start); - $(element).find('#data_midpoint').text(data.midpoint); - $(element).find('#data_midpoint2').text(data.midpoint); - $(element).find('#data_end').text(data.end); + element.querySelector('#data_start').innerText = data.start; + element.querySelector('#data_midpoint').innerText = data.midpoint; + element.querySelector('#data_midpoint2').innerText = data.midpoint; + element.querySelector('#data_end').innerText = data.end; - $(element).find('#data_unique_before').text(data.unique_before); - $(element).find('#data_unique_after').text(data.unique_after); - $(element).find('#data_unique_trend').replaceWith(trend(data.unique_trend)); - $(element).find('#data_new_before').text(data.new_before); - $(element).find('#data_new_after').text(data.new_after); - $(element).find('#data_new_trend').replaceWith(trend(data.new_trend)); - $(element).find('#data_regular_before').text(data.regular_before); - $(element).find('#data_regular_after').text(data.regular_after); - $(element).find('#data_regular_trend').replaceWith(trend(data.regular_trend)); + element.querySelector('#data_unique_before').innerText = data.unique_before; + element.querySelector('#data_unique_after').innerText = data.unique_after; + element.querySelector('#data_unique_trend').innerHTML = trend(data.unique_trend); + element.querySelector('#data_new_before').innerText = data.new_before; + element.querySelector('#data_new_after').innerText = data.new_after; + element.querySelector('#data_new_trend').innerHTML = trend(data.new_trend); + element.querySelector('#data_regular_before').innerText = data.regular_before; + element.querySelector('#data_regular_after').innerText = data.regular_after; + element.querySelector('#data_regular_trend').innerHTML = trend(data.regular_trend); - $(element).find('#data_average_playtime_before').text(data.average_playtime_before); - $(element).find('#data_average_playtime_after').text(data.average_playtime_after); - $(element).find('#data_average_playtime_trend').replaceWith(trend(data.average_playtime_trend)); - $(element).find('#data_sessions_before').text(data.sessions_before); - $(element).find('#data_sessions_after').text(data.sessions_after); - $(element).find('#data_sessions_trend').replaceWith(trend(data.sessions_trend)); + element.querySelector('#data_average_playtime_before').innerText = data.average_playtime_before; + element.querySelector('#data_average_playtime_after').innerText = data.average_playtime_after; + element.querySelector('#data_average_playtime_trend').innerHTML = trend(data.average_playtime_trend); + element.querySelector('#data_sessions_before').innerText = data.sessions_before; + element.querySelector('#data_sessions_after').innerText = data.sessions_after; + element.querySelector('#data_sessions_trend').innerHTML = trend(data.sessions_trend); - $(element).find('#data_player_kills_before').text(data.player_kills_before); - $(element).find('#data_player_kills_after').text(data.player_kills_after); - $(element).find('#data_player_kills_trend').replaceWith(trend(data.player_kills_trend)); - $(element).find('#data_mob_kills_before').text(data.mob_kills_before); - $(element).find('#data_mob_kills_after').text(data.mob_kills_after); - $(element).find('#data_mob_kills_trend').replaceWith(trend(data.mob_kills_trend)); - $(element).find('#data_deaths_before').text(data.deaths_before); - $(element).find('#data_deaths_after').text(data.deaths_after); - $(element).find('#data_deaths_trend').replaceWith(trend(data.deaths_trend)) + element.querySelector('#data_player_kills_before').innerText = data.player_kills_before; + element.querySelector('#data_player_kills_after').innerText = data.player_kills_after; + element.querySelector('#data_player_kills_trend').innerHTML = trend(data.player_kills_trend); + element.querySelector('#data_mob_kills_before').innerText = data.mob_kills_before; + element.querySelector('#data_mob_kills_after').innerText = data.mob_kills_after; + element.querySelector('#data_mob_kills_trend').innerHTML = trend(data.mob_kills_trend); + element.querySelector('#data_deaths_before').innerText = data.deaths_before; + element.querySelector('#data_deaths_after').innerText = data.deaths_after; + element.querySelector('#data_deaths_trend').innerHTML = trend(data.deaths_trend); } /* This function loads Online Activity Overview tab */ diff --git a/Plan/common/src/main/resources/assets/plan/web/js/xmlhttprequests.js b/Plan/common/src/main/resources/assets/plan/web/js/xmlhttprequests.js index 9bfb5de92..3615b4bc9 100644 --- a/Plan/common/src/main/resources/assets/plan/web/js/xmlhttprequests.js +++ b/Plan/common/src/main/resources/assets/plan/web/js/xmlhttprequests.js @@ -1,3 +1,37 @@ +function refreshingJsonRequest(address, callback, tabID) { + const timestamp = Date.now(); + const addressWithTimestamp = address.includes('?') + ? `${address}×tamp=${timestamp}` + : `${address}?timestamp=${timestamp}` + + function makeTheRequest() { + jsonRequest(addressWithTimestamp, (json, error) => { + const refreshElement = document.querySelector(`#${tabID} .refresh-element`); + if (error) { + if (error.status === 400 && error.error.includes('Attempt to get data from the future!')) { + console.error(error.error); // System time not in sync with UTC + refreshElement.innerHTML = "System times out of sync with UTC"; + return jsonRequest(address, callback); + } + refreshElement.querySelector('.refresh-notice').remove(); + return callback(json, error); + } + + refreshElement.querySelector('.refresh-time').innerText = json.timestamp_f; + + const lastUpdated = json.timestamp; + if (lastUpdated < timestamp) { + setTimeout(makeTheRequest, 5000); + } else { + refreshElement.querySelector('.refresh-notice').remove(); + } + callback(json, error); + }) + } + + makeTheRequest(); +} + /** * Make an XMLHttpRequest for JSON data. * @param address Address to request from diff --git a/Plan/common/src/main/resources/assets/plan/web/server.html b/Plan/common/src/main/resources/assets/plan/web/server.html index a92896d01..c8b23cf68 100644 --- a/Plan/common/src/main/resources/assets/plan/web/server.html +++ b/Plan/common/src/main/resources/assets/plan/web/server.html @@ -157,7 +157,12 @@

${serverDisplayName} - · Server Overview

+ · Server Overview + + + Updating.. + + ${backButton}
@@ -1290,7 +1295,7 @@