From b40abafb95de36ab0ba625413b03942e318a56d0 Mon Sep 17 00:00:00 2001 From: Harvey Tindall Date: Tue, 27 May 2025 14:20:17 +0100 Subject: [PATCH] list: cleanup, include offset in DateAttempt included UTC offset in minutes in DateAttempt, will be used shortly. Also moved this stuff (ParsedDate, DateAttempt) to the common d.ts, and the method for parsing from a string (now parseDateString) to common. Also pre-emptively load the user cache when the admin page loads. --- ts/modules/accounts.ts | 5 ----- ts/modules/activity.ts | 5 +---- ts/modules/common.ts | 15 +++++++++++++++ ts/modules/list.ts | 6 +++++- ts/modules/search.ts | 35 +++++------------------------------ ts/typings/d.ts | 15 +++++++++++++++ usercache.go | 11 ++++++----- views.go | 7 ++++++- 8 files changed, 53 insertions(+), 46 deletions(-) diff --git a/ts/modules/accounts.ts b/ts/modules/accounts.ts index 0d1a8b7..cbf6209 100644 --- a/ts/modules/accounts.ts +++ b/ts/modules/accounts.ts @@ -7,8 +7,6 @@ import { SearchConfiguration, QueryType, SearchableItem, SearchableItemDataAttri import { HiddenInputField } from "./ui" import { PaginatedList } from "./list" -// FIXME: Find and define a threshold after which searches are no longer performed on input (or just in general by the browser). - declare var window: GlobalWindow; const USER_DEFAULT_SORT_FIELD = "name"; @@ -976,9 +974,6 @@ export class accountsList extends PaginatedList { }); this._populateNumbers(); - // FIXME: Remove! - (window as any).acc = this; - let searchConfig: SearchConfiguration = { filterArea: this._c.filterArea, sortingByButton: this._sortingByButton, diff --git a/ts/modules/activity.ts b/ts/modules/activity.ts index 708199a..94af779 100644 --- a/ts/modules/activity.ts +++ b/ts/modules/activity.ts @@ -533,9 +533,6 @@ export class activityList extends PaginatedList { } }); - // FIXME: Remove! - (window as any).act = this; - this._container = document.getElementById("activity-card-list") document.addEventListener("activity-reload", () => this.reload()); @@ -583,7 +580,7 @@ export class activityList extends PaginatedList { // Setting default sort makes sense, since this is the only sort ever being done. this._c.defaultSortAscending = this.ascending; this._sortDirection.innerHTML = `${window.lang.strings("sortDirection")} `; - // FIXME?: We don't actually re-sort the list here, instead just use setOrdering to apply this.ascending before a reload. + // NOTE: We don't actually re-sort the list here, instead just use setOrdering to apply this.ascending before a reload. this._search.setOrdering(this._search.ordering, this._c.defaultSortField, this.ascending); if (this._hasLoaded) { if (this._search.inServerSearch) { diff --git a/ts/modules/common.ts b/ts/modules/common.ts index e417431..768591f 100644 --- a/ts/modules/common.ts +++ b/ts/modules/common.ts @@ -1,4 +1,5 @@ declare var window: GlobalWindow; +import dateParser from "any-date-parser"; export function toDateString(date: Date): string { const locale = window.language || (window as any).navigator.userLanguage || window.navigator.language; @@ -21,6 +22,20 @@ export function toDateString(date: Date): string { return date.toLocaleDateString(locale, args1) + " " + date.toLocaleString(locale, args2); } +export const parseDateString = (value: string): ParsedDate => { + let out: ParsedDate = { + text: value, + // Used just to tell use what fields the user passed. + attempt: dateParser.attempt(value), + // note Date.fromString is also provided by dateParser. + date: (Date as any).fromString(value) as Date + }; + out.attempt.offsetMinutesFromUTC = out.date.getTimezoneOffset(); + // Month in Date objects is 0-based, so make our parsed date that way too + if ("month" in out.attempt) out.attempt.month -= 1; + return out; +} + export const _get = (url: string, data: Object, onreadystatechange: (req: XMLHttpRequest) => void, noConnectionError: boolean = false): void => { let req = new XMLHttpRequest(); if (window.pages) { url = window.pages.Base + url; } diff --git a/ts/modules/list.ts b/ts/modules/list.ts index 9b0d6a4..4c25366 100644 --- a/ts/modules/list.ts +++ b/ts/modules/list.ts @@ -4,6 +4,10 @@ import "@af-utils/scrollend-polyfill"; declare var window: GlobalWindow; +export interface ListItem { + asElement: () => HTMLElement; +}; + export class RecordCounter { private _container: HTMLElement; private _totalRecords: HTMLElement; @@ -342,7 +346,7 @@ export abstract class PaginatedList { this.lastPage = resp.last_page; appendFunc(resp); - + this._counter.loaded = this._search.ordering.length; if (post) post(resp); diff --git a/ts/modules/search.ts b/ts/modules/search.ts index 3b2a871..8d4d139 100644 --- a/ts/modules/search.ts +++ b/ts/modules/search.ts @@ -1,4 +1,5 @@ -const dateParser = require("any-date-parser"); +import { ListItem } from "./list"; +import { parseDateString } from "./common"; declare var window: GlobalWindow; @@ -176,20 +177,6 @@ export class StringQuery extends Query { } } -export interface DateAttempt { - year?: number; - month?: number; - day?: number; - hour?: number; - minute?: number -} - -export interface ParsedDate { - attempt: DateAttempt; - date: Date; - text: string; -}; - const dateGetters: Map number> = (() => { let m = new Map number>(); m.set("year", Date.prototype.getFullYear); @@ -222,24 +209,15 @@ export class DateQuery extends Query { ${subject.name}: ${dateText != "" ? dateText+" " : ""}${value.text} `; } + public static paramsFromString(valueString: string): [ParsedDate, QueryOperator, boolean] { - // FIXME: Validate this! let op = QueryOperator.Equal; if ((Object.values(QueryOperator) as string[]).includes(valueString.charAt(0))) { op = valueString.charAt(0) as QueryOperator; // Trim the operator from the string valueString = valueString.substring(1); } - - let out: ParsedDate = { - text: valueString, - // Used just to tell use what fields the user passed. - attempt: dateParser.attempt(valueString), - // note Date.fromString is also provided by dateParser. - date: (Date as any).fromString(valueString) as Date - }; - // Month in Date objects is 0-based, so make our parsed date that way too - if ("month" in out.attempt) out.attempt.month -= 1; + let out = parseDateString(valueString); let isValid = true; if ("invalid" in (out.date as any)) { isValid = false; }; @@ -278,10 +256,8 @@ export class DateQuery extends Query { } } -export interface SearchableItem { +export interface SearchableItem extends ListItem { matchesSearch: (query: string) => boolean; - // FIXME: SearchableItem should really be ListItem or something, this isn't for search! - asElement: () => HTMLElement; } export const SearchableItemDataAttribute = "data-search-item"; @@ -598,7 +574,6 @@ export class Search { this._c.search.oninput(null as any); }; - // FIXME: Make XQuery classes less specifically for in-progress searches, and include this code for making info button things. generateFilterList = () => { // Generate filter buttons for (let queryName of Object.keys(this._c.queries)) { diff --git a/ts/typings/d.ts b/ts/typings/d.ts index a1df5c8..e3c5a3c 100644 --- a/ts/typings/d.ts +++ b/ts/typings/d.ts @@ -161,5 +161,20 @@ interface PaginatedReqDTO { ascending: boolean; }; +interface DateAttempt { + year?: number; + month?: number; + day?: number; + hour?: number; + minute?: number; + offsetMinutesFromUTC?: number; +} + +interface ParsedDate { + attempt: DateAttempt; + date: Date; + text: string; +}; + declare var config: Object; declare var modifiedConfig: Object; diff --git a/usercache.go b/usercache.go index 07e6868..b26be92 100644 --- a/usercache.go +++ b/usercache.go @@ -235,11 +235,12 @@ const ( }*/ type DateAttempt struct { - Year *int `json:"year,omitempty"` - Month *int `json:"month,omitempty"` - Day *int `json:"day,omitempty"` - Hour *int `json:"hour,omitempty"` - Minute *int `json:"minute,omitempty"` + Year *int `json:"year,omitempty"` + Month *int `json:"month,omitempty"` + Day *int `json:"day,omitempty"` + Hour *int `json:"hour,omitempty"` + Minute *int `json:"minute,omitempty"` + OffsetMinutesFromUTC *int `json:"offsetMinutesFromUTC,omitempty"` } // Compare roughly compares a time.Time to a DateAttempt. diff --git a/views.go b/views.go index be574b4..c13191f 100644 --- a/views.go +++ b/views.go @@ -67,9 +67,10 @@ func (app *appContext) pushResources(gc *gin.Context, page Page) { default: toPush = []string{} } + urlBase := app.getURLBase(gc) if pusher := gc.Writer.Pusher(); pusher != nil { for _, f := range toPush { - if err := pusher.Push(PAGES.Base+f, nil); err != nil { + if err := pusher.Push(urlBase+f, nil); err != nil { app.debug.Printf(lm.FailedServerPush, err) } } @@ -172,6 +173,10 @@ func (app *appContext) getLang(gc *gin.Context, page Page, chosen string) string func (app *appContext) AdminPage(gc *gin.Context) { app.pushResources(gc, AdminPage) + + // Pre-emptively (maybe) generate user cache + go app.userCache.MaybeSync(app) + lang := app.getLang(gc, AdminPage, app.storage.lang.chosenAdminLang) jfAdminOnly := app.config.Section("ui").Key("admin_only").MustBool(true) jfAllowAll := app.config.Section("ui").Key("allow_all").MustBool(false)