Skip to content

Commit

Permalink
remove time zone ambiguity, drop momentJS dependency
Browse files Browse the repository at this point in the history
This makes it clear in the UI that times are all in the user's
time zone, not Pacific. It does this using modern JavaScript time
capabilities, so we can drop use of the long-deprecated momentJS
dependency.

I'd kind of like to extend this to always show times in LA time,
but it'd be kind of ugly to hardcode America/Los_Angeles in the
frontend code. This is a good stepping stone, anyway.

#1407
  • Loading branch information
srabraham committed Nov 15, 2024
1 parent 9e04064 commit 14f2c8c
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 40 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ Each month below should look like the following, using the same ordering for the
- Added full Unicode support to IMS. All text fields now accept previously unsupported characters, like those from Cyrillic, Chinese, emoji, and much more ([#1353](https://github.com/burningmantech/ranger-ims-server/issues/1353))
- Started doing client-side retries on any EventSource connection failures. This should mean that an IMS web session will be better kept in sync with incident updates, in particular in the off-season, when IMS is running on AWS ([#1389](https://github.com/burningmantech/ranger-ims-server/pull/1389))
- Added a warning banner to non-production instances of the web UI, to make sure people don't accidentally put prod data into non-production IMS instances. [(#1366](https://github.com/burningmantech/ranger-ims-server/issues/1366))
- Started showing full datetimes, including time zone, when a user hovers over a time on the incidents page. All times have always been in the user's locale, but this wasn't indicated anywhere ([#1412](https://github.com/burningmantech/ranger-ims-server/pull/1412)

### Removed

- Got rid of Moment.js dependency, as it's deprecated and we're able to use the newer Intl JavaScript browser construct instead ([#1412](https://github.com/burningmantech/ranger-ims-server/pull/1412)

### Fixed

Expand Down
20 changes: 0 additions & 20 deletions src/ims/application/_external.py
Original file line number Diff line number Diff line change
Expand Up @@ -683,13 +683,11 @@ class ExternalApplication:
bootstrapVersionNumber = "3.3.7"
jqueryVersionNumber = "3.1.0"
dataTablesVersionNumber = "1.10.12"
momentVersionNumber = "2.22.2"
lscacheVersionNumber = "1.0.5"

bootstrapVersion = f"bootstrap-{bootstrapVersionNumber}-dist"
jqueryVersion = f"jquery-{jqueryVersionNumber}"
dataTablesVersion = f"DataTables-{dataTablesVersionNumber}"
momentVersion = f"moment-{momentVersionNumber}"
lscacheVersion = f"lscache-{lscacheVersionNumber}"

bootstrapSourceURL = URL.fromText(
Expand All @@ -712,11 +710,6 @@ class ExternalApplication:
f"DataTables-{dataTablesVersionNumber}.zip"
)

momentJSSourceURL = URL.fromText(
f"https://cdnjs.cloudflare.com/ajax/libs/moment.js/"
f"{momentVersionNumber}/moment.min.js"
)

lscacheJSSourceURL = URL.fromText(
f"https://raw.githubusercontent.com/pamelafox/lscache/"
f"{lscacheVersionNumber}/lscache.min.js"
Expand Down Expand Up @@ -802,19 +795,6 @@ async def dataTablesResource(self, request: IRequest) -> KleinRenderable:
*names,
)

@router.route(_unprefix(URLs.momentJS), methods=("HEAD", "GET"))
@static
async def momentJSResource(self, request: IRequest) -> KleinRenderable:
"""
Endpoint for moment.js.
"""
request.setHeader(
HeaderName.contentType.value, ContentType.javascript.value
)
return await self.cachedResource(
request, self.momentJSSourceURL, f"{self.momentVersion}.min.js"
)

@router.route(_unprefix(URLs.lscacheJS), methods=("HEAD", "GET"))
@static
async def lscacheJSResource(self, request: IRequest) -> KleinRenderable:
Expand Down
2 changes: 0 additions & 2 deletions src/ims/config/_urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,6 @@ class URLs:
"media", "js", "dataTables.bootstrap.min.js"
)

momentJS: ClassVar[URL] = external.child("moment.min.js")

lscacheJS: ClassVar[URL] = external.child("lscache.min.js")

# Web application
Expand Down
1 change: 0 additions & 1 deletion src/ims/element/page/_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ def add(name: str) -> None:

if name == "ims":
add("jquery")
add("moment")

try:
result[name] = getattr(urls, f"{name}JS")
Expand Down
39 changes: 34 additions & 5 deletions src/ims/element/static/ims.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,10 @@ function parseInt(stringInt) {

// Create a <time> element from a date.
function timeElement(date) {
date = moment(date);
var timeStampContainer = jQuery(
"<time />", {"datetime": date.toISOString()}
);
timeStampContainer.text(date.format("MMMM Do YYYY HH:mm:ss"));
timeStampContainer.text(fullDateTime.format(date));
return timeStampContainer;
}

Expand Down Expand Up @@ -603,15 +602,45 @@ function renderPriority(priorityNumber, type, incident) {
return undefined;
}

// e.g. "Wed, 8/28"
const shortDate = new Intl.DateTimeFormat(undefined, {
weekday: "short",
month: "numeric",
day: "2-digit",
// timeZone not specified; will use user's timezone
});

// e.g. "19:21"
const shortTime = new Intl.DateTimeFormat(undefined, {
hour: "numeric",
hour12: false,
minute: "numeric",
// timeZone not specified; will use user's timezone
});

// e.g. "Oct 8, 2023, 19:11:04 EDT"
const fullDateTime = new Intl.DateTimeFormat(undefined, {
year: "numeric",
month: "short",
day: "numeric",
hour: "numeric",
hour12: false,
minute: "numeric",
second: "numeric",
timeZoneName: "short",
// timeZone not specified; will use user's timezone
});

function renderDate(date, type, incident) {
const d = Date.parse(date);
switch (type) {
case "display":
return moment(date).format("dd M/D[<wbr />]@HH:mm");
return shortDate.format(d) + "<wbr />@" + shortTime.format(d);
case "filter":
return moment(date).format("dd M/D HH:mm");
return shortDate.format(d) + " " + shortTime.format(d);
case "type":
case "sort":
return moment(date);
return d;
}
return undefined;
}
Expand Down
17 changes: 11 additions & 6 deletions src/ims/element/static/incident_reports.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ function initDataTables() {
// Open new context with link
window.open(url, "Incident_Report:" + incidentReport.number);
});
$(row).find(".incident_report_created")
.attr("title", fullDateTime.format(Date.parse(incidentReport.created)));
},
});
}
Expand Down Expand Up @@ -229,12 +231,13 @@ function initSearchField() {

function initSearch() {
function modifiedAfter(incidentReport, timestamp) {
if (timestamp.isBefore(incidentReport.created)) {
if (timestamp < Date.parse(incidentReport.created)) {
return true;
}

// needs to use native comparison
for (var i in incidentReport.report_entries) {
if (timestamp.isBefore(incidentReport.report_entries[i].created)) {
if (timestamp < Date.parse(incidentReport.report_entries[i].created)) {
return true;
}
}
Expand Down Expand Up @@ -280,10 +283,12 @@ function showDays(daysBackToShow) {
if (daysBackToShow == null) {
_showModifiedAfter = null;
} else {
_showModifiedAfter = moment()
.startOf("day")
.subtract(daysBackToShow, "days")
;
const after = new Date();
after.setHours(0);
after.setMinutes(0);
after.setSeconds(0);
after.setDate(after.getDate()-daysBackToShow);
_showModifiedAfter = after;
}

incidentReportsTable.draw();
Expand Down
16 changes: 10 additions & 6 deletions src/ims/element/static/incidents.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,8 @@ function initDataTables() {
url, "Incident:" + eventID + "#" + incident.number
);
});
$(row).find(".incident_created")
.attr("title", fullDateTime.format(Date.parse(incident.created)));
},
});
}
Expand Down Expand Up @@ -315,12 +317,12 @@ function initSearchField() {

function initSearch() {
function modifiedAfter(incident, timestamp) {
if (timestamp.isBefore(incident.created)) {
if (timestamp < Date.parse(incident.created)) {
return true;
}

for (var i in incident.report_entries) {
if (timestamp.isBefore(incident.report_entries[i].created)) {
if (timestamp < Date.parse(incident.report_entries[i].created)) {
return true;
}
}
Expand Down Expand Up @@ -420,10 +422,12 @@ function showDays(daysBackToShow) {
if (daysBackToShow == null) {
_showModifiedAfter = null;
} else {
_showModifiedAfter = moment()
.startOf("day")
.subtract(daysBackToShow, "days")
;
const after = new Date();
after.setHours(0);
after.setMinutes(0);
after.setSeconds(0);
after.setDate(after.getDate()-daysBackToShow);
_showModifiedAfter = after;
}

incidentsTable.draw();
Expand Down

0 comments on commit 14f2c8c

Please sign in to comment.