Bun, Inferno->React migration (#22529)

Re-creation of https://github.com/Aurorastation/Aurora.3/pull/21046 to
skip merge conflict hell. Brings us modern TGUI.

**ALTERNATE TITLE: TGUI HELLSCAPE PR
ABANDON ALL HOPE YE WHO ENTER HERE**

- [x] Migrate build tools (javascript -> typescript, bun for package
management).
- [x] Upgrade all TGUI dependencies and associated root files to
TG-congruent versions (axios, babel, dompurify, eslint, highlight,
marked, prettier, sass, source-map, stacktrace-parser, typescript).
- [x] InfernoJS -> React migrations
- [x] React cleanup and polish (migrate all remaining .js files to
appropriate .ts or .tsx filetype, all remaining hooks, linting, error
corrections, etc.)
- [ ] Test all remaining TGUI interfaces
This commit is contained in:
Batrachophreno
2026-06-05 09:55:22 -04:00
committed by GitHub
parent a52729c105
commit 0d92359da7
930 changed files with 23130 additions and 50520 deletions
@@ -1,241 +0,0 @@
PROCESSING_SUBSYSTEM_DEF(nanoui)
// Subsystem stuff.
name = "NanoUI"
flags = SS_NO_INIT
priority = SS_PRIORITY_NANOUI
stat_tag = "A"
// NanoUI stuff.
var/list/open_nanouis = list()
/**
* Get an open /nanoui ui for the current user, src_object and ui_key and try to update it with data
*
* * user - /mob The mob who opened/owns the ui
* * src_object - /obj|/mob The obj or mob which the ui belongs to
* * ui_key - A string key used for the ui
* * data - List, the data to be passed to the ui, if it exists
* * force_open - Boolean, the ui is being forced to (re)open, so close ui if it exists (instead of updating)
*
* Returns the `/nanoui` found ui, for null if none exists
*/
/datum/controller/subsystem/processing/nanoui/proc/try_update_ui(mob/user, src_object, ui_key, datum/nanoui/ui, data, force_open = FALSE)
if (!ui) // no ui has been passed, so we'll search for one
ui = get_open_ui(user, src_object, ui_key)
if (ui)
// The UI is already open
if (!force_open)
ui.push_data(data)
return ui
else
ui.reinitialise(new_initial_data=data)
return ui
return null
/**
* Get an open /nanoui ui for the current user, src_object and ui_key
*
* * user - The `/mob` who opened/owns the ui
* * src_object - The `/obj` or `/mob` which the ui belongs to
* * ui_key - A string key used for the ui
*/
/datum/controller/subsystem/processing/nanoui/proc/get_open_ui(mob/user, src_object, ui_key)
var/src_object_key = REF(src_object)
if (!LAZYLEN(open_nanouis[src_object_key]) || !LAZYLEN(open_nanouis[src_object_key][ui_key]))
return null
for (var/datum/nanoui/ui in open_nanouis[src_object_key][ui_key])
if (ui.user == user)
return ui
//testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - ui not found")
return null
/**
* Update all `/nanoui` uis attached to src_object
*
* * src_object - The `/obj` or `/mob` which the uis are attached to
*
* Returns the number of UIs updated
*/
/datum/controller/subsystem/processing/nanoui/proc/update_uis(src_object)
var/src_object_key = REF(src_object)
if (!LAZYLEN(open_nanouis[src_object_key]))
return 0
. = 0
var/list/obj_uis = open_nanouis[src_object_key]
for (var/ui_key in obj_uis)
for (var/thing in obj_uis[ui_key])
var/datum/nanoui/ui = thing
if(ui && ui.src_object && ui.user && ui.src_object.ui_host())
ui.process(1)
.++
/**
* Close all `/nanoui` uis attached to src_object
*
* * src_object - The `/obj` or `/mob` which the uis are attached to
*
* Returns the number of UIs closed
*/
/datum/controller/subsystem/processing/nanoui/proc/close_uis(src_object)
var/src_object_key = REF(src_object)
if (!open_nanouis[src_object_key] || !islist(open_nanouis[src_object_key]))
return 0
. = 0
var/list/obj_uis = open_nanouis[src_object_key]
for (var/ui_key in obj_uis)
for (var/thing in obj_uis[ui_key])
var/datum/nanoui/ui = thing
if(ui && ui.src_object && ui.user && ui.src_object.ui_host())
ui.close()
.++
/**
* Update /nanoui uis belonging to user
*
* * user - The `/mob` who owns the uis
* * src_object - An `/obj` or `/mob` that, if is provided, only update uis which are attached to it (optional)
* * ui_key - A string, if ui_key is provided, only update uis with a matching ui_key (optional)
*
* Returns the number of UIs updated
*/
/datum/controller/subsystem/processing/nanoui/proc/update_user_uis(mob/user, src_object, ui_key)
if (!LAZYLEN(user.open_nanouis))
return 0 // has no open uis
. = 0
for (var/thing in user.open_nanouis)
var/datum/nanoui/ui = thing
if (NULL_OR_EQUAL(src_object, ui.src_object) && NULL_OR_EQUAL(ui_key, ui.ui_key))
ui.process(1)
.++
/datum/controller/subsystem/processing/nanoui/proc/close_user_uis(mob/user, src_object, ui_key)
if (!LAZYLEN(user.open_nanouis))
return 0
for (var/thing in user.open_nanouis)
var/datum/nanoui/ui = thing
if (NULL_OR_EQUAL(src_object, ui.src_object) && NULL_OR_EQUAL(ui_key, ui.ui_key))
ui.close()
.++
//testing("nanomanager/close_user_uis mob [user.name] closed [open_nanouis.len] of [.] uis")
/**
* Add a /nanoui ui to the list of open uis
* This is called by the /nanoui open() proc
*
* * ui - The `/nanoui` ui to add
*/
/datum/controller/subsystem/processing/nanoui/proc/ui_opened(datum/nanoui/ui)
var/src_object_key = REF(ui.src_object)
LAZYINITLIST(open_nanouis[src_object_key])
LAZYADD(ui.user.open_nanouis, ui)
LAZYADD(open_nanouis[src_object_key][ui.ui_key], ui)
START_PROCESSING(SSnanoui, ui)
//testing("nanomanager/ui_opened mob [ui.user.name] [ui.src_object:name] [ui.ui_key] - user.open_nanouis [ui.user.open_nanouis.len] | uis [uis.len] | processing_uis [processing_uis.len]")
/**
* Remove a /nanoui ui from the list of open uis
* This is called by the /nanoui close() proc
*
* * ui - A `/nanoui` to remove
*
* Returns FALSE if no ui was removed, TRUE if removed successfully
*/
/datum/controller/subsystem/processing/nanoui/proc/ui_closed(datum/nanoui/ui)
var/src_object_key = REF(ui.src_object)
var/ui_key = ui.ui_key
var/list/obj_uis = open_nanouis[src_object_key]
if (!LAZYLEN(obj_uis) || !obj_uis[ui_key])
return 0 // Wasn't open.
STOP_PROCESSING(SSnanoui, ui)
if(ui.user) // Sanity check in case a user has been deleted (say a blown up borg watching the alarm interface)
LAZYREMOVE(ui.user.open_nanouis, ui)
obj_uis[ui_key] -= ui
if (!LAZYLEN(obj_uis[ui_key]))
obj_uis -= ui_key
if (!LAZYLEN(obj_uis))
open_nanouis -= src_object_key
//testing("nanomanager/ui_closed mob [ui.user.name] [ui.src_object:name] [ui.ui_key] - user.open_nanouis [ui.user.open_nanouis.len] | uis [uis.len] | processing_uis [processing_uis.len]")
return 1
/**
* This is called on user logout
* Closes/clears all uis attached to the user's `/mob`
*
* * user - The user's `/mob`
*/
/datum/controller/subsystem/processing/nanoui/proc/user_logout(mob/user)
return close_user_uis(user)
/**
* This is called when a player transfers from one mob to another
* Transfers all open UIs to the new mob
*
* * oldMob - The user's old `/mob`
* * newMob - The user's new `/mob`
*/
/datum/controller/subsystem/processing/nanoui/proc/user_transferred(mob/oldMob, mob/newMob)
//testing("nanomanager/user_transferred from mob [oldMob.name] to mob [newMob.name]")
if (!oldMob || !LAZYLEN(oldMob.open_nanouis) || !LAZYLEN(open_nanouis))
//testing("nanomanager/user_transferred mob [oldMob.name] has no open uis")
return 0 // has no open uis
for (var/thing in oldMob.open_nanouis)
var/datum/nanoui/ui = thing
ui.user = newMob
LAZYADD(newMob.open_nanouis, ui)
oldMob.open_nanouis = null
return 1 // success
/datum/asset/nanoui
var/list/common = list()
var/list/common_dirs = list(
"nano/css/",
"nano/js/",
"nano/images/",
"nano/images/status_icons/",
"nano/templates/"
)
var/list/uncommon_dirs = list()
/datum/asset/nanoui/register()
// Crawl the directories to find files.
for (var/path in common_dirs)
var/list/filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename)) != "/") // Ignore directories.
if(fexists(path + filename))
common[filename] = fcopy_rsc(path + filename)
SSassets.transport.register_asset(filename, common[filename])
for (var/path in uncommon_dirs)
var/list/filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename)) != "/") // Ignore directories.
if(fexists(path + filename))
SSassets.transport.register_asset(filename, fcopy_rsc(path + filename))
/datum/asset/nanoui/send(client, uncommon)
if(!islist(uncommon))
uncommon = list(uncommon)
SSassets.transport.send_assets(client, uncommon)
SSassets.transport.send_assets(client, common)
@@ -1,369 +0,0 @@
/*!
* Copyright (c) 2020 Aleksej Komarov
* SPDX-License-Identifier: MIT
*/
/**
* tgui subsystem
*
* Contains all tgui state and subsystem code.
*
*/
PROCESSING_SUBSYSTEM_DEF(tgui)
name = "tgui"
wait = 9
flags = SS_NO_INIT
priority = SS_PRIORITY_NANOUI
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
/// A list of UIs scheduled to process
var/list/current_run = list()
/// A list of all open UIs
var/list/all_uis = list()
/// The HTML base used for all UIs.
var/basehtml
/datum/controller/subsystem/processing/tgui/PreInit()
basehtml = file2text('tgui/public/tgui.html')
// Inject inline polyfills
var/polyfill = file2text('tgui/public/tgui-polyfill.min.js')
polyfill = "<script>\n[polyfill]\n</script>"
basehtml = replacetextEx(basehtml, "<!-- tgui:inline-polyfill -->", polyfill)
basehtml = replacetextEx(basehtml, "<!-- tgui:nt-copyright -->", "NanoTrasen © 2457-[text2num(time2text(world.realtime, "YYYY")) + 442]")
basehtml = replacetext(basehtml, "tgui:stylesheet", MAP_STYLESHEET)
/datum/controller/subsystem/processing/tgui/OnConfigLoad()
var/storage_iframe = GLOB.config.storage_cdn_iframe
if(storage_iframe && storage_iframe != /datum/configuration::storage_cdn_iframe)
basehtml = replacetextEx(basehtml, "tgui:storagecdn", storage_iframe)
return
if(GLOB.config.asset_transport == "webroot")
var/datum/asset_transport/webroot/webroot = SSassets.transport
var/datum/asset_cache_item/item = webroot.register_asset("iframe.html", file("tgui/public/iframe.html"))
basehtml = replacetext(basehtml, "tgui:storagecdn", webroot.get_asset_url("iframe.html", item))
return
if(!storage_iframe)
return
basehtml = replacetextEx(basehtml, "tgui:storagecdn", storage_iframe)
/datum/controller/subsystem/processing/tgui/Shutdown()
close_all_uis()
/datum/controller/subsystem/processing/tgui/stat_entry(msg)
msg = "P:[length(all_uis)]"
return ..()
/datum/controller/subsystem/processing/tgui/fire(resumed = FALSE)
CAN_BE_REDEFINED(TRUE)
if(!resumed)
src.current_run = all_uis.Copy()
// Cache for sanic speed (lists are references anyways)
var/list/current_run = src.current_run
var/seconds_per_tick = wait * 0.1
while(current_run.len)
var/datum/tgui/ui = current_run[current_run.len]
current_run.len--
// TODO: Move user/src_object check to process()
if(ui?.user && ui.src_object)
ui.process(seconds_per_tick)
else
ui.close(0)
if(MC_TICK_CHECK)
return
/**
* public
*
* Requests a usable tgui window from the pool.
* Returns null if pool was exhausted.
*
* required user mob
* return datum/tgui
*/
/datum/controller/subsystem/processing/tgui/proc/request_pooled_window(mob/user)
if(!user.client)
return null
var/list/windows = user.client.tgui_windows
var/window_id
var/datum/tgui_window/window
var/window_found = FALSE
// Find a usable window
for(var/i in 1 to TGUI_WINDOW_HARD_LIMIT)
window_id = TGUI_WINDOW_ID(i)
window = windows[window_id]
// As we are looping, create missing window datums
if(!window)
window = new(user.client, window_id, pooled = TRUE)
// Skip windows with acquired locks
if(window.locked)
continue
if(window.status == TGUI_WINDOW_READY)
return window
if(window.status == TGUI_WINDOW_CLOSED)
window.status = TGUI_WINDOW_LOADING
window_found = TRUE
break
if(!window_found)
log_tgui(user, "Error: Pool exhausted",
context = "SStgui/request_pooled_window")
return null
return window
/**
* public
*
* Force closes all tgui windows.
*
* required user mob
*/
/datum/controller/subsystem/processing/tgui/proc/force_close_all_windows(mob/user)
log_tgui(user, context = "SStgui/force_close_all_windows")
if(user.client)
user.client.tgui_windows = list()
for(var/i in 1 to TGUI_WINDOW_HARD_LIMIT)
var/window_id = TGUI_WINDOW_ID(i)
user << browse(null, "window=[window_id]")
/**
* public
*
* Force closes the tgui window by window_id.
*
* required user mob
* required window_id string
*/
/datum/controller/subsystem/processing/tgui/proc/force_close_window(mob/user, window_id)
log_tgui(user, context = "SStgui/force_close_window")
// Close all tgui datums based on window_id.
for(var/datum/tgui/ui in user.tgui_open_uis)
if(ui.window && ui.window.id == window_id)
ui.close(can_be_suspended = FALSE)
// Unset machine just to be sure.
user.unset_machine()
// Close window directly just to be sure.
user << browse(null, "window=[window_id]")
/**
* public
*
* Try to find an instance of a UI, and push an update to it.
*
* required user mob The mob who opened/is using the UI.
* required src_object datum The object/datum which owns the UI.
* optional ui datum/tgui The UI to be updated, if it exists.
* optional force_open bool If the UI should be re-opened instead of updated.
*
* return datum/tgui The found UI.
*/
/datum/controller/subsystem/processing/tgui/proc/try_update_ui(
mob/user,
datum/src_object,
datum/tgui/ui)
// Look up a UI if it wasn't passed
if(isnull(ui))
ui = get_open_ui(user, src_object)
// Couldn't find a UI.
if(isnull(ui))
return null
ui.process_status()
// UI ended up with the closed status
// or is actively trying to close itself.
// FIXME: Doesn't actually fix the paper bug.
if(ui.status <= UI_CLOSE)
ui.close()
return null
ui.send_update()
return ui
/**
* public
*
* Get a open UI given a user and src_object.
*
* required user mob The mob who opened/is using the UI.
* required src_object datum The object/datum which owns the UI.
*
* return datum/tgui The found UI.
*/
/datum/controller/subsystem/processing/tgui/proc/get_open_ui(mob/user, datum/src_object)
if(!LAZYLEN(src_object?.open_uis))
return null
for(var/datum/tgui/ui in src_object.open_uis)
// Make sure we have the right user
if(ui.user == user)
return ui
return null
/**
* public
*
* Update all UIs attached to src_object.
*
* required src_object datum The object/datum which owns the UIs.
*
* return int The number of UIs updated.
*/
/datum/controller/subsystem/processing/tgui/proc/update_uis(datum/src_object)
if(!LAZYLEN(src_object?.open_uis))
return 0
var/count = 0
var/seconds_per_tick = wait * 0.1
for(var/datum/tgui/ui in src_object.open_uis)
// Check if UI is valid.
if(ui?.src_object && ui.user && ui.src_object.ui_host(ui.user))
INVOKE_ASYNC(ui, TYPE_PROC_REF(/datum/tgui, process), seconds_per_tick, TRUE)
count++
return count
/**
* public
*
* Close all UIs attached to src_object.
*
* required src_object datum The object/datum which owns the UIs.
*
* return int The number of UIs closed.
*/
/datum/controller/subsystem/processing/tgui/proc/close_uis(datum/src_object)
// No UIs opened for this src_object
if(!LAZYLEN(src_object?.open_uis))
return 0
var/count = 0
for(var/datum/tgui/ui in src_object.open_uis)
// Check if UI is valid.
if(ui?.src_object && ui.user && ui.src_object.ui_host(ui.user))
ui.close()
count++
return count
/**
* public
*
* Close all UIs regardless of their attachment to src_object.
*
* return int The number of UIs closed.
*/
/datum/controller/subsystem/processing/tgui/proc/close_all_uis()
var/count = 0
for(var/datum/tgui/ui in all_uis)
// Check if UI is valid.
if(ui?.src_object && ui.user && ui.src_object.ui_host(ui.user))
ui.close()
count++
return count
/**
* public
*
* Update all UIs belonging to a user.
*
* required user mob The mob who opened/is using the UI.
* optional src_object datum If provided, only update UIs belonging this src_object.
*
* return int The number of UIs updated.
*/
/datum/controller/subsystem/processing/tgui/proc/update_user_uis(mob/user, datum/src_object)
var/count = 0
if(length(user?.tgui_open_uis) == 0)
return count
var/seconds_per_tick = wait * 0.1
for(var/datum/tgui/ui in user.tgui_open_uis)
if(isnull(src_object) || ui.src_object == src_object)
ui.process(seconds_per_tick, force = 1)
count++
return count
/**
* public
*
* Close all UIs belonging to a user.
*
* required user mob The mob who opened/is using the UI.
* optional src_object datum If provided, only close UIs belonging this src_object.
*
* return int The number of UIs closed.
*/
/datum/controller/subsystem/processing/tgui/proc/close_user_uis(mob/user, datum/src_object)
var/count = 0
if(length(user?.tgui_open_uis) == 0)
return count
for(var/datum/tgui/ui in user.tgui_open_uis)
if(isnull(src_object) || ui.src_object == src_object)
ui.close()
count++
return count
/**
* private
*
* Add a UI to the list of open UIs.
*
* required ui datum/tgui The UI to be added.
*/
/datum/controller/subsystem/processing/tgui/proc/on_open(datum/tgui/ui)
ui.user?.tgui_open_uis |= ui
LAZYOR(ui.src_object.open_uis, ui)
all_uis |= ui
/**
* private
*
* Remove a UI from the list of open UIs.
*
* required ui datum/tgui The UI to be removed.
*
* return bool If the UI was removed or not.
*/
/datum/controller/subsystem/processing/tgui/proc/on_close(datum/tgui/ui)
// Remove it from the list of processing UIs.
all_uis -= ui
current_run -= ui
// If the user exists, remove it from them too.
if(ui.user)
ui.user.tgui_open_uis -= ui
if(ui.src_object)
LAZYREMOVE(ui.src_object.open_uis, ui)
return TRUE
/**
* private
*
* Handle client logout, by closing all their UIs.
*
* required user mob The mob which logged out.
*
* return int The number of UIs closed.
*/
/datum/controller/subsystem/processing/tgui/proc/on_logout(mob/user)
close_user_uis(user)
/**
* private
*
* Handle clients switching mobs, by transferring their UIs.
*
* required user source The client's original mob.
* required user target The client's new mob.
*
* return bool If the UIs were transferred.
*/
/datum/controller/subsystem/processing/tgui/proc/on_transfer(mob/source, mob/target)
// The old mob had no open UIs.
if(length(source?.tgui_open_uis) == 0)
return FALSE
if(isnull(target.tgui_open_uis) || !istype(target.tgui_open_uis, /list))
target.tgui_open_uis = list()
// Transfer all the UIs.
for(var/datum/tgui/ui in source.tgui_open_uis)
// Inform the UIs of their new owner.
ui.user = target
target.tgui_open_uis += ui
// Clear the old list.
source.tgui_open_uis.Cut()
return TRUE