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
@@ -45,8 +45,7 @@ if one is destroyed the second will take over. If all relays are gone it stops w
possible to enable/disable Software Downloading, P2P file transfers and Communication (IC version of IRC, PDA messages for more than two people)
5. Software
Software would almost exclusively use NanoUI modules. Few exceptions are text editor (uses similar screen as TCS IDE used for editing and classic HTML for previewing as Nano looks differently)
and similar programs which for some reason require HTML UI. Most software will be highly dependent on NTNet to work as laptops are not physically connected to the station's network.
Software would almost exclusively use TGUI modules. Most software will be highly dependent on NTNet to work as laptops are not physically connected to the station's network.
What i plan to add:
Note: XXXXDB programs will use ingame_manuals to display basic help for players, similar to how books, etc. do
@@ -416,13 +416,10 @@
/obj/item/modular_computer/proc/update_uis()
if(active_program) //Should we update program ui or computer ui?
SSnanoui.update_uis(active_program)
SStgui.update_uis(src)
if(active_program.NM)
SSnanoui.update_uis(active_program.NM)
if(active_program)
SStgui.update_uis(active_program)
else
SStgui.update_uis(src)
SSnanoui.update_uis(src)
/obj/item/modular_computer/proc/check_update_ui_need()
var/ui_update_needed = FALSE
@@ -458,18 +455,6 @@
if(ui_update_needed)
update_uis()
// Used by camera monitor program
/obj/item/modular_computer/check_eye(var/mob/user)
if(active_program)
return active_program.check_eye(user)
return ..()
// Used by camera monitor program
/obj/item/modular_computer/grants_equipment_vision(var/mob/user)
if(active_program)
return active_program.grants_equipment_vision(user)
return ..()
/obj/item/modular_computer/get_cell()
return battery_module ? battery_module.get_cell() : DEVICE_NO_CELL
@@ -37,9 +37,9 @@
/obj/item/modular_computer/proc/get_header_data(list/data)
LAZYINITLIST(data)
data["PC_batteryicon"] = get_battery_icon()
data["PC_batteryicon"] = battery_module ? get_battery_icon() : null
data["PC_showbatteryicon"] = !!battery_module
data["PC_batterypercent"] = battery_module ? "[round(battery_module.battery.percent())] %" : "N/C"
data["PC_batterypercent"] = battery_module ? "[round(battery_module.battery.percent())] %" : null
data["PC_apclinkicon"] = (tesla_link?.enabled && apc_powered) ? "charging.gif" : ""
data["PC_device_theme"] = active_program ? active_program.tgui_theme : "scc"
data["PC_ntneticon"] = get_ntnet_status_icon()
@@ -206,5 +206,15 @@
return UI_INTERACTIVE
. = ..()
if(. < UI_INTERACTIVE)
if(user.machine)
if(user?.machine)
user.unset_machine()
/obj/item/modular_computer/check_eye(mob/user)
if(active_program)
return active_program.check_eye(user)
return ..()
/obj/item/modular_computer/grants_equipment_vision(mob/user)
if(active_program)
return active_program.grants_equipment_vision(user)
return ..()
@@ -19,6 +19,9 @@
/obj/item/modular_computer/silicon/ui_host()
. = computer_host
/obj/item/modular_computer/silicon/ui_state(mob/user)
return GLOB.self_state
/obj/item/modular_computer/silicon/Initialize(mapload)
if(istype(loc, /mob/living/silicon))
computer_host = loc
@@ -84,11 +84,7 @@ ABSTRACT_TYPE(/datum/computer_file/program)
var/tgui_theme = "scc"
/// If this TGUI should autoupdate or not.
var/ui_auto_update = TRUE
// TO BE DEPRECATED:
var/datum/nano_module/NM // If the program uses NanoModule, put it here and it will be automagically opened. Otherwise implement ui_interact.
var/nanomodule_path // Path to nanomodule, make sure to set this if implementing new program.
var/ui_auto_update = TRUE // Path to nanomodule, make sure to set this if implementing new program.
/datum/computer_file/program/New(obj/item/modular_computer/comp)
..()
@@ -136,7 +132,6 @@ ABSTRACT_TYPE(/datum/computer_file/program)
var/datum/computer_file/program/temp = ..(rename, computer)
temp.required_access_run = required_access_run
temp.required_access_download = required_access_download
temp.nanomodule_path = nanomodule_path
temp.filedesc = filedesc
temp.program_icon_state = program_icon_state
temp.requires_ntnet = requires_ntnet
@@ -200,6 +195,14 @@ ABSTRACT_TYPE(/datum/computer_file/program)
return computer.get_ntnet_status(specific_action)
return FALSE
/// Allows active programs to preserve non-standard user views, such as camera monitors.
/datum/computer_file/program/proc/check_eye(mob/user)
return -1
/// Allows active programs to grant equipment vision while controlling the user's view.
/datum/computer_file/program/proc/grants_equipment_vision(mob/user)
return FALSE
// Called by Process() on device that runs us, once every tick.
/datum/computer_file/program/proc/process_tick()
return TRUE
@@ -307,31 +310,12 @@ ABSTRACT_TYPE(/datum/computer_file/program)
else // Should never happen - So fail silently
return FALSE
// This attempts to retrieve header data for NanoUIs. If implementing completely new device of different type than existing ones
// This attempts to retrieve header data for UIs. If implementing completely new device of different type than existing ones
// always include the device here in this proc. This proc basically relays the request to whatever is running the program.
/datum/computer_file/program/proc/get_header_data()
if(computer)
return computer.get_header_data()
/datum/computer_file/program/Topic(href, href_list)
if(..())
return TRUE
if(computer)
return computer.Topic(href, href_list)
// Relays the call to nano module, if we have one
/datum/computer_file/program/proc/check_eye(var/mob/user)
if(NM)
return NM.check_eye(user)
else
return -1
/// Relays the call to nano module, if we have one
/datum/computer_file/program/proc/grants_equipment_vision(var/mob/user)
if(NM)
return NM.grants_equipment_vision(user)
/datum/computer_file/program/proc/message_dead(var/message)
for(var/mob/M in GLOB.player_list)
if(M.stat == DEAD && (M.client && M.client.prefs.toggles & CHAT_GHOSTEARS))
@@ -5,8 +5,6 @@
// When implementing new program based device, use this to run the program.
/datum/computer_file/program/proc/run_program(var/mob/user)
if(can_run(user, 1) || !requires_access_to_run)
if(nanomodule_path)
NM = new nanomodule_path(src, new /datum/topic_manager/program(src), src)
if(requires_ntnet && network_destination)
generate_network_log("Connection opened to [network_destination].")
program_state = PROGRAM_STATE_ACTIVE
@@ -18,9 +16,6 @@
program_state = PROGRAM_STATE_KILLED
if(network_destination)
generate_network_log("Connection to [network_destination] closed.")
if(NM)
qdel(NM)
NM = null
return TRUE
// Is called when program service is being activated
@@ -1,39 +1,5 @@
/obj/item/modular_computer/initial_data()
/obj/item/modular_computer/proc/initial_data()
return list("_PC" = get_header_data())
/datum/computer_file/program/initial_data()
/datum/computer_file/program/proc/initial_data()
return list("_PC" = get_header_data())
/obj/item/modular_computer/update_layout()
return TRUE
/datum/computer_file/program/update_layout()
return TRUE
/datum/nano_module/program
available_to_ai = FALSE
var/datum/computer_file/program/program // Program-Based computer program that runs this nano module. Defaults to null.
/datum/nano_module/program/New(var/host, var/topic_manager, var/program)
..()
src.program = program
/datum/nano_module/program/Destroy()
program = null
return ..()
/datum/topic_manager/program
var/datum/program
/datum/topic_manager/program/New(var/datum/program)
..()
src.program = program
/datum/topic_manager/program/Destroy()
program = null
return ..()
// Calls forwarded to PROGRAM itself should begin with "PRG_"
// Calls forwarded to COMPUTER running the program should begin with "PC_"
/datum/topic_manager/program/Topic(href, href_list)
return program && program.Topic(href, href_list)
@@ -9,7 +9,6 @@
available_on_ntnet = TRUE
usage_flags = PROGRAM_ALL
tgui_id = "CargoOrder"
ui_auto_update = FALSE
var/page = "main" //main - Main Menu, order - Order Page, item_details - Item Details Page, tracking - Tracking Page
var/selected_category = null // Category that is currently selected
@@ -11,7 +11,6 @@
size = 8
color = LIGHT_COLOR_BLUE
tgui_id = "IDCardModification"
ui_auto_update = FALSE
var/is_centcom = FALSE
var/show_assignments = FALSE
@@ -12,7 +12,6 @@
network_destination = "station long-range communication array"
color = LIGHT_COLOR_BLUE
tgui_id = "CommandCommunications"
ui_auto_update = FALSE
var/datum/comm_message_listener/message_core
var/intercept = FALSE
var/can_call_shuttle = FALSE //If calling the shuttle should be available from this console
@@ -272,7 +271,12 @@ GLOBAL_VAR_INIT(last_message_id, 0)
/datum/comm_message_listener/proc/Add(var/list/message)
messages[++messages.len] = message
/datum/comm_message_listener/proc/Remove(var/list/message)
/datum/comm_message_listener/proc/Remove(var/message)
if(isnum(message))
for(var/list/stored_message in messages)
if(stored_message["id"] == message)
message = stored_message
break
messages -= list(message)
/*
Command action procs
@@ -48,7 +48,7 @@
// Opens the interface for the given air alarm.
if("alarm")
var/obj/structure/machinery/alarm/alarm = locate(params["alarm"]) in (monitored_alarms.len ? monitored_alarms : SSmachinery.processing)
if(alarm)
if(alarm?.rcon_setting)
alarm.ui_interact(usr)
return TRUE
// Manually clear and repopulate the alarm list.
@@ -65,6 +65,8 @@
var/alarms = list()
for(var/obj/structure/machinery/alarm/alarm in monitored_alarms)
if(!alarm.rcon_setting)
continue
alarms += list(list(
"deck" = alarm.alarm_area.horizon_deck,
"dept" = alarm.alarm_area.department,
@@ -77,4 +79,3 @@
data["alarms"] = alarms
return data
@@ -23,7 +23,9 @@
..()
lstate = SSnightlight.is_active() ? "dark" : "full"
/datum/computer_file/program/lighting_control/proc/update_lighting()
/datum/computer_file/program/lighting_control/proc/update_lighting(var/new_context = context, var/new_lstate = lstate)
context = new_context
lstate = new_lstate
// whether to only select areas explicitly marked for nightlighting
var/wl_only = context == "all" ? 0 : 1
@@ -48,7 +50,8 @@
lstate = params["mode"]
. = TRUE
if ("set")
update_lighting()
update_lighting(params["context"] || context, params["mode"] || lstate)
. = TRUE
/datum/computer_file/program/lighting_control/ui_data(mob/user)
var/list/data = initial_data()
@@ -14,7 +14,6 @@
color = LIGHT_COLOR_YELLOW
tgui_id = "RCON"
tgui_theme = "hephaestus"
ui_auto_update = FALSE
/datum/computer_file/program/rcon_console/New()
..()
@@ -162,9 +162,10 @@
return FALSE
set_current(C)
user.set_machine(ui_host())
var/obj/host = ui_host()
if(host)
user.set_machine(host)
user.reset_view(current_camera)
check_eye(user)
if(ishuman(user))
var/mob/living/carbon/human/H = user
@@ -172,6 +173,22 @@
return TRUE
/datum/computer_file/program/camera_monitor/check_eye(mob/user)
if(user.stat || user.blinded)
return -1
if(!current_camera)
return 0
var/viewflag = current_camera.check_eye(user)
if(viewflag < 0)
reset_current()
return viewflag
/datum/computer_file/program/camera_monitor/grants_equipment_vision(mob/user)
if(user.stat || user.blinded || !current_camera)
return FALSE
return current_camera.grants_equipment_vision(user)
/datum/computer_file/program/camera_monitor/proc/set_current(var/obj/structure/machinery/camera/C)
if(current_camera == C)
return
@@ -192,44 +209,14 @@
L.tracking_cancelled()
current_camera = null
/datum/computer_file/program/camera_monitor/check_eye(var/mob/user as mob)
var/obj/item/modular_computer/MC = user.machine
if(istype(MC) && ui_host() == MC)
if(!MC.working || user.blinded || user.stat)
user.unset_machine()
return -1
if(!current_camera)
return 0
var/viewflag = current_camera.check_eye(user)
if ( viewflag < 0 ) //camera doesn't work
reset_current()
return viewflag
/datum/computer_file/program/camera_monitor/grants_equipment_vision(mob/user)
var/obj/item/modular_computer/MC = user.machine
if(istype(MC) && ui_host() == MC)
if(!MC.working || user.blinded || user.stat)
return FALSE
if(!current_camera)
return FALSE
var/viewflag = current_camera.check_eye(user)
if (viewflag < 0) //camera doesn't work
return FALSE
return TRUE
// ERT Variant of the program
/datum/computer_file/program/camera_monitor/ert
filename = "ntcammon"
filedesc = "Advanced Camera Monitoring"
extended_desc = "This program allows remote access to station's camera system. Some camera networks may have additional access requirements. This version has an integrated database with additional encrypted keys."
size = 14
nanomodule_path = /datum/nano_module/camera_monitor/ert
available_on_ntnet = FALSE
/datum/nano_module/camera_monitor/ert
name = "Advanced Camera Monitoring Program"
available_to_ai = FALSE
// The ERT variant has access to ERT and crescent cams, but still checks for accesses. ERT members should be able to use it.
/datum/computer_file/program/camera_monitor/ert/modify_networks_list(var/list/networks)
..()
@@ -242,13 +229,9 @@
filedesc = "Journalism Camera Monitoring"
extended_desc = "This program allows remote access to station's camera system. Some camera networks may have additional access requirements. This version has has a connection to news networks."
size = 2
nanomodule_path = /datum/nano_module/camera_monitor/news
required_access_download = null
usage_flags = PROGRAM_ALL
/datum/nano_module/camera_monitor/news
name = "Journalism Camera Monitoring Program"
/datum/computer_file/program/camera_monitor/news/modify_networks_list(var/list/networks)
networks = list()
networks.Add(list(list("tag" = NETWORK_NEWS, "has_access" = 1)))
@@ -128,7 +128,6 @@
set_current(C)
user.machine = ui_host()
user.reset_view(current_camera)
check_eye(user)
return TRUE
/datum/computer_file/program/penal_mechs/proc/set_current(var/obj/structure/machinery/camera/C)
@@ -150,11 +149,3 @@
if(istype(L))
L.tracking_cancelled()
current_camera = null
/datum/computer_file/program/penal_mechs/check_eye(var/mob/user)
if(!current_camera)
return FALSE
var/viewflag = current_camera.check_eye(user)
if(viewflag < 0) //camera doesn't work
reset_current()
return viewflag
@@ -12,6 +12,7 @@
undeletable = TRUE
tgui_id = "FileManager"
var/open_file
var/open_file_is_usb = FALSE
var/error
/datum/computer_file/program/filemanager/ui_data(mob/user)
@@ -27,7 +28,11 @@
if(!computer || !computer.hard_drive)
data["error"] = "I/O ERROR: Unable to access hard drive."
else
HDD = computer.hard_drive
HDD = open_file_is_usb ? computer.portable_drive : computer.hard_drive
data["file_is_usb"] = open_file_is_usb
if(!HDD)
data["error"] = "I/O ERROR: Unable to open file."
return data
file = HDD.find_file_by_name(open_file)
script = file
if(!istype(file))
@@ -45,6 +50,7 @@
else
data["scriptdata"] = null
data["filedata"] = null
data["file_is_usb"] = FALSE
data["filename"] = null
HDD = computer.hard_drive
RHDD = computer.portable_drive
@@ -85,10 +91,23 @@
return
if(F.can_access_file(usr))
open_file = params["PRG_openfile"]
open_file_is_usb = FALSE
if("PRG_usbopenfile")
. = TRUE
var/obj/item/computer_hardware/hard_drive/RHDD = computer.portable_drive
if(!RHDD)
return
var/datum/computer_file/F = RHDD.find_file_by_name(params["PRG_usbopenfile"])
if(!F)
return
if(F.can_access_file(usr))
open_file = params["PRG_usbopenfile"]
open_file_is_usb = TRUE
if("PRG_newtextfile")
. = TRUE
var/newname = sanitize(input(usr, "Enter file name or leave blank to cancel:", "File rename"))
var/newname = sanitize_filename(tgui_input_text(usr, "Enter file name or leave blank to cancel:", "File rename"))
if(!newname)
return TRUE
var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive
@@ -97,7 +116,9 @@
var/datum/computer_file/data/F = new/datum/computer_file/data()
F.filename = newname
F.filetype = "TXT"
HDD.store_file(F)
if(!HDD.store_file(F))
qdel(F)
error = "I/O ERROR: Unable to create file. The hard drive may be full, read-only, or contain a conflicting file."
if("PRG_deletefile")
. = TRUE
@@ -122,6 +143,7 @@
if("PRG_closefile")
. = TRUE
open_file = null
open_file_is_usb = FALSE
error = null
if("PRG_clone")
@@ -132,8 +154,13 @@
var/datum/computer_file/F = HDD.find_file_by_name(params["PRG_clone"])
if(!F || !istype(F))
return TRUE
if(istype(F, /datum/computer_file/program))
error = "I/O ERROR: Executable programs cannot be cloned from File Manager."
return TRUE
var/datum/computer_file/C = F.clone(1)
HDD.store_file(C)
if(!HDD.store_file(C))
qdel(C)
error = "I/O ERROR: Unable to clone file. The hard drive may be full, read-only, or contain a conflicting file."
if("PRG_rename")
. = TRUE
@@ -143,7 +170,7 @@
var/datum/computer_file/file = HDD.find_file_by_name(params["PRG_rename"])
if(!file || !istype(file))
return TRUE
var/newname = sanitize(input(usr, "Enter new file name:", "File rename", file.filename))
var/newname = sanitize_filename(tgui_input_text(usr, "Enter new file name or leave blank to cancel:", "File rename", file.filename))
if(file && newname)
file.filename = newname
@@ -163,7 +190,7 @@
var/oldtext = html_decode(F.stored_data)
oldtext = replacetext(oldtext, "\[editorbr\]", "\n")
var/newtext = sanitize(replacetext(input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[editorbr\]"), MAX_TEXTFILE_LENGTH)
var/newtext = sanitize_filename(replacetext(tgui_input_text(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", oldtext), "\n", "\[editorbr\]"), MAX_TEXTFILE_LENGTH)
if(!newtext)
return
@@ -185,10 +212,10 @@
return TRUE
var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive
if(!HDD)
return TRUE
return FALSE
if(!computer.nano_printer)
error = "Missing Hardware: Your computer does not have required hardware to complete this operation."
return TRUE
return FALSE
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
var/datum/computer_file/script/S = F
if(!F)
@@ -196,21 +223,21 @@
if(istype(F))
if(!computer.nano_printer.print_text(F.stored_data))
error = "Hardware error: Printer was unable to print the file. It may be out of paper."
return TRUE
return FALSE
else if(istype(S))
if(!computer.nano_printer.print_text(S.code))
error = "Hardware error: Printer was unable to print the file. It may be out of paper."
return TRUE
return FALSE
if("PRG_copytousb")
. = TRUE
var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive
var/obj/item/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive
if(!HDD || !RHDD)
return TRUE
return FALSE
var/datum/computer_file/F = HDD.find_file_by_name(params["PRG_copytousb"])
if(!F || !istype(F))
return TRUE
return FALSE
var/is_usr_tech_support = FALSE
if(ishuman(usr))
var/mob/living/carbon/human/H = usr
@@ -270,7 +297,7 @@
return
if(F.password)
return
F.password = sanitize(input(usr, "Enter an encryption key:", "Encrypt File"))
F.password = sanitize_filename(tgui_input_text(usr, "Enter an encryption key:", "Encrypt File"))
if("PRG_decrypt")
. = TRUE