diff --git a/code/__DEFINES/{yogs_defines}/telecomms.dm b/code/__DEFINES/{yogs_defines}/telecomms.dm
new file mode 100644
index 000000000000..91c522dd149e
--- /dev/null
+++ b/code/__DEFINES/{yogs_defines}/telecomms.dm
@@ -0,0 +1,2 @@
+#define SERVER_LOG_STORAGE_MAX 400 // Number of chat logs the telecomms servers will store before they start deleting the older ones.
+#define TELECOMMS_SCAN_RANGE 25 // The range at which the telecomms computers can scan for telecomm servers.
\ No newline at end of file
diff --git a/code/game/machinery/telecomms/computers/logbrowser.dm b/code/game/machinery/telecomms/computers/logbrowser.dm
index 94ebf9bbff2a..892ec7c5195d 100644
--- a/code/game/machinery/telecomms/computers/logbrowser.dm
+++ b/code/game/machinery/telecomms/computers/logbrowser.dm
@@ -1,215 +1,117 @@
-
+#define MONITOR_MAINMENU 0
+#define MONITOR_SERVERLOGS 1
/obj/machinery/computer/telecomms/server
name = "telecommunications server monitoring console"
icon_screen = "comm_logs"
- desc = "Has full access to all details and record of the telecommunications network it's monitoring."
+ desc = "A computer dedicated to monitoring telecommuncation server logs."
- var/screen = 0 // the screen number:
- var/list/servers = list() // the servers located by the computer
+ var/screen_state = MONITOR_MAINMENU // the screen state
+ var/list/cached_server_list = list() // The servers located by the computer
var/obj/machinery/telecomms/server/SelectedServer
var/network = "NULL" // the network to probe
- var/temp = "" // temporary feedback messages
- var/universal_translate = 0 // set to 1 if it can translate nonhuman speech
+ var/universal_translate = FALSE // set to TRUE if it can translate nonhuman speech
req_access = list(ACCESS_TCOMSAT)
circuit = /obj/item/circuitboard/computer/comm_server
+ tgui_id = "LogBrowser"
-/obj/machinery/computer/telecomms/server/ui_interact(mob/user)
- . = ..()
- var/dat = "
Telecommunication Server Monitor Telecommunications Server Monitor "
-
- switch(screen)
-
-
- // --- Main Menu ---
-
- if(0)
- dat += " [temp] "
- dat += " Current Network: [network] "
- if(servers.len)
- dat += " Detected Telecommunication Servers:"
- for(var/obj/machinery/telecomms/T in servers)
- dat += "[REF(T)] [T.name] ([T.id]) "
- dat += " "
- dat += "\[Flush Buffer\] "
-
- else
- dat += " No servers detected. Scan for servers: \[Scan\] "
-
-
- // --- Viewing Server ---
-
- if(1)
- dat += " [temp] "
- dat += "\[Main Menu\] \[Refresh\] "
- dat += " Current Network: [network]"
- dat += " Selected Server: [SelectedServer.id]"
-
- if(SelectedServer.totaltraffic >= 1024)
- dat += " Total recorded traffic: [round(SelectedServer.totaltraffic / 1024)] Terrabytes "
- else
- dat += " Total recorded traffic: [SelectedServer.totaltraffic] Gigabytes "
-
- dat += "Stored Logs: "
-
- var/i = 0
- for(var/datum/comm_log_entry/C in SelectedServer.log_entries)
- i++
-
-
- // If the log is a speech file
- if(C.input_type == "Speech File")
- dat += "[C.name] \[X\] "
-
- // -- Determine race of orator --
-
- var/mobtype = C.parameters["mobtype"]
- var/race // The actual race of the mob
-
- if(ispath(mobtype, /mob/living/carbon/human) || ispath(mobtype, /mob/living/brain))
- race = "Humanoid"
-
- // NT knows a lot about slimes, but not aliens. Can identify slimes
- else if(ispath(mobtype, /mob/living/simple_animal/slime))
- race = "Slime"
-
- else if(ispath(mobtype, /mob/living/carbon/monkey))
- race = "Monkey"
-
- // sometimes M gets deleted prematurely for AIs... just check the job
- else if(ispath(mobtype, /mob/living/silicon) || C.parameters["job"] == "AI")
- race = "Artificial Life"
-
- else if(isobj(mobtype))
- race = "Machinery"
-
- else if(ispath(mobtype, /mob/living/simple_animal))
- race = "Domestic Animal"
-
- else
- race = "Unidentifiable "
-
- dat += "Data type : [C.input_type] "
- dat += "Source : [C.parameters["name"]] (Job: [C.parameters["job"]]) "
- dat += "Class : [race] "
- var/message = C.parameters["message"]
- var/language = C.parameters["language"]
-
- // based on [/atom/movable/proc/lang_treat]
- if (universal_translate || user.has_language(language))
- message = "\"[message]\""
- else if (!user.has_language(language))
- var/datum/language/D = GLOB.language_datum_instances[language]
- message = "\"[D.scramble(message)]\""
- else if (language)
- message = "(unintelligible) "
-
- dat += "Contents : [message] "
- dat += " "
-
- else if(C.input_type == "Execution Error")
- dat += "[C.name] \[X\] "
- dat += "Error : \"[C.parameters["message"]]\" "
- dat += " "
-
- else
- dat += "[C.name] \[X\] "
- dat += "Data type : [C.input_type] "
- dat += "Contents : (unintelligible) "
- dat += " "
-
+/obj/machinery/computer/telecomms/server/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user,src,ui)
+ if(!ui)
+ ui = new(user,src,"LogBrowser")
+ ui.open()
- dat += " "
-
- dat += ""
-
- user << browse(dat, "window=comm_monitor;size=575x400")
- onclose(user, "server_control")
-
- temp = ""
- return
-
-
-/obj/machinery/computer/telecomms/server/Topic(href, href_list)
+/obj/machinery/computer/telecomms/server/ui_act(action, list/params)
if(..())
return
-
-
- add_fingerprint(usr)
- usr.set_machine(src)
-
- if(href_list["viewserver"])
- screen = 1
- for(var/obj/machinery/telecomms/T in servers)
- if(T.id == href_list["viewserver"])
- SelectedServer = T
- break
-
- if(href_list["operation"])
- switch(href_list["operation"])
-
- if("release")
- servers = list()
- screen = 0
-
- if("mainmenu")
- screen = 0
-
- if("scan")
- if(servers.len > 0)
- temp = "- FAILED: CANNOT PROBE WHEN BUFFER FULL - "
-
- else
- for(var/obj/machinery/telecomms/server/T in urange(25, src))
- if(T.network == network)
- servers.Add(T)
-
- if(!servers.len)
- temp = "- FAILED: UNABLE TO LOCATE SERVERS IN \[[network]\] - "
- else
- temp = "- [servers.len] SERVERS PROBED & BUFFERED - "
-
- screen = 0
-
- if(href_list["delete"])
-
- if(!src.allowed(usr) && !(obj_flags & EMAGGED))
- to_chat(usr, span_danger("ACCESS DENIED."))
+ switch(action)
+ if("Back")
+ screen_state = MONITOR_MAINMENU
+ SelectedServer = null
+ return TRUE
+ if("ViewServer")
+ var/id = params["server_id"]
+ if(!id)
+ return
+ for(var/machine in cached_server_list)
+ var/obj/machinery/telecomms/server/m = machine
+ if(m.id == id)
+ SelectedServer = m
+ break
+ if(SelectedServer)
+ screen_state = MONITOR_SERVERLOGS
+ return TRUE
return
-
- if(SelectedServer)
-
- var/datum/comm_log_entry/D = SelectedServer.log_entries[text2num(href_list["delete"])]
-
- temp = "- DELETED ENTRY: [D.name] - "
-
- SelectedServer.log_entries.Remove(D)
- qdel(D)
-
- else
- temp = "- FAILED: NO SELECTED MACHINE - "
-
- if(href_list["network"])
-
- var/newnet = stripped_input(usr, "Which network do you want to view?", "Comm Monitor", network)
-
- if(newnet && ((usr in range(1, src)) || issilicon(usr)))
- if(length(newnet) > 15)
- temp = "- FAILED: NETWORK TAG STRING TOO LENGHTLY - "
-
- else
-
- network = newnet
- screen = 0
- servers = list()
- temp = "- NEW NETWORK TAG SET IN ADDRESS \[[network]\] - "
-
- updateUsrDialog()
- return
-
-/obj/machinery/computer/telecomms/server/attackby()
- . = ..()
- updateUsrDialog()
+ if("DeleteLog")
+ if(!SelectedServer)
+ return
+ var/name = params["name"]
+ if(!name || !istext(name) || length(name) > 1024)
+ return
+ for(var/l in SelectedServer.log_entries)
+ var/datum/comm_log_entry/log = l
+ if(log.name == name)
+ SelectedServer.log_entries.Remove(log)
+ return TRUE
+ return
+ if("SetNetwork")
+ var/net = params["network"]
+ if(!net || !istext(net) || isnotpretty(net) || length(net) > 15)
+ return
+ network = params["network"]
+ return TRUE
+ if("Scan")
+ if(cached_server_list.len > 0)
+ cached_server_list = list()
+ for(var/obj/machinery/telecomms/server/T in range(TELECOMMS_SCAN_RANGE, src))
+ if(T.network == network)
+ cached_server_list.Add(T)
+ return TRUE
+ if("Refresh")
+ return TRUE // Welp, you asked for it
+
+/obj/machinery/computer/telecomms/server/proc/generate_message(datum/comm_log_entry/log, mob/user)
+ if(!log.parameters["message"])
+ return "***"
+ var/lang = log.parameters["language"]
+ if(universal_translate || !lang)
+ return log.parameters["message"]
+ if(user.has_language(lang))
+ return log.parameters["message"]
+ else
+ var/datum/language/D = GLOB.language_datum_instances[lang]
+ return D.scramble(log.parameters["message"])
+
+/obj/machinery/computer/telecomms/server/ui_data(mob/user)
+ var/list/data = list()
+ data["screen_state"] = screen_state
+ data["network"] = network
+ if(screen_state == MONITOR_MAINMENU)
+ var/list/servers = list()
+ for(var/machine in cached_server_list)
+ var/obj/machinery/telecomms/server/m = machine
+ servers.Add(m.id)
+ data["servers"] = servers
+ if(screen_state == MONITOR_SERVERLOGS)
+ data["selected_name"] = SelectedServer.id
+ data["totaltraffic"] = SelectedServer.log_entries.len
+ data["define_max_storage"] = SERVER_LOG_STORAGE_MAX
+ data["logs"] = list()
+ for(var/l in SelectedServer.log_entries)
+ var/datum/comm_log_entry/log = l
+ var/list/datalog = list()
+ datalog["is_corrupt"] = (log.input_type == "Corrupt File")
+ datalog["is_error"] = (log.input_type == "Execution Error")
+ datalog["name"] = log.parameters["name"] || "Unknown"
+ datalog["job"] = log.parameters["job"] || FALSE
+ datalog["message"] = generate_message(log,user)
+ datalog["packet_id"] = log.name // since this is some MD5 thing we can actually use this to ID this packet later in ui_act()
+ data["logs"] += list(datalog)
+
+ return data
+
+#undef MONITOR_MAINMENU
+#undef MONITOR_SERVERLOGS
diff --git a/code/game/machinery/telecomms/machines/server.dm b/code/game/machinery/telecomms/machines/server.dm
index 33004ee04952..9a22b11a1d86 100644
--- a/code/game/machinery/telecomms/machines/server.dm
+++ b/code/game/machinery/telecomms/machines/server.dm
@@ -28,7 +28,7 @@
totaltraffic += traffic // add current traffic to total traffic
// Delete particularly old logs
- if (log_entries.len >= 400)
+ if (log_entries.len >= SERVER_LOG_STORAGE_MAX)
log_entries.Cut(1, 2)
signal.data["server"] = src; //Yogs
diff --git a/tgui/packages/tgui/interfaces/LogBrowser.js b/tgui/packages/tgui/interfaces/LogBrowser.js
new file mode 100644
index 000000000000..ab56c803d179
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/LogBrowser.js
@@ -0,0 +1,164 @@
+import { useBackend } from '../backend';
+import { Box, Button, Divider, Section, LabeledList, Icon, NoticeBox, Input, ProgressBar, Tooltip, Flex } from '../components';
+import { Window } from '../layouts';
+
+
+const generate_server_list = (servers, act) => {
+ if (!servers || servers.length === 0)
+ {
+ return (
+
+
+ No Servers stored in Buffer!
+ Please scan for servers to continue.
+
+ );
+ }
+ const mapped_servers = servers.map(server => {
+ return ( act('ViewServer', { 'server_id': server })}>
+ Select Server
+
+ )} />);
+ });
+ return mapped_servers;
+};
+
+const generate_logs = (logs, act) => {
+ if (!logs || logs.length === 0)
+ {
+ return (
+
+
+ No logs detected!
+
+ );
+ }
+ let mapped_logs = [];
+ for (const [index, log] of Object.entries(logs)) {
+ if (log["is_error"])
+ {
+ mapped_logs.push(
+
+ { act('DeleteLog', { "name": log["packet_id"] }); }}>Delete
+
+
+ {log["message"]}
+
+ );
+ }
+ else
+ {
+ if (log["job"])
+ {
+ mapped_logs.push(
+
+
+ { act('DeleteLog', { "name": log["packet_id"] }); }}>Delete {log["packet_id"]}
+
+
+ Name: {log["name"]}
+ Job: {log["job"]}
+ Received Message: {log["message"]}
+
+
+ );
+ continue;
+ }
+ mapped_logs.push(
+
+
+ { act('DeleteLog', { "name": log["packet_id"] }); }}>Delete {log["packet_id"]}
+
+ Name: {log["name"]}
+ Received Message: {log["message"]}
+ { act('DeleteLog', { "name": log["packet_id"] }); }}>Delete
+ );
+ }
+ }
+ return mapped_logs;
+};
+
+export const LogBrowser = (props, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ screen_state,
+ network,
+ //
+ servers,
+ //
+ selected_name,
+ logs,
+ totaltraffic,
+ define_max_storage,
+ } = data;
+
+ if (screen_state === 0) // MAIN MENU
+ {
+ return (
+
+
+
+ Current network: { act('SetNetwork', { "network": value }); }} />
+
+
+ { act('Scan', {}); }}> Scan for Servers
+
+ {generate_server_list(servers, act)}
+
+
+
+ );
+ }
+ else if (screen_state === 1) // SERVER LOGS
+ {
+ return (
+
+
+
+
+ { act('Back', {}); }}> Back
+
+
+
+ { act('Refresh', {}); }}> Refresh
+
+
+
+
+ Network: {network}
+ Server: {selected_name}
+
+ Total Traffic Storage:
+ {totaltraffic} GB
+
+
+
+
+ {generate_logs(logs, act)}
+
+
+
+ );
+ }
+
+};
diff --git a/yogstation.dme b/yogstation.dme
index 1501f965b267..8e8a9d77e75f 100644
--- a/yogstation.dme
+++ b/yogstation.dme
@@ -138,6 +138,7 @@
#include "code\__DEFINES\{yogs_defines}\reactions.dm"
#include "code\__DEFINES\{yogs_defines}\shuttles.dm"
#include "code\__DEFINES\{yogs_defines}\spacepods.dm"
+#include "code\__DEFINES\{yogs_defines}\telecomms.dm"
#include "code\__DEFINES\{yogs_defines}\wires.dm"
#include "code\__HELPERS\_lists.dm"
#include "code\__HELPERS\_logging.dm"