From 8f8ccd41d3f3bc93eab4ea397bf2f8070c680e89 Mon Sep 17 00:00:00 2001 From: Gabriel Adamson Date: Thu, 19 Aug 2021 09:15:38 -0500 Subject: [PATCH 01/24] Start porting admin ticket panel to TGUI --- code/modules/admin/verbs/adminhelp.dm | 697 ------------------ code/modules/tgui/states/holder.dm | 6 + .../tgui/interfaces/TicketListPanel.js | 22 + yogstation.dme | 1 + .../code/modules/admin/verbs/adminhelp.dm | 5 +- .../code/modules/admin/verbs/ticketpanel.dm | 29 + yogstation/interface/interface.dm | 12 +- 7 files changed, 67 insertions(+), 705 deletions(-) delete mode 100644 code/modules/admin/verbs/adminhelp.dm create mode 100644 code/modules/tgui/states/holder.dm create mode 100644 tgui/packages/tgui/interfaces/TicketListPanel.js create mode 100644 yogstation/code/modules/admin/verbs/ticketpanel.dm diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm deleted file mode 100644 index edf1f76ec4b0..000000000000 --- a/code/modules/admin/verbs/adminhelp.dm +++ /dev/null @@ -1,697 +0,0 @@ -// yogs - This file is mirrored to yogstation/modules/admin -/client/var/adminhelptimerid = 0 //a timer id for returning the ahelp verb -/client/var/datum/admin_help/current_ticket //the current ticket the (usually) not-admin client is dealing with - -// -//TICKET MANAGER -// - -GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) - -/datum/admin_help_tickets - var/list/active_tickets = list() - var/list/closed_tickets = list() - var/list/resolved_tickets = list() - - var/obj/effect/statclick/ticket_list/astatclick = new(null, null, AHELP_ACTIVE) - var/obj/effect/statclick/ticket_list/cstatclick = new(null, null, AHELP_CLOSED) - var/obj/effect/statclick/ticket_list/rstatclick = new(null, null, AHELP_RESOLVED) - -/datum/admin_help_tickets/Destroy() - QDEL_LIST(active_tickets) - QDEL_LIST(closed_tickets) - QDEL_LIST(resolved_tickets) - QDEL_NULL(astatclick) - QDEL_NULL(cstatclick) - QDEL_NULL(rstatclick) - return ..() - -/datum/admin_help_tickets/proc/TicketByID(id) - var/list/lists = list(active_tickets, closed_tickets, resolved_tickets) - for(var/I in lists) - for(var/J in I) - var/datum/admin_help/AH = J - if(AH.id == id) - return J - -/datum/admin_help_tickets/proc/TicketsByCKey(ckey) - . = list() - var/list/lists = list(active_tickets, closed_tickets, resolved_tickets) - for(var/I in lists) - for(var/J in I) - var/datum/admin_help/AH = J - if(AH.initiator_ckey == ckey) - . += AH - -//private -/datum/admin_help_tickets/proc/ListInsert(datum/admin_help/new_ticket) - var/list/ticket_list - switch(new_ticket.state) - if(AHELP_ACTIVE) - ticket_list = active_tickets - if(AHELP_CLOSED) - ticket_list = closed_tickets - if(AHELP_RESOLVED) - ticket_list = resolved_tickets - else - CRASH("Invalid ticket state: [new_ticket.state]") - var/num_closed = ticket_list.len - if(num_closed) - for(var/I in 1 to num_closed) - var/datum/admin_help/AH = ticket_list[I] - if(AH.id > new_ticket.id) - ticket_list.Insert(I, new_ticket) - return - ticket_list += new_ticket - -//opens the ticket listings for one of the 3 states -/datum/admin_help_tickets/proc/BrowseTickets(state) - var/list/l2b - var/title - switch(state) - if(AHELP_ACTIVE) - l2b = active_tickets - title = "Active Tickets" - if(AHELP_CLOSED) - l2b = closed_tickets - title = "Closed Tickets" - if(AHELP_RESOLVED) - l2b = resolved_tickets - title = "Resolved Tickets" - if(!l2b) - return - var/list/dat = list("[title]") - dat += "Refresh

" - for(var/I in l2b) - var/datum/admin_help/AH = I - dat += "Ticket #[AH.id]: [AH.initiator_key_name]: [AH.name]
" - - usr << browse(dat.Join(), "window=ahelp_list[state];size=600x480") - -//Tickets statpanel -/datum/admin_help_tickets/proc/stat_entry() - SHOULD_CALL_PARENT(TRUE) - SHOULD_NOT_SLEEP(TRUE) - var/list/L = list() - var/num_disconnected = 0 - L[++L.len] = list("Active Tickets:", "[astatclick.update("[active_tickets.len]")]", null, REF(astatclick)) - astatclick.update("[active_tickets.len]") - for(var/I in active_tickets) - var/datum/admin_help/AH = I - if(AH.initiator) - L[++L.len] = list("#[AH.id]. [AH.initiator_key_name]:", "[AH.statclick.update()]", REF(AH)) - else - ++num_disconnected - if(num_disconnected) - L[++L.len] = list("Disconnected:", "[astatclick.update("[num_disconnected]")]", null, REF(astatclick)) - L[++L.len] = list("Closed Tickets:", "[cstatclick.update("[closed_tickets.len]")]", null, REF(cstatclick)) - L[++L.len] = list("Resolved Tickets:", "[rstatclick.update("[resolved_tickets.len]")]", null, REF(rstatclick)) - return L - -//Reassociate still open ticket if one exists -/datum/admin_help_tickets/proc/ClientLogin(client/C) - C.current_ticket = CKey2ActiveTicket(C.ckey) - if(C.current_ticket) - C.current_ticket.initiator = C - C.current_ticket.AddInteraction("Client reconnected.") - -//Dissasociate ticket -/datum/admin_help_tickets/proc/ClientLogout(client/C) - if(C.current_ticket) - C.current_ticket.AddInteraction("Client disconnected.") - C.current_ticket.initiator = null - C.current_ticket = null - -//Get a ticket given a ckey -/datum/admin_help_tickets/proc/CKey2ActiveTicket(ckey) - for(var/I in active_tickets) - var/datum/admin_help/AH = I - if(AH.initiator_ckey == ckey) - return AH - -// -//TICKET LIST STATCLICK -// - -/obj/effect/statclick/ticket_list - var/current_state - -/obj/effect/statclick/ticket_list/New(loc, name, state) - current_state = state - ..() - -/obj/effect/statclick/ticket_list/Click() - GLOB.ahelp_tickets.BrowseTickets(current_state) - -//called by admin topic -/obj/effect/statclick/ticket_list/proc/Action() - Click() - -// -//TICKET DATUM -// - -/datum/admin_help - var/id - var/name - var/state = AHELP_ACTIVE - - var/opened_at - var/closed_at - - var/client/initiator //semi-misnomer, it's the person who ahelped/was bwoinked - var/initiator_ckey - var/initiator_key_name - var/heard_by_no_admins = FALSE - - var/list/_interactions //use AddInteraction() or, preferably, admin_ticket_log() - - var/obj/effect/statclick/ahelp/statclick - - var/static/ticket_counter = 0 - -//call this on its own to create a ticket, don't manually assign current_ticket -//msg is the title of the ticket: usually the ahelp text -//is_bwoink is TRUE if this ticket was started by an admin PM -/datum/admin_help/New(msg, client/C, is_bwoink) - //clean the input msg - msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN)) - if(!msg || !C || !C.mob) - qdel(src) - return - - id = ++ticket_counter - opened_at = world.time - - name = msg - - initiator = C - initiator_ckey = initiator.ckey - initiator_key_name = key_name(initiator, FALSE, TRUE) - if(initiator.current_ticket) //This is a bug - stack_trace("Multiple ahelp current_tickets") - initiator.current_ticket.AddInteraction("Ticket erroneously left open by code") - initiator.current_ticket.Close() - initiator.current_ticket = src - - TimeoutVerb() - - statclick = new(null, src) - _interactions = list() - - if(is_bwoink) - AddInteraction("[usr.client.ckey] PM'd [initiator.ckey]") - message_admins("Ticket [TicketHref("#[id]")] created") - else - MessageNoRecipient(msg) - - //send it to irc if nobody is on and tell us how many were on - var/admin_number_present = send2irc_adminless_only(initiator_ckey, "Ticket #[id]: [name]") - log_admin_private("Ticket #[id]: [key_name(initiator)]: [name] - heard by [admin_number_present] non-AFK admins who have +BAN.") - if(admin_number_present <= 0) - to_chat(C, "No active admins are online, your adminhelp was sent to the admin irc.", confidential=TRUE) - heard_by_no_admins = TRUE - - GLOB.ahelp_tickets.active_tickets += src - -/datum/admin_help/Destroy() - RemoveActive() - GLOB.ahelp_tickets.closed_tickets -= src - GLOB.ahelp_tickets.resolved_tickets -= src - return ..() - -/datum/admin_help/proc/AddInteraction(formatted_message) - if(heard_by_no_admins && usr && usr.ckey != initiator_ckey) - heard_by_no_admins = FALSE - send2irc(initiator_ckey, "Ticket #[id]: Answered by [key_name(usr)]") - _interactions += "[time_stamp()]: [formatted_message]" - -//Removes the ahelp verb and returns it after 2 minutes -/datum/admin_help/proc/TimeoutVerb() - remove_verb(initiator, /client/verb/adminhelp) - initiator.adminhelptimerid = addtimer(CALLBACK(initiator, /client/proc/giveadminhelpverb), 1200, TIMER_STOPPABLE) //2 minute cooldown of admin helps - -//private -/datum/admin_help/proc/FullMonty(ref_src) - if(!ref_src) - ref_src = "[REF(src)]" - . = ADMIN_FULLMONTY_NONAME(initiator.mob) - if(state == AHELP_ACTIVE) - . += ClosureLinks(ref_src) - -//private -/datum/admin_help/proc/ClosureLinks(ref_src) - if(!ref_src) - ref_src = "[REF(src)]" - . = " (REJT)" - . += " (IC)" - . += " (CLOSE)" - . += " (RSLVE)" - -//private -/datum/admin_help/proc/LinkedReplyName(ref_src) - if(!ref_src) - ref_src = "[REF(src)]" - return "[initiator_key_name]" - -//private -/datum/admin_help/proc/TicketHref(msg, ref_src, action = "ticket") - if(!ref_src) - ref_src = "[REF(src)]" - return "[msg]" - -//message from the initiator without a target, all admins will see this -//won't bug irc -/datum/admin_help/proc/MessageNoRecipient(msg) - msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN)) - var/ref_src = "[REF(src)]" - //Message to be sent to all admins - var/admin_msg = "Ticket [TicketHref("#[id]", ref_src)]: [LinkedReplyName(ref_src)] [FullMonty(ref_src)]: [keywords_lookup(msg)]" - - AddInteraction("[LinkedReplyName(ref_src)]: [msg]") - log_admin_private("Ticket #[id]: [key_name(initiator)]: [msg]") - - //send this msg to all admins - for(var/client/X in GLOB.admins) - if(X.prefs.toggles & SOUND_ADMINHELP) - SEND_SOUND(X, sound('sound/effects/adminhelp.ogg')) - window_flash(X, ignorepref = TRUE) - to_chat(X, - type = MESSAGE_TYPE_ADMINPM, - html = admin_msg, - confidential = TRUE) - - //show it to the person adminhelping too - to_chat(initiator, - type = MESSAGE_TYPE_ADMINPM, - html = "PM to-Admins: [msg]", - confidential = TRUE) - -//Reopen a closed ticket -/datum/admin_help/proc/Reopen() - if(state == AHELP_ACTIVE) - to_chat(usr, "This ticket is already open.", confidential=TRUE) - return - - if(GLOB.ahelp_tickets.CKey2ActiveTicket(initiator_ckey)) - to_chat(usr, "This user already has an active ticket, cannot reopen this one.", confidential=TRUE) - return - - statclick = new(null, src) - GLOB.ahelp_tickets.active_tickets += src - GLOB.ahelp_tickets.closed_tickets -= src - GLOB.ahelp_tickets.resolved_tickets -= src - switch(state) - if(AHELP_CLOSED) - SSblackbox.record_feedback("tally", "ahelp_stats", -1, "closed") - if(AHELP_RESOLVED) - SSblackbox.record_feedback("tally", "ahelp_stats", -1, "resolved") - state = AHELP_ACTIVE - closed_at = null - if(initiator) - initiator.current_ticket = src - - AddInteraction("Reopened by [key_name_admin(usr)]") - var/msg = "Ticket [TicketHref("#[id]")] reopened by [key_name_admin(usr)]." - message_admins(msg) - log_admin_private(msg) - SSblackbox.record_feedback("tally", "ahelp_stats", 1, "reopened") - TicketPanel() //can only be done from here, so refresh it - -//private -/datum/admin_help/proc/RemoveActive() - if(state != AHELP_ACTIVE) - return - closed_at = world.time - QDEL_NULL(statclick) - GLOB.ahelp_tickets.active_tickets -= src - if(initiator && initiator.current_ticket == src) - initiator.current_ticket = null - -//Mark open ticket as closed/meme -/datum/admin_help/proc/Close(key_name = key_name_admin(usr), silent = FALSE) - if(state != AHELP_ACTIVE) - return - RemoveActive() - state = AHELP_CLOSED - GLOB.ahelp_tickets.ListInsert(src) - AddInteraction("Closed by [key_name].") - if(!silent) - SSblackbox.record_feedback("tally", "ahelp_stats", 1, "closed") - var/msg = "Ticket [TicketHref("#[id]")] closed by [key_name]." - message_admins(msg) - log_admin_private(msg) - -//Mark open ticket as resolved/legitimate, returns ahelp verb -/datum/admin_help/proc/Resolve(key_name = key_name_admin(usr), silent = FALSE) - if(state != AHELP_ACTIVE) - return - RemoveActive() - state = AHELP_RESOLVED - GLOB.ahelp_tickets.ListInsert(src) - - addtimer(CALLBACK(initiator, /client/proc/giveadminhelpverb), 50) - - AddInteraction("Resolved by [key_name].") - to_chat(initiator, "Your ticket has been resolved by an admin. The Adminhelp verb will be returned to you shortly.", confidential=TRUE) - if(!silent) - SSblackbox.record_feedback("tally", "ahelp_stats", 1, "resolved") - var/msg = "Ticket [TicketHref("#[id]")] resolved by [key_name]" - message_admins(msg) - log_admin_private(msg) - -//Close and return ahelp verb, use if ticket is incoherent -/datum/admin_help/proc/Reject(key_name = key_name_admin(usr)) - if(state != AHELP_ACTIVE) - return - - if(initiator) - initiator.giveadminhelpverb() - - SEND_SOUND(initiator, sound('sound/effects/adminhelp.ogg')) - - to_chat(initiator, "- AdminHelp Rejected! -", confidential=TRUE) - to_chat(initiator, "Your admin help was rejected. The adminhelp verb has been returned to you so that you may try again.", confidential=TRUE) - to_chat(initiator, "Please try to be calm, clear, and descriptive in admin helps, do not assume the admin has seen any related events, and clearly state the names of anybody you are reporting.", confidential=TRUE) - - SSblackbox.record_feedback("tally", "ahelp_stats", 1, "rejected") - var/msg = "Ticket [TicketHref("#[id]")] rejected by [key_name]" - message_admins(msg) - log_admin_private(msg) - AddInteraction("Rejected by [key_name].") - Close(silent = TRUE) - -//Resolve ticket with IC Issue message -/datum/admin_help/proc/ICIssue(key_name = key_name_admin(usr)) - if(state != AHELP_ACTIVE) - return - - var/msg = "- AdminHelp marked as IC issue! -
" - msg += "Your issue has been determined by an administrator to be an in character issue and does NOT require administrator intervention at this time. For further resolution you should pursue options that are in character." - - if(initiator) - to_chat(initiator, msg, confidential=TRUE) - - SSblackbox.record_feedback("tally", "ahelp_stats", 1, "IC") - msg = "Ticket [TicketHref("#[id]")] marked as IC by [key_name]" - message_admins(msg) - log_admin_private(msg) - AddInteraction("Marked as IC issue by [key_name]") - Resolve(silent = TRUE) - -//Show the ticket panel -/datum/admin_help/proc/TicketPanel() - var/list/dat = list("Ticket #[id]") - var/ref_src = "[REF(src)]" - dat += "

Admin Help Ticket #[id]: [LinkedReplyName(ref_src)]

" - dat += "State: " - switch(state) - if(AHELP_ACTIVE) - dat += "OPEN" - if(AHELP_RESOLVED) - dat += "RESOLVED" - if(AHELP_CLOSED) - dat += "CLOSED" - else - dat += "UNKNOWN" - dat += "[GLOB.TAB][TicketHref("Refresh", ref_src)][GLOB.TAB][TicketHref("Re-Title", ref_src, "retitle")]" - if(state != AHELP_ACTIVE) - dat += "[GLOB.TAB][TicketHref("Reopen", ref_src, "reopen")]" - dat += "

Opened at: [gameTimestamp(wtime = opened_at)] (Approx [DisplayTimeText(world.time - opened_at)] ago)" - if(closed_at) - dat += "
Closed at: [gameTimestamp(wtime = closed_at)] (Approx [DisplayTimeText(world.time - closed_at)] ago)" - dat += "

" - if(initiator) - dat += "Actions: [FullMonty(ref_src)]
" - else - dat += "DISCONNECTED[GLOB.TAB][ClosureLinks(ref_src)]
" - dat += "
Log:

" - for(var/I in _interactions) - dat += "[I]
" - - usr << browse(dat.Join(), "window=ahelp[id];size=620x480") - -/datum/admin_help/proc/Retitle() - var/new_title = input(usr, "Enter a title for the ticket", "Rename Ticket", name) as text|null - if(new_title) - name = new_title - //not saying the original name cause it could be a long ass message - var/msg = "Ticket [TicketHref("#[id]")] titled [name] by [key_name_admin(usr)]" - message_admins(msg) - log_admin_private(msg) - TicketPanel() //we have to be here to do this - -//Forwarded action from admin/Topic -/datum/admin_help/proc/Action(action) - testing("Ahelp action: [action]") - switch(action) - if("ticket") - TicketPanel() - if("retitle") - Retitle() - if("reject") - Reject() - if("reply") - usr.client.cmd_ahelp_reply(initiator) - if("icissue") - ICIssue() - if("close") - Close() - if("resolve") - Resolve() - if("reopen") - Reopen() - -// -// TICKET STATCLICK -// - -/obj/effect/statclick/ahelp - var/datum/admin_help/ahelp_datum - -/obj/effect/statclick/ahelp/Initialize(mapload, datum/admin_help/AH) - ahelp_datum = AH - . = ..() - -/obj/effect/statclick/ahelp/update() - return ..(ahelp_datum.name) - -/obj/effect/statclick/ahelp/Click() - ahelp_datum.TicketPanel() - -/obj/effect/statclick/ahelp/Destroy() - ahelp_datum = null - return ..() - -// -// CLIENT PROCS -// - -/client/proc/giveadminhelpverb() - add_verb(src, /client/verb/adminhelp) - deltimer(adminhelptimerid) - adminhelptimerid = 0 - -// Used for methods where input via arg doesn't work -/client/proc/get_adminhelp() - var/msg = input(src, "Please describe your problem concisely and an admin will help as soon as they're able.", "Adminhelp contents") as text|null - adminhelp(msg) - -/client/verb/adminhelp(msg as text) - set category = "Admin" - set name = "Adminhelp" - - if(GLOB.say_disabled) //This is here to try to identify lag problems - to_chat(usr, "Speech is currently admin-disabled.", confidential=TRUE) - return - - //handle muting and automuting - if(prefs.muted & MUTE_ADMINHELP) - to_chat(src, "Error: Admin-PM: You cannot send adminhelps (Muted).", confidential=TRUE) - return - if(handle_spam_prevention(msg,MUTE_ADMINHELP)) - return - - msg = trim(msg) - - if(!msg) - return - - SSblackbox.record_feedback("tally", "admin_verb", 1, "Adminhelp") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - if(current_ticket) - if(alert(usr, "You already have a ticket open. Is this for the same issue?",,"Yes","No") != "No") - if(current_ticket) - current_ticket.MessageNoRecipient(msg) - current_ticket.TimeoutVerb() - return - else - to_chat(usr, "Ticket not found, creating new one...", confidential=TRUE) - else - current_ticket.AddInteraction("[key_name_admin(usr)] opened a new ticket.") - current_ticket.Close() - - new /datum/admin_help(msg, src, FALSE) - -// -// LOGGING -// - -//Use this proc when an admin takes action that may be related to an open ticket on what -//what can be a client, ckey, or mob -/proc/admin_ticket_log(what, message) - var/client/C - var/mob/Mob = what - if(istype(Mob)) - C = Mob.client - else - C = what - if(istype(C) && C.current_ticket) - C.current_ticket.AddInteraction(message) - return C.current_ticket - if(istext(what)) //ckey - var/datum/admin_help/AH = GLOB.ahelp_tickets.CKey2ActiveTicket(what) - if(AH) - AH.AddInteraction(message) - return AH - -// -// HELPER PROCS -// - -/proc/get_admin_counts(requiredflags = R_BAN) - . = list("total" = list(), "noflags" = list(), "afk" = list(), "stealth" = list(), "present" = list()) - for(var/client/X in GLOB.admins) - .["total"] += X - if(requiredflags != 0 && !check_rights_for(X, requiredflags)) - .["noflags"] += X - else if(X.is_afk()) - .["afk"] += X - else if(X.holder.fakekey) - .["stealth"] += X - else - .["present"] += X - -/proc/send2irc_adminless_only(source, msg, requiredflags = R_BAN) - var/list/adm = get_admin_counts(requiredflags) - var/list/activemins = adm["present"] - . = activemins.len - if(. <= 0) - var/final = "" - var/list/afkmins = adm["afk"] - var/list/stealthmins = adm["stealth"] - var/list/powerlessmins = adm["noflags"] - var/list/allmins = adm["total"] - if(!afkmins.len && !stealthmins.len && !powerlessmins.len) - final = "[msg] - No admins online" - else - final = "[msg] - All admins stealthed\[[english_list(stealthmins)]\], AFK\[[english_list(afkmins)]\], or lacks +BAN\[[english_list(powerlessmins)]\]! Total: [allmins.len] " - send2irc(source,final) - send2otherserver(source,final) - - -/proc/send2irc(msg,msg2) - msg = replacetext(replacetext(msg, "\proper", ""), "\improper", "") - msg2 = replacetext(replacetext(msg2, "\proper", ""), "\improper", "") - world.TgsTargetedChatBroadcast("[msg] | [msg2]", TRUE) - -/proc/send2otherserver(source,msg,type = "Ahelp") - var/comms_key = CONFIG_GET(string/comms_key) - if(!comms_key) - return - var/list/message = list() - message["message_sender"] = source - message["message"] = msg - message["source"] = "([CONFIG_GET(string/cross_comms_name)])" - message["key"] = comms_key - message += type - - var/list/servers = CONFIG_GET(keyed_list/cross_server) - for(var/I in servers) - world.Export("[servers[I]]?[list2params(message)]") - - -/proc/ircadminwho() - var/list/message = list("Admins: ") - var/list/admin_keys = list() - for(var/adm in GLOB.admins) - var/client/C = adm - admin_keys += "[C][C.holder.fakekey ? "(Stealth)" : ""][C.is_afk() ? "(AFK)" : ""]" - - for(var/admin in admin_keys) - if(LAZYLEN(message) > 1) - message += ", [admin]" - else - message += "[admin]" - - return jointext(message, "") - -/proc/keywords_lookup(msg,irc) - - //This is a list of words which are ignored by the parser when comparing message contents for names. MUST BE IN LOWER CASE! - var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","alien","as", "i") - - //explode the input msg into a list - var/list/msglist = splittext(msg, " ") - - //generate keywords lookup - var/list/surnames = list() - var/list/forenames = list() - var/list/ckeys = list() - var/founds = "" - for(var/mob/M in GLOB.mob_list) - var/list/indexing = list(M.real_name, M.name) - if(M.mind) - indexing += M.mind.name - - for(var/string in indexing) - var/list/L = splittext(string, " ") - var/surname_found = 0 - //surnames - for(var/i=L.len, i>=1, i--) - var/word = ckey(L[i]) - if(word) - surnames[word] = M - surname_found = i - break - //forenames - for(var/i=1, i(?|F) " - continue - msg += "[original_word] " - if(irc) - if(founds == "") - return "Search Failed" - else - return founds - - return msg diff --git a/code/modules/tgui/states/holder.dm b/code/modules/tgui/states/holder.dm new file mode 100644 index 000000000000..667068d07054 --- /dev/null +++ b/code/modules/tgui/states/holder.dm @@ -0,0 +1,6 @@ +GLOBAL_DATUM_INIT(holder_state, /datum/ui_state/holder_state, new) + +/datum/ui_state/holder_state/can_use_topic(src_object, mob/user) + if(user.client && user.client.holder) + return UI_INTERACTIVE + return UI_CLOSE diff --git a/tgui/packages/tgui/interfaces/TicketListPanel.js b/tgui/packages/tgui/interfaces/TicketListPanel.js new file mode 100644 index 000000000000..51a8a917fd29 --- /dev/null +++ b/tgui/packages/tgui/interfaces/TicketListPanel.js @@ -0,0 +1,22 @@ + +import { useBackend } from '../backend'; +import { Section, Collapsible, Button } from '../components'; +import { Window } from '../layouts'; + +export const DisconnectPanel = (props, context) => { + const { act, data } = useBackend(context); + + return ( + + +
+ Hello +
+
+
+ ); +}; diff --git a/yogstation.dme b/yogstation.dme index c1367aba2a16..7713ce8fdb7b 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -3026,6 +3026,7 @@ #include "code\modules\tgui\states\deep_inventory.dm" #include "code\modules\tgui\states\default.dm" #include "code\modules\tgui\states\hands.dm" +#include "code\modules\tgui\states\holder.dm" #include "code\modules\tgui\states\human_adjacent.dm" #include "code\modules\tgui\states\inventory.dm" #include "code\modules\tgui\states\language_menu.dm" diff --git a/yogstation/code/modules/admin/verbs/adminhelp.dm b/yogstation/code/modules/admin/verbs/adminhelp.dm index 0683fc415d1a..f12e0da3e63b 100644 --- a/yogstation/code/modules/admin/verbs/adminhelp.dm +++ b/yogstation/code/modules/admin/verbs/adminhelp.dm @@ -612,7 +612,10 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) set name = "Adminlisttickets" set category = "Admin" - view_tickets_main(TICKET_FLAG_LIST_ALL) + if(GLOB.experimental_adminpanel) + new /datum/ticket_list_panel + else + view_tickets_main(TICKET_FLAG_LIST_ALL) /client/proc/view_tickets_main(var/flag) flag = text2num(flag) diff --git a/yogstation/code/modules/admin/verbs/ticketpanel.dm b/yogstation/code/modules/admin/verbs/ticketpanel.dm new file mode 100644 index 000000000000..81f60a8afa60 --- /dev/null +++ b/yogstation/code/modules/admin/verbs/ticketpanel.dm @@ -0,0 +1,29 @@ +GLOBAL_VAR_INIT(experimental_adminpanel, TRUE) + +/datum/ticket_list_panel + var/client/holder + +/datum/ticket_list_panel/New(user) + if(user) + setup(user) + +/datum/ticket_list_panel/proc/setup(user) + if(istype(user,/client)) + holder = user + else + var/mob/user_mob = user + holder = user_mob.client + + ui_interact(holder.mob) + +/datum/ticket_list_panel/ui_state(mob/user) + return GLOB.holder_state + +/datum/ticket_list_panel/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "TicketListPanel") + ui.open() + +/datum/ticket_list_panel/ui_data(mob/user) + . = list() diff --git a/yogstation/interface/interface.dm b/yogstation/interface/interface.dm index c3eb4237754b..4266edb87b2b 100644 --- a/yogstation/interface/interface.dm +++ b/yogstation/interface/interface.dm @@ -7,16 +7,14 @@ /client/verb/show_tickets() set name = "Tickets" set desc = "Show list of tickets" - set hidden = 1 + set hidden = TRUE if(holder) view_tickets() else - for(var/I in GLOB.ahelp_tickets.tickets_list) - var/datum/admin_help/T = I - if(compare_ckey(T.initiator_ckey, usr) && T.state == AHELP_ACTIVE) - T.TicketPanel() - return + if(current_ticket && current_ticket.state == AHELP_ACTIVE) + current_ticket.TicketPanel() + return to_chat(src, "You have no open tickets!") - return \ No newline at end of file + return From ae83cfe14e01c7d5773aeba3acb5927d67634ce7 Mon Sep 17 00:00:00 2001 From: Gabriel Adamson Date: Thu, 19 Aug 2021 09:22:38 -0500 Subject: [PATCH 02/24] Forgot to tick new file --- yogstation.dme | 1 + 1 file changed, 1 insertion(+) diff --git a/yogstation.dme b/yogstation.dme index 7713ce8fdb7b..389f817069ab 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -3290,6 +3290,7 @@ #include "yogstation\code\modules\admin\verbs\shuttle_verbs.dm" #include "yogstation\code\modules\admin\verbs\spawnfloorcluwne.dm" #include "yogstation\code\modules\admin\verbs\telecomms.dm" +#include "yogstation\code\modules\admin\verbs\ticketpanel.dm" #include "yogstation\code\modules\antagonists\_common\antag_datum.dm" #include "yogstation\code\modules\antagonists\abductor\equipment\abduction_outfits.dm" #include "yogstation\code\modules\antagonists\blob\blob\blobs\core.dm" From ef85fa81d07e5b57f4d448ff24ca0b20e82c733f Mon Sep 17 00:00:00 2001 From: Gabriel Adamson Date: Thu, 19 Aug 2021 17:30:02 -0500 Subject: [PATCH 03/24] Admin ticket viewer works now --- code/modules/admin/admin.dm | 56 +++++++++ code/modules/admin/admin_verbs.dm | 2 +- code/modules/admin/topic.dm | 57 +-------- .../tgui/interfaces/TicketListPanel.js | 115 +++++++++++++++++- .../code/modules/admin/verbs/adminhelp.dm | 2 +- .../code/modules/admin/verbs/ticketpanel.dm | 59 +++++++++ 6 files changed, 228 insertions(+), 63 deletions(-) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 4fcc170889e6..ad1e3dbcf187 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -979,6 +979,62 @@ return 1 +/datum/admins/proc/adminmoreinfo(mob/M) + if(!ismob(M)) + to_chat(usr, "This can only be used on instances of type /mob.", confidential=TRUE) + return + + var/location_description = "" + var/special_role_description = "" + var/health_description = "" + var/gender_description = "" + var/turf/T = get_turf(M) + + //Location + if(isturf(T)) + if(isarea(T.loc)) + location_description = "([M.loc == T ? "at coordinates " : "in [M.loc] at coordinates "] [T.x], [T.y], [T.z] in area [T.loc])" + else + location_description = "([M.loc == T ? "at coordinates " : "in [M.loc] at coordinates "] [T.x], [T.y], [T.z])" + + //Job + antagonist + if(M.mind) + special_role_description = "Role: [M.mind.assigned_role]; Antagonist: [M.mind.special_role]" + else + special_role_description = "Role: Mind datum missing Antagonist: Mind datum missing" + + //Health + if(isliving(M)) + var/mob/living/L = M + var/status + switch (M.stat) + if(CONSCIOUS) + status = "Alive" + if(SOFT_CRIT) + status = "Dying" + if(UNCONSCIOUS) + status = "[L.InCritical() ? "Unconscious and Dying" : "Unconscious"]" + if(DEAD) + status = "Dead" + health_description = "Status = [status]" + health_description += "
Oxy: [L.getOxyLoss()] - Tox: [L.getToxLoss()] - Fire: [L.getFireLoss()] - Brute: [L.getBruteLoss()] - Clone: [L.getCloneLoss()] - Brain: [L.getOrganLoss(ORGAN_SLOT_BRAIN)] - Stamina: [L.getStaminaLoss()]" + else + health_description = "This mob type has no health to speak of." + + //Gender + switch(M.gender) + if(MALE,FEMALE) + gender_description = "[M.gender]" + else + gender_description = "[M.gender]" + + to_chat(src.owner, "Info about [M.name]: ", confidential=TRUE) + to_chat(src.owner, "Mob type = [M.type]; Gender = [gender_description] Damage = [health_description]", confidential=TRUE) + to_chat(src.owner, "Name = [M.name]; Real_name = [M.real_name]; Mind_name = [M.mind?"[M.mind.name]":""]; Key = [M.key];", confidential=TRUE) + to_chat(src.owner, "Location = [location_description];", confidential=TRUE) + to_chat(src.owner, "[special_role_description]", confidential=TRUE) + to_chat(src.owner, ADMIN_FULLMONTY_NONAME(M), confidential=TRUE) + /client/proc/adminGreet(logout) if(SSticker.HasRoundStarted()) var/string diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index b71782e3cbc6..07911a8a17fd 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -393,7 +393,7 @@ GLOBAL_PROTECT(admin_verbs_hideable) /client/proc/check_antagonists() set name = "Check Antagonists" set category = "Admin" - if(holder) + if(check_rights(R_ADMIN)) // yogs start log_admin("[key_name(usr)] checked antagonists.") //for tsar~ if((!isobserver(usr) && SSticker.HasRoundStarted()) || !check_rights(R_VAREDIT)) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 37d6f60f3768..af246612d3fc 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1285,60 +1285,7 @@ else if(href_list["adminmoreinfo"]) var/mob/M = locate(href_list["adminmoreinfo"]) in GLOB.mob_list - if(!ismob(M)) - to_chat(usr, "This can only be used on instances of type /mob.", confidential=TRUE) - return - - var/location_description = "" - var/special_role_description = "" - var/health_description = "" - var/gender_description = "" - var/turf/T = get_turf(M) - - //Location - if(isturf(T)) - if(isarea(T.loc)) - location_description = "([M.loc == T ? "at coordinates " : "in [M.loc] at coordinates "] [T.x], [T.y], [T.z] in area [T.loc])" - else - location_description = "([M.loc == T ? "at coordinates " : "in [M.loc] at coordinates "] [T.x], [T.y], [T.z])" - - //Job + antagonist - if(M.mind) - special_role_description = "Role: [M.mind.assigned_role]; Antagonist: [M.mind.special_role]" - else - special_role_description = "Role: Mind datum missing Antagonist: Mind datum missing" - - //Health - if(isliving(M)) - var/mob/living/L = M - var/status - switch (M.stat) - if(CONSCIOUS) - status = "Alive" - if(SOFT_CRIT) - status = "Dying" - if(UNCONSCIOUS) - status = "[L.InCritical() ? "Unconscious and Dying" : "Unconscious"]" - if(DEAD) - status = "Dead" - health_description = "Status = [status]" - health_description += "
Oxy: [L.getOxyLoss()] - Tox: [L.getToxLoss()] - Fire: [L.getFireLoss()] - Brute: [L.getBruteLoss()] - Clone: [L.getCloneLoss()] - Brain: [L.getOrganLoss(ORGAN_SLOT_BRAIN)] - Stamina: [L.getStaminaLoss()]" - else - health_description = "This mob type has no health to speak of." - - //Gender - switch(M.gender) - if(MALE,FEMALE) - gender_description = "[M.gender]" - else - gender_description = "[M.gender]" - - to_chat(src.owner, "Info about [M.name]: ", confidential=TRUE) - to_chat(src.owner, "Mob type = [M.type]; Gender = [gender_description] Damage = [health_description]", confidential=TRUE) - to_chat(src.owner, "Name = [M.name]; Real_name = [M.real_name]; Mind_name = [M.mind?"[M.mind.name]":""]; Key = [M.key];", confidential=TRUE) - to_chat(src.owner, "Location = [location_description];", confidential=TRUE) - to_chat(src.owner, "[special_role_description]", confidential=TRUE) - to_chat(src.owner, ADMIN_FULLMONTY_NONAME(M), confidential=TRUE) + adminmoreinfo(M) else if(href_list["addjobslot"]) if(!check_rights(R_ADMIN)) @@ -1966,8 +1913,6 @@ src.access_news_network() else if(href_list["check_antagonist"]) - if(!check_rights(R_ADMIN)) - return usr.client.check_antagonists() else if(href_list["kick_all_from_lobby"]) diff --git a/tgui/packages/tgui/interfaces/TicketListPanel.js b/tgui/packages/tgui/interfaces/TicketListPanel.js index 51a8a917fd29..1d066f9a81ec 100644 --- a/tgui/packages/tgui/interfaces/TicketListPanel.js +++ b/tgui/packages/tgui/interfaces/TicketListPanel.js @@ -3,20 +3,125 @@ import { useBackend } from '../backend'; import { Section, Collapsible, Button } from '../components'; import { Window } from '../layouts'; -export const DisconnectPanel = (props, context) => { +export const TicketListPanel = (props, context) => { const { act, data } = useBackend(context); + const open_count = data.unresolved_tickets.length; + const closed_count = data.resolved_tickets.length; + const total_count = open_count + closed_count; + return ( -
- Hello -
+ + {data.unresolved_tickets.map(ticket => ( + + ))} + + + {data.resolved_tickets.map(ticket => ( + + ))} +
); }; + +export const TicketSummary = (props, context) => { + const { ticket } = props + const { act } = useBackend(context); + + return ( +
+ Owner: {ticket.initiator_key_name}
+ Admin: {ticket.admin_key ? ticket.admin_key : "UNCLAIMED"} +
+ + + + + + + + + + +
+
+ ) +} diff --git a/yogstation/code/modules/admin/verbs/adminhelp.dm b/yogstation/code/modules/admin/verbs/adminhelp.dm index f12e0da3e63b..7c8ea4e51781 100644 --- a/yogstation/code/modules/admin/verbs/adminhelp.dm +++ b/yogstation/code/modules/admin/verbs/adminhelp.dm @@ -613,7 +613,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) set category = "Admin" if(GLOB.experimental_adminpanel) - new /datum/ticket_list_panel + new /datum/ticket_list_panel(src) else view_tickets_main(TICKET_FLAG_LIST_ALL) diff --git a/yogstation/code/modules/admin/verbs/ticketpanel.dm b/yogstation/code/modules/admin/verbs/ticketpanel.dm index 81f60a8afa60..6e0e0ef1b853 100644 --- a/yogstation/code/modules/admin/verbs/ticketpanel.dm +++ b/yogstation/code/modules/admin/verbs/ticketpanel.dm @@ -27,3 +27,62 @@ GLOBAL_VAR_INIT(experimental_adminpanel, TRUE) /datum/ticket_list_panel/ui_data(mob/user) . = list() + .["unresolved_tickets"] = list() + .["resolved_tickets"] = list() + + for(var/datum/admin_help/ahelp as anything in GLOB.ahelp_tickets.tickets_list) + var/ticket_data = list() + ticket_data["name"] = ahelp.name + ticket_data["id"] = ahelp.id + ticket_data["initiator_key_name"] = ahelp.initiator_key_name + ticket_data["initiator_ckey"] = ahelp.initiator_ckey + ticket_data["admin_key"] = ahelp.handling_admin && ahelp.handling_admin.key + ticket_data["active"] = ahelp.state == AHELP_ACTIVE + + if(ahelp.state == AHELP_ACTIVE) + .["unresolved_tickets"] += list(ticket_data) + else + .["resolved_tickets"] += list(ticket_data) + +/datum/ticket_list_panel/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + var/datum/admin_help/ticket = GLOB.ahelp_tickets.tickets_list[params["id"]] + + switch(action) + if("view") + ticket.TicketPanel() + if("adminmoreinfo") + if(!ticket.initiator) + to_chat(holder, "Client not found") + return + holder.holder.adminmoreinfo(ticket.initiator.mob) + if("PP") + if(!ticket.initiator) + to_chat(holder, "Client not found") + return + holder.holder.show_player_panel(ticket.initiator.mob) + if("VV") + if(!ticket.initiator) + to_chat(holder, "Client not found") + return + holder.debug_variables(ticket.initiator.mob) + if("SM") + if(!ticket.initiator) + to_chat(holder, "Client not found") + return + holder.cmd_admin_subtle_message(ticket.initiator.mob) + if("FLW") + if(!ticket.initiator) + to_chat(holder, "Client not found") + return + holder.holder.observe_follow(ticket.initiator.mob) + if("CA") + holder.check_antagonists() + if("Resolve") + ticket.Resolve() + if("Reject") + ticket.Reject() + if("Close") + ticket.Close() + if("IC") + ticket.ICIssue() From c12bbc1fca0adb9a5b4d0678a44c9e3390e3173c Mon Sep 17 00:00:00 2001 From: Gabriel Adamson Date: Fri, 20 Aug 2021 12:58:28 -0500 Subject: [PATCH 04/24] Added individual ticket viewer as well --- .../tgui/interfaces/TicketListPanel.js | 7 + tgui/packages/tgui/interfaces/TicketPanel.js | 163 ++++++++++++++++ .../code/modules/admin/verbs/adminhelp.dm | 6 +- .../code/modules/admin/verbs/ticketpanel.dm | 183 +++++++++++++++--- 4 files changed, 326 insertions(+), 33 deletions(-) create mode 100644 tgui/packages/tgui/interfaces/TicketPanel.js diff --git a/tgui/packages/tgui/interfaces/TicketListPanel.js b/tgui/packages/tgui/interfaces/TicketListPanel.js index 1d066f9a81ec..ab1e57f05cd4 100644 --- a/tgui/packages/tgui/interfaces/TicketListPanel.js +++ b/tgui/packages/tgui/interfaces/TicketListPanel.js @@ -63,30 +63,35 @@ export const TicketSummary = (props, context) => { View + + + + + + + + + + + + + + + + + + ); + } + return ( + + + + + + ); + +}; + +export const TicketMessages = (props, context) => { + const { ticket, title } = props + const { act } = useBackend(context); + + const [ + message, + setMessage, + ] = useLocalState(context, 'text', ""); + + return ( +
+ + {ticket.log.map(entry => (!entry.for_admins || ticket.is_admin) && ( + + + {entry.text} + + + ) || "")} +
+ { + if(e.keyCode === KEY_ENTER) { + setMessage('') + e.target.value = message + act('send_message', {'message': value}) + } else { + setMessage(value) + } + }}> + + +
+ ) + +}; diff --git a/yogstation/code/modules/admin/verbs/adminhelp.dm b/yogstation/code/modules/admin/verbs/adminhelp.dm index 7c8ea4e51781..5d50b0c5e665 100644 --- a/yogstation/code/modules/admin/verbs/adminhelp.dm +++ b/yogstation/code/modules/admin/verbs/adminhelp.dm @@ -455,6 +455,10 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) //Show the ticket panel /datum/admin_help/proc/TicketPanel() + if(GLOB.experimental_adminpanel) + ui_interact(usr) + return + var/reply_link = " Reply" var/refresh_link = " Refresh" @@ -613,7 +617,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) set category = "Admin" if(GLOB.experimental_adminpanel) - new /datum/ticket_list_panel(src) + GLOB.ahelp_tickets.ui_interact(usr) else view_tickets_main(TICKET_FLAG_LIST_ALL) diff --git a/yogstation/code/modules/admin/verbs/ticketpanel.dm b/yogstation/code/modules/admin/verbs/ticketpanel.dm index 6e0e0ef1b853..16ac3ae1792a 100644 --- a/yogstation/code/modules/admin/verbs/ticketpanel.dm +++ b/yogstation/code/modules/admin/verbs/ticketpanel.dm @@ -1,31 +1,15 @@ GLOBAL_VAR_INIT(experimental_adminpanel, TRUE) -/datum/ticket_list_panel - var/client/holder - -/datum/ticket_list_panel/New(user) - if(user) - setup(user) - -/datum/ticket_list_panel/proc/setup(user) - if(istype(user,/client)) - holder = user - else - var/mob/user_mob = user - holder = user_mob.client - - ui_interact(holder.mob) - -/datum/ticket_list_panel/ui_state(mob/user) +/datum/admin_help_tickets/ui_state(mob/user) return GLOB.holder_state -/datum/ticket_list_panel/ui_interact(mob/user, datum/tgui/ui) +/datum/admin_help_tickets/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) ui = new(user, src, "TicketListPanel") ui.open() -/datum/ticket_list_panel/ui_data(mob/user) +/datum/admin_help_tickets/ui_data(mob/user) . = list() .["unresolved_tickets"] = list() .["resolved_tickets"] = list() @@ -39,50 +23,185 @@ GLOBAL_VAR_INIT(experimental_adminpanel, TRUE) ticket_data["admin_key"] = ahelp.handling_admin && ahelp.handling_admin.key ticket_data["active"] = ahelp.state == AHELP_ACTIVE + ticket_data["has_client"] = !!ahelp.initiator + ticket_data["has_mob"] = ticket_data["has_client"] && !!ahelp.initiator.mob + if(ahelp.state == AHELP_ACTIVE) .["unresolved_tickets"] += list(ticket_data) else .["resolved_tickets"] += list(ticket_data) -/datum/ticket_list_panel/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) +/datum/admin_help_tickets/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() - var/datum/admin_help/ticket = GLOB.ahelp_tickets.tickets_list[params["id"]] + if(.) + return + var/datum/admin_help/ticket = tickets_list[params["id"]] + . = TRUE switch(action) if("view") ticket.TicketPanel() + return if("adminmoreinfo") if(!ticket.initiator) - to_chat(holder, "Client not found") + to_chat(usr, "Client not found") return - holder.holder.adminmoreinfo(ticket.initiator.mob) + usr.client.holder.adminmoreinfo(ticket.initiator.mob) + return if("PP") if(!ticket.initiator) - to_chat(holder, "Client not found") + to_chat(usr, "Client not found") return - holder.holder.show_player_panel(ticket.initiator.mob) + usr.client.holder.show_player_panel(ticket.initiator.mob) + return if("VV") if(!ticket.initiator) - to_chat(holder, "Client not found") + to_chat(usr, "Client not found") return - holder.debug_variables(ticket.initiator.mob) + usr.client.debug_variables(ticket.initiator.mob) + return if("SM") if(!ticket.initiator) - to_chat(holder, "Client not found") + to_chat(usr, "Client not found") return - holder.cmd_admin_subtle_message(ticket.initiator.mob) + usr.client.cmd_admin_subtle_message(ticket.initiator.mob) + return if("FLW") if(!ticket.initiator) - to_chat(holder, "Client not found") + to_chat(usr, "Client not found") return - holder.holder.observe_follow(ticket.initiator.mob) + usr.client.holder.observe_follow(ticket.initiator.mob) + return if("CA") - holder.check_antagonists() + usr.client.check_antagonists() + return if("Resolve") ticket.Resolve() + return if("Reject") ticket.Reject() + return if("Close") ticket.Close() + return if("IC") ticket.ICIssue() + return + return FALSE + +/datum/admin_help/ui_state(mob/user) + return GLOB.always_state + +/datum/admin_help/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "TicketPanel") + ui.open() + +/datum/admin_help/ui_data(mob/user) + . = list() + .["is_admin"] = !!user.client.holder + .["name"] = name + .["id"] = id + .["admin"] = handling_admin && handling_admin.key + .["is_resolved"] = state != AHELP_ACTIVE + .["initiator_key_name"] = initiator_key_name + .["popups"] = popups_enabled + + var/mob/initiator_mob = initiator && initiator.mob + var/datum/mind/initiator_mind = initiator_mob && initiator_mob.mind + .["has_client"] = !!initiator + .["has_mob"] = !!initiator_mob + .["role"] = initiator_mind && initiator_mind.assigned_role + .["antag"] = initiator_mind && initiator_mind.special_role + + var/turf/T = get_turf(initiator.mob) + var/location = "([initiator.mob.loc == T ? "at " : "in [initiator.mob.loc] at "] [T.x], [T.y], [T.z]" + if(isturf(T)) + if(isarea(T.loc)) + location += " in area [T.loc]" + location += ")" + .["location"] = location + + .["log"] = list() + + for(var/datum/ticket_log/TL as anything in _interactions) + var/log_data = list() + log_data["text"] = TL.toSanitizedString() + log_data["for_admins"] = TL.for_admins + .["log"] += list(log_data) + + +/datum/admin_help/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + . = TRUE + switch(action) + if("adminmoreinfo") + if(!initiator) + to_chat(usr, "Client not found") + return + usr.client.holder.adminmoreinfo(initiator.mob) + return + if("PP") + if(!initiator) + to_chat(usr, "Client not found") + return + usr.client.holder.show_player_panel(initiator.mob) + return + if("VV") + if(!initiator) + to_chat(usr, "Client not found") + return + usr.client.debug_variables(initiator.mob) + return + if("SM") + if(!initiator) + to_chat(usr, "Client not found") + return + usr.client.cmd_admin_subtle_message(initiator.mob) + return + if("FLW") + if(!initiator) + to_chat(usr, "Client not found") + return + usr.client.holder.observe_follow(initiator.mob) + return + if("CA") + usr.client.check_antagonists() + return + if("Resolve") + Resolve() + return + if("Reject") + Reject() + return + if("Close") + Close() + return + if("IC") + ICIssue() + return + if("MHelp") + MhelpQuestion() + return + if("togglePopups") + PopUps() + return + if("Administer") + Administer() + return + if("send_message") + var/message = params["message"] + if(usr.client.holder) + usr.client.cmd_admin_pm(initiator, message) + return + if(usr.client.current_ticket != src) + to_chat(usr, "You are not able to reply to this ticket. To open a ticket, please use the adminhelp verb") + if(handling_admin) + usr.client.cmd_admin_pm(handling_admin, message) + else + MessageNoRecipient(message) + + From 8718b68ed1f3effbfe155503d0618d5628d1ec76 Mon Sep 17 00:00:00 2001 From: Gabriel Adamson Date: Fri, 20 Aug 2021 13:07:18 -0500 Subject: [PATCH 05/24] Fix linter errors --- tgui/packages/tgui/interfaces/TicketPanel.js | 27 ++++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/tgui/packages/tgui/interfaces/TicketPanel.js b/tgui/packages/tgui/interfaces/TicketPanel.js index 51f45aa07ecd..a03a205addda 100644 --- a/tgui/packages/tgui/interfaces/TicketPanel.js +++ b/tgui/packages/tgui/interfaces/TicketPanel.js @@ -7,7 +7,7 @@ import { KEY_ENTER } from 'common/keycodes'; export const TicketPanel = (props, context) => { const { act, data } = useBackend(context); - if(data.is_admin) { + if (data.is_admin) { return ( { Is{data.is_resolved ? "" : " not"} resolved
+ level="2"> Job: {data.role}
Antag: {data.antag || "No"}
Location: {data.location}
+ level="2">
+ title="Messages" /> ); @@ -107,7 +107,7 @@ export const TicketPanel = (props, context) => { + ticket={data} /> ); @@ -141,19 +141,18 @@ export const TicketMessages = (props, context) => { selfclear value={message} onChange={(e, value) => { - if(e.keyCode === KEY_ENTER) { - setMessage('') - e.target.value = message - act('send_message', {'message': value}) + if (e.keyCode === KEY_ENTER) { + setMessage(''); + e.target.value = message; + act('send_message', { 'message': value }); } else { - setMessage(value) + setMessage(value); } - }}> - + }} /> From f98a1c7bbaaca03d083768cd01e040f9ad092389 Mon Sep 17 00:00:00 2001 From: Gabriel Adamson Date: Fri, 20 Aug 2021 13:11:09 -0500 Subject: [PATCH 06/24] Actually saved changes this time --- .../tgui/interfaces/TicketListPanel.js | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/tgui/packages/tgui/interfaces/TicketListPanel.js b/tgui/packages/tgui/interfaces/TicketListPanel.js index ab1e57f05cd4..8ad8f50bed2d 100644 --- a/tgui/packages/tgui/interfaces/TicketListPanel.js +++ b/tgui/packages/tgui/interfaces/TicketListPanel.js @@ -19,13 +19,13 @@ export const TicketListPanel = (props, context) => { {data.unresolved_tickets.map(ticket => ( + ticket={ticket} /> ))} { title={"Resolved Tickets (" + closed_count + "/" + total_count + ")"}> {data.resolved_tickets.map(ticket => ( + key={ticket.id} + ticket={ticket} /> ))} @@ -44,13 +44,12 @@ export const TicketListPanel = (props, context) => { }; export const TicketSummary = (props, context) => { - const { ticket } = props + const { ticket } = props; const { act } = useBackend(context); return (
Owner: {ticket.initiator_key_name}
Admin: {ticket.admin_key ? ticket.admin_key : "UNCLAIMED"} @@ -58,77 +57,78 @@ export const TicketSummary = (props, context) => { level = "2">
- ) -} + ); +}; From ae632ea0dfe3337b1504dd208c2a834e6ff41fad Mon Sep 17 00:00:00 2001 From: Gabriel Adamson Date: Fri, 20 Aug 2021 13:17:22 -0500 Subject: [PATCH 07/24] Hopefully linter is happy --- tgui/packages/tgui/interfaces/TicketListPanel.js | 2 +- tgui/packages/tgui/interfaces/TicketPanel.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tgui/packages/tgui/interfaces/TicketListPanel.js b/tgui/packages/tgui/interfaces/TicketListPanel.js index 8ad8f50bed2d..917a6c8c88a0 100644 --- a/tgui/packages/tgui/interfaces/TicketListPanel.js +++ b/tgui/packages/tgui/interfaces/TicketListPanel.js @@ -54,7 +54,7 @@ export const TicketSummary = (props, context) => { Owner: {ticket.initiator_key_name}
Admin: {ticket.admin_key ? ticket.admin_key : "UNCLAIMED"}
+ level="2">
- ) + ); }; From eb12451e6406f07646c27433c8af327090b89896 Mon Sep 17 00:00:00 2001 From: Gabriel Adamson Date: Fri, 20 Aug 2021 16:53:31 -0500 Subject: [PATCH 08/24] Fixed crash when client disconnects --- yogstation/code/modules/admin/verbs/ticketpanel.dm | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/yogstation/code/modules/admin/verbs/ticketpanel.dm b/yogstation/code/modules/admin/verbs/ticketpanel.dm index 16ac3ae1792a..9cc2ae02f6b9 100644 --- a/yogstation/code/modules/admin/verbs/ticketpanel.dm +++ b/yogstation/code/modules/admin/verbs/ticketpanel.dm @@ -115,12 +115,14 @@ GLOBAL_VAR_INIT(experimental_adminpanel, TRUE) .["role"] = initiator_mind && initiator_mind.assigned_role .["antag"] = initiator_mind && initiator_mind.special_role - var/turf/T = get_turf(initiator.mob) - var/location = "([initiator.mob.loc == T ? "at " : "in [initiator.mob.loc] at "] [T.x], [T.y], [T.z]" - if(isturf(T)) - if(isarea(T.loc)) - location += " in area [T.loc]" - location += ")" + var/location = "" + if(initiator_mob) + var/turf/T = get_turf(initiator.mob) + location = "([initiator.mob.loc == T ? "at " : "in [initiator.mob.loc] at "] [T.x], [T.y], [T.z]" + if(isturf(T)) + if(isarea(T.loc)) + location += " in area [T.loc]" + location += ")" .["location"] = location .["log"] = list() From 847e930a599dac69a4f08091e840396477c3c8ae Mon Sep 17 00:00:00 2001 From: Gabriel Adamson Date: Fri, 20 Aug 2021 20:31:40 -0500 Subject: [PATCH 09/24] Committing changes for now --- code/modules/admin/admin.dm | 3 + code/modules/admin/verbs/randomverbs.dm | 2 +- .../tgui/interfaces/TicketListPanel.js | 21 +++-- tgui/packages/tgui/interfaces/TicketPanel.js | 88 ++++++++++++++----- .../code/modules/admin/verbs/ticketpanel.dm | 32 ++++++- 5 files changed, 116 insertions(+), 30 deletions(-) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index ad1e3dbcf187..171b7144f86e 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -761,6 +761,9 @@ set desc = "Edit mobs's memory and role" set name = "Show Traitor Panel" + if(!check_rights(R_ADMIN)) + return + if(!istype(M)) to_chat(usr, "This can only be used on instances of type /mob", confidential=TRUE) return diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index a70be6b8aac9..98c8046fc33b 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -41,7 +41,7 @@ to_chat(M, "You hear a voice in your head... [msg]") log_admin("SubtlePM: [key_name(usr)] -> [key_name(M)] : [msg]") - msg = " SubtleMessage: [key_name(usr)] -> [key_name(M)] : [msg]" // yogs - Yog Tickets + msg = "SubtleMessage: [key_name(usr)] -> [key_name(M)] : [msg]" // yogs - Yog Tickets message_admins(msg) admin_ticket_log(M, msg) SSblackbox.record_feedback("tally", "admin_verb", 1, "Subtle Message") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/tgui/packages/tgui/interfaces/TicketListPanel.js b/tgui/packages/tgui/interfaces/TicketListPanel.js index 917a6c8c88a0..fd803f2fc76f 100644 --- a/tgui/packages/tgui/interfaces/TicketListPanel.js +++ b/tgui/packages/tgui/interfaces/TicketListPanel.js @@ -13,11 +13,21 @@ export const TicketListPanel = (props, context) => { return ( - + + ); +}; + +export const TicketListView = (prop, context) => { + const { data, filter_type } = prop + return ( + + { ticket={ticket} /> ))} - - - ); -}; + + ) +} export const TicketSummary = (props, context) => { const { ticket } = props; diff --git a/tgui/packages/tgui/interfaces/TicketPanel.js b/tgui/packages/tgui/interfaces/TicketPanel.js index cb2cc1dfc18d..844a0609648f 100644 --- a/tgui/packages/tgui/interfaces/TicketPanel.js +++ b/tgui/packages/tgui/interfaces/TicketPanel.js @@ -1,6 +1,6 @@ import { useBackend, useLocalState } from '../backend'; -import { Section, Button, Table, Input } from '../components'; +import { Section, Button, Table, Input, TextArea, Box } from '../components'; import { Window } from '../layouts'; import { KEY_ENTER } from 'common/keycodes'; @@ -13,81 +13,128 @@ export const TicketPanel = (props, context) => { title="Ticket Viewer" width={700} height={700} - resizable> + resizable + backgroundColor='pink'>
- Primary Admin: {data.admin || "Unassigned"}
+ + Assigned Admin: {data.admin || "Unassigned"}
Is{data.is_resolved ? "" : " not"} resolved +
- Job: {data.role}
- Antag: {data.antag || "No"}
- Location: {data.location} + level="2" + m="-5px"> + Job: {data.role}
+ Antag: {data.antag || "No"}
+ Location: {data.location}
+ onClick={() => act('adminmoreinfo')} /> + + + + +
@@ -126,20 +173,18 @@ export const TicketMessages = (props, context) => { return (
- - {ticket.log.map(entry => (!entry.for_admins || ticket.is_admin) && ( - - - {entry.text} - - - ) || "")} -
+ {ticket.log.map(entry => (!entry.for_admins || ticket.is_admin) && ( + + {entry.time} - {entry.user} - {entry.text} + + ) || "")} { if (e.keyCode === KEY_ENTER) { setMessage(''); @@ -150,6 +195,7 @@ export const TicketMessages = (props, context) => { } }} /> + )}> + Owner: {ticket.initiator_key_name}
+ Admin: {ticket.admin_key ? ticket.admin_key : "UNCLAIMED"}
+ {!ticket.has_client ? "DISCONNECTED" : ""}
+ })} /> + + +
diff --git a/tgui/packages/tgui/interfaces/TicketPanel.js b/tgui/packages/tgui/interfaces/TicketPanel.js index 844a0609648f..87144ea9fe7a 100644 --- a/tgui/packages/tgui/interfaces/TicketPanel.js +++ b/tgui/packages/tgui/interfaces/TicketPanel.js @@ -36,47 +36,47 @@ export const TicketPanel = (props, context) => { level="2"> @@ -97,7 +97,7 @@ export const TicketPanel = (props, context) => { @@ -108,25 +108,25 @@ export const TicketPanel = (props, context) => { diff --git a/yogstation/code/modules/admin/verbs/ticketpanel.dm b/yogstation/code/modules/admin/verbs/ticketpanel.dm index cacee9c7c2b5..8b0c26701eed 100644 --- a/yogstation/code/modules/admin/verbs/ticketpanel.dm +++ b/yogstation/code/modules/admin/verbs/ticketpanel.dm @@ -13,6 +13,7 @@ GLOBAL_VAR_INIT(experimental_adminpanel, TRUE) . = list() .["unresolved_tickets"] = list() .["resolved_tickets"] = list() + .["user_key"] = user.key for(var/datum/admin_help/ahelp as anything in GLOB.ahelp_tickets.tickets_list) var/ticket_data = list() @@ -36,56 +37,18 @@ GLOBAL_VAR_INIT(experimental_adminpanel, TRUE) if(.) return var/datum/admin_help/ticket = tickets_list[params["id"]] + if(!ticket) + return FALSE . = TRUE + if(ticket_ui_act(action, ticket)) + return switch(action) if("view") ticket.TicketPanel() return - if("adminmoreinfo") - if(!ticket.initiator) - to_chat(usr, "Client not found") - return - usr.client.holder.adminmoreinfo(ticket.initiator.mob) - return - if("PP") - if(!ticket.initiator) - to_chat(usr, "Client not found") - return - usr.client.holder.show_player_panel(ticket.initiator.mob) - return - if("VV") - if(!ticket.initiator) - to_chat(usr, "Client not found") - return - usr.client.debug_variables(ticket.initiator.mob) - return - if("SM") - if(!ticket.initiator) - to_chat(usr, "Client not found") - return - usr.client.cmd_admin_subtle_message(ticket.initiator.mob) - return - if("FLW") - if(!ticket.initiator) - to_chat(usr, "Client not found") - return - usr.client.holder.observe_follow(ticket.initiator.mob) - return - if("CA") - usr.client.check_antagonists() - return - if("Resolve") - ticket.Resolve() - return - if("Reject") - ticket.Reject() - return - if("Close") - ticket.Close() - return - if("IC") - ticket.ICIssue() + if("reply") + usr.client.cmd_admin_pm(ticket.initiator) return return FALSE @@ -141,97 +104,106 @@ GLOBAL_VAR_INIT(experimental_adminpanel, TRUE) if(.) return . = TRUE + if(ticket_ui_act(action, src)) + return + + switch(action) + if("send_message") + var/message = params["message"] + if(usr.client.holder) + usr.client.cmd_admin_pm(initiator, message) + return + if(usr.client.current_ticket != src) + to_chat(usr, "You are not able to reply to this ticket. To open a ticket, please use the adminhelp verb") + if(handling_admin) + usr.client.cmd_admin_pm(handling_admin, message) + else + MessageNoRecipient(message) + return + return FALSE + +/proc/ticket_ui_act(action, T) + var/datum/admin_help/ticket = T + if(!ticket) + return + . = TRUE switch(action) if("adminmoreinfo") - if(!initiator) + if(!ticket.initiator) to_chat(usr, "Client not found") return - usr.client.holder.adminmoreinfo(initiator.mob) + usr.client.holder.adminmoreinfo(ticket.initiator.mob) return if("PP") - if(!initiator) + if(!ticket.initiator) to_chat(usr, "Client not found") return - usr.client.holder.show_player_panel(initiator.mob) + usr.client.holder.show_player_panel(ticket.initiator.mob) return if("VV") - if(!initiator) + if(!ticket.initiator) to_chat(usr, "Client not found") return - usr.client.debug_variables(initiator.mob) + usr.client.debug_variables(ticket.initiator.mob) return if("SM") - if(!initiator) + if(!ticket.initiator) to_chat(usr, "Client not found") return - usr.client.cmd_admin_subtle_message(initiator.mob) + usr.client.cmd_admin_subtle_message(ticket.initiator.mob) return if("FLW") - if(!initiator) + if(!ticket.initiator) to_chat(usr, "Client not found") return - usr.client.holder.observe_follow(initiator.mob) + usr.client.holder.observe_follow(ticket.initiator.mob) return if("CA") usr.client.check_antagonists() return if("Resolve") - Resolve() + ticket.Resolve() return if("Reject") - Reject() + ticket.Reject() return if("Close") - Close() + ticket.Close() return if("IC") - ICIssue() + ticket.ICIssue() return if("MHelp") - MhelpQuestion() + ticket.MhelpQuestion() return if("togglePopups") - PopUps() + ticket.PopUps() return if("Administer") - Administer() + ticket.Administer() return if("Wiki") - WikiIssue() + ticket.WikiIssue() return if("Bug") - GithubIssue() + ticket.GithubIssue() return if("TP") - if(!initiator) + if(!ticket.initiator) to_chat(usr, "Client not found") return - usr.client.holder.show_traitor_panel(initiator.mob) + usr.client.holder.show_traitor_panel(ticket.initiator.mob) return if("Logs") - if(!initiator) + if(!ticket.initiator) to_chat(usr, "Client not found") return - show_individual_logging_panel(initiator.mob) + show_individual_logging_panel(ticket.initiator.mob) return if("Smite") - if(!initiator) + if(!ticket.initiator) to_chat(usr, "Client not found") return - usr.client.smite(initiator.mob) - return - if("send_message") - var/message = params["message"] - if(usr.client.holder) - usr.client.cmd_admin_pm(initiator, message) - return - if(usr.client.current_ticket != src) - to_chat(usr, "You are not able to reply to this ticket. To open a ticket, please use the adminhelp verb") - if(handling_admin) - usr.client.cmd_admin_pm(handling_admin, message) - else - MessageNoRecipient(message) + usr.client.smite(ticket.initiator.mob) return return FALSE - - From b95a5e368da357f9b2cc9931122670247f3a1126 Mon Sep 17 00:00:00 2001 From: Gabriel Adamson Date: Wed, 25 Aug 2021 00:40:30 -0500 Subject: [PATCH 11/24] Fix some linter errors --- .../tgui/interfaces/TicketListPanel.js | 49 ++++++++++--------- tgui/packages/tgui/interfaces/TicketPanel.js | 5 +- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/tgui/packages/tgui/interfaces/TicketListPanel.js b/tgui/packages/tgui/interfaces/TicketListPanel.js index 1009e8c0df72..0215b56dfafb 100644 --- a/tgui/packages/tgui/interfaces/TicketListPanel.js +++ b/tgui/packages/tgui/interfaces/TicketListPanel.js @@ -2,6 +2,7 @@ import { useBackend, useLocalState } from '../backend'; import { Section, Collapsible, Button, Tabs } from '../components'; import { Window } from '../layouts'; +import { Fragment } from 'inferno'; export const TicketListPanel = (props, context) => { const { act, data } = useBackend(context); @@ -9,10 +10,10 @@ export const TicketListPanel = (props, context) => { const FILTERS = [ "ALL", "MY TICKETS", - "UNCLAIMED" - ] + "UNCLAIMED", + ]; - const [filterType, setFilterType] = useLocalState(context, 'filterType', FILTERS[0]) + const [filterType, setFilterType] = useLocalState(context, 'filterType', FILTERS[0]); return ( { resizable> - {FILTERS.map((filter) => ( + {FILTERS.map(filter => ( { const closed_count = data.resolved_tickets.length; const total_count = open_count + closed_count; - const filterTicket = function(ticket) { - if(filter_type === "ALL") return true - if(filter_type === "MY TICKETS" && ticket.admin_key == data.user_key) return true - if(filter_type === "UNCLAIMED" && !ticket.admin_key) return true - return false - } + const filterTicket = function (ticket) { + if (filter_type === "ALL") return true; + if (filter_type === "MY TICKETS" && ticket.admin_key === data.user_key) return true; + if (filter_type === "UNCLAIMED" && !ticket.admin_key) return true; + return false; + }; return ( - {data.unresolved_tickets.filter(filterTicket).map(ticket => ( - - ))} + className="Section__titleText" + color={open_count === 0 ? 'default' : 'red'} + open + title={"Unresolved Tickets (" + open_count + "/" + total_count + ")"}> + {data.unresolved_tickets.filter(filterTicket).map(ticket => ( + + ))} {data.resolved_tickets.filter(filterTicket).map(ticket => ( - + ))} - ) -} + ); +}; export const TicketSummary = (props, context) => { const { ticket } = props; diff --git a/tgui/packages/tgui/interfaces/TicketPanel.js b/tgui/packages/tgui/interfaces/TicketPanel.js index 87144ea9fe7a..6f9803d3495b 100644 --- a/tgui/packages/tgui/interfaces/TicketPanel.js +++ b/tgui/packages/tgui/interfaces/TicketPanel.js @@ -13,12 +13,11 @@ export const TicketPanel = (props, context) => { title="Ticket Viewer" width={700} height={700} - resizable - backgroundColor='pink'> + resizable>
- + Assigned Admin: {data.admin || "Unassigned"}
Is{data.is_resolved ? "" : " not"} resolved From cff2f20ee0d9c3518ebf63303824cfb74fae9afe Mon Sep 17 00:00:00 2001 From: Gabriel Adamson Date: Wed, 25 Aug 2021 00:45:03 -0500 Subject: [PATCH 12/24] Fix indentation --- tgui/packages/tgui/interfaces/TicketPanel.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tgui/packages/tgui/interfaces/TicketPanel.js b/tgui/packages/tgui/interfaces/TicketPanel.js index 6f9803d3495b..233807a8ab2b 100644 --- a/tgui/packages/tgui/interfaces/TicketPanel.js +++ b/tgui/packages/tgui/interfaces/TicketPanel.js @@ -18,10 +18,10 @@ export const TicketPanel = (props, context) => {
- Assigned Admin: {data.admin || "Unassigned"}
- - Is{data.is_resolved ? "" : " not"} resolved - + Assigned Admin: {data.admin || "Unassigned"}
+ + Is{data.is_resolved ? "" : " not"} resolved +
Date: Wed, 25 Aug 2021 00:53:48 -0500 Subject: [PATCH 13/24] Fixed indenting this time, I hope --- .../tgui/interfaces/TicketListPanel.js | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tgui/packages/tgui/interfaces/TicketListPanel.js b/tgui/packages/tgui/interfaces/TicketListPanel.js index 0215b56dfafb..ef3cb0ed0d29 100644 --- a/tgui/packages/tgui/interfaces/TicketListPanel.js +++ b/tgui/packages/tgui/interfaces/TicketListPanel.js @@ -63,21 +63,21 @@ export const TicketListView = (props, context) => { open title={"Unresolved Tickets (" + open_count + "/" + total_count + ")"}> {data.unresolved_tickets.filter(filterTicket).map(ticket => ( - + ))} - - - {data.resolved_tickets.filter(filterTicket).map(ticket => ( + + + {data.resolved_tickets.filter(filterTicket).map(ticket => ( - ))} - + ))} + ); }; From 8ca4dd9534bb4f184a0cc9b26488d962faf3d561 Mon Sep 17 00:00:00 2001 From: Gabriel Adamson Date: Wed, 25 Aug 2021 11:22:32 -0500 Subject: [PATCH 14/24] Remove html from teleport ticket log --- code/modules/admin/verbs/adminjump.dm | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm index f7c1dc013e37..e196d8678b94 100644 --- a/code/modules/admin/verbs/adminjump.dm +++ b/code/modules/admin/verbs/adminjump.dm @@ -148,10 +148,11 @@ if(A && istype(A)) if(M.forceMove(safepick(get_area_turfs(A)))) - log_admin("[key_name(usr)] teleported [key_name(M)] to [AREACOORD(A)]") - var/msg = "[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(M)] to [AREACOORD(A)]" - message_admins(msg) - admin_ticket_log(M, msg) + message_admins("[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(M)] to [AREACOORD(A)]") + + var/log_msg = "[key_name(usr)] teleported [key_name(M)] to [AREACOORD(A)]" + log_admin(log_msg) + admin_ticket_log(M, log_msg, TRUE) else to_chat(src, "Failed to move mob to a valid location.", confidential=TRUE) SSblackbox.record_feedback("tally", "admin_verb", 1, "Send Mob") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! From 8fd2ed102519d093c4f28e5acef3643227e97e08 Mon Sep 17 00:00:00 2001 From: Gabriel Adamson Date: Wed, 25 Aug 2021 11:31:48 -0500 Subject: [PATCH 15/24] Added line break, changed TP icon --- tgui/packages/tgui/interfaces/TicketListPanel.js | 2 +- tgui/packages/tgui/interfaces/TicketPanel.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tgui/packages/tgui/interfaces/TicketListPanel.js b/tgui/packages/tgui/interfaces/TicketListPanel.js index ef3cb0ed0d29..e7b91117b1fb 100644 --- a/tgui/packages/tgui/interfaces/TicketListPanel.js +++ b/tgui/packages/tgui/interfaces/TicketListPanel.js @@ -150,7 +150,7 @@ export const TicketSummary = (props, context) => { FLW +
- )}> - Owner: {ticket.initiator_key_name}
+ title={"#" + ticket.id + ": " + ticket.name}> + Owner: +
Admin: {ticket.admin_key ? ticket.admin_key : "UNCLAIMED"}
{!ticket.has_client ? "DISCONNECTED" : ""}
Date: Wed, 25 Aug 2021 14:10:16 -0500 Subject: [PATCH 17/24] Makes ticket panel thicc --- tgui/packages/tgui/interfaces/TicketListPanel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgui/packages/tgui/interfaces/TicketListPanel.js b/tgui/packages/tgui/interfaces/TicketListPanel.js index 365464cb4dc3..6f9d3eb11320 100644 --- a/tgui/packages/tgui/interfaces/TicketListPanel.js +++ b/tgui/packages/tgui/interfaces/TicketListPanel.js @@ -18,7 +18,7 @@ export const TicketListPanel = (props, context) => { return ( From 8eae07621a40530779b5617a524197c13e571d87 Mon Sep 17 00:00:00 2001 From: Gabriel Adamson Date: Wed, 25 Aug 2021 14:11:15 -0500 Subject: [PATCH 18/24] Little bit less thicc --- tgui/packages/tgui/interfaces/TicketListPanel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgui/packages/tgui/interfaces/TicketListPanel.js b/tgui/packages/tgui/interfaces/TicketListPanel.js index 6f9d3eb11320..1ddb14faceab 100644 --- a/tgui/packages/tgui/interfaces/TicketListPanel.js +++ b/tgui/packages/tgui/interfaces/TicketListPanel.js @@ -18,7 +18,7 @@ export const TicketListPanel = (props, context) => { return ( From 0e5d9ac863cf06e722af402223bae1efa195b000 Mon Sep 17 00:00:00 2001 From: Gabriel Adamson Date: Wed, 25 Aug 2021 14:29:19 -0500 Subject: [PATCH 19/24] Reverses ticket list --- tgui/packages/tgui/interfaces/TicketListPanel.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tgui/packages/tgui/interfaces/TicketListPanel.js b/tgui/packages/tgui/interfaces/TicketListPanel.js index 1ddb14faceab..3c1ff553bc23 100644 --- a/tgui/packages/tgui/interfaces/TicketListPanel.js +++ b/tgui/packages/tgui/interfaces/TicketListPanel.js @@ -62,7 +62,7 @@ export const TicketListView = (props, context) => { color={open_count === 0 ? 'default' : 'red'} open title={"Unresolved Tickets (" + open_count + "/" + total_count + ")"}> - {data.unresolved_tickets.filter(filterTicket).map(ticket => ( + {data.unresolved_tickets.filter(filterTicket).reverse().map(ticket => ( @@ -72,7 +72,7 @@ export const TicketListView = (props, context) => { className="Section__titleText" color="green" title={"Resolved Tickets (" + closed_count + "/" + total_count + ")"}> - {data.resolved_tickets.filter(filterTicket).map(ticket => ( + {data.resolved_tickets.filter(filterTicket).reverse().map(ticket => ( From d38e0f92f5ed3ad6a5b6a38a90a0b73b0b6e782e Mon Sep 17 00:00:00 2001 From: Gabriel Adamson Date: Wed, 25 Aug 2021 23:55:28 -0500 Subject: [PATCH 20/24] Hopefully removes html from tickets --- code/datums/datumvars.dm | 2 +- code/modules/admin/verbs/adminjump.dm | 12 ++++++------ code/modules/admin/verbs/adminpm.dm | 4 ++-- code/modules/admin/verbs/randomverbs.dm | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 03367dc214eb..e79b3af975d6 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -1466,7 +1466,7 @@ var/log_msg = "[key_name(usr)] dealt [amount] amount of [Text] damage to [key_name(L)]" message_admins("[key_name(usr)] dealt [amount] amount of [Text] damage to [ADMIN_LOOKUPFLW(L)]") log_admin(log_msg) - admin_ticket_log(L, "[log_msg]") + admin_ticket_log(L, log_msg) vv_update_display(L, Text, "[newamt]") else if(href_list["copyoutfit"]) if(!check_rights(R_SPAWN)) diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm index e196d8678b94..b6c015d93efc 100644 --- a/code/modules/admin/verbs/adminjump.dm +++ b/code/modules/admin/verbs/adminjump.dm @@ -103,9 +103,9 @@ return var/atom/loc = get_turf(usr) - log_admin("[key_name(usr)] teleported [key_name(M)] to [AREACOORD(loc)]") - var/msg = "[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(M)] to [ADMIN_VERBOSEJMP(loc)]" - message_admins(msg) + message_admins("[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(M)] to [ADMIN_VERBOSEJMP(loc)]" + var/msg = "[key_name(usr)] teleported [key_name(M)] to [AREACOORD(loc)]") + log_admin(msg) admin_ticket_log(M, msg) M.forceMove(loc) SSblackbox.record_feedback("tally", "admin_verb", 1, "Get Mob") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -129,9 +129,9 @@ if(!M) return - log_admin("[key_name(usr)] teleported [key_name(M)]") - var/msg = "[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(M)]" - message_admins(msg) + message_admins("[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(M)]") + var/msg = "[key_name(usr)] teleported [key_name(M)]" + log_admin(msg) admin_ticket_log(M, msg) if(M) M.forceMove(get_turf(usr)) diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index 4f32ec980b5d..00cd9f431092 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -182,7 +182,7 @@ if(irc) to_chat(src, "PM to-Admins: [rawmsg]", confidential=TRUE) - var/datum/admin_help/AH = admin_ticket_log(src, keywordparsedmsg) // yogs - Yog Tickets + var/datum/admin_help/AH = admin_ticket_log(src, rawmsg) // yogs - Yog Tickets ircreplyamount-- send2irc("[AH ? "#[AH.id] " : ""]Reply: [ckey]", rawmsg) else @@ -368,7 +368,7 @@ html = "Click on the administrator's name to reply.", confidential = TRUE) // yogs - Yog Tickets - admin_ticket_log(C, "PM From [irc_tagged]: [msg]") // yogs - Yog Tickets + admin_ticket_log(C, "PM From [irc_tagged]: [msg]") // yogs - Yog Tickets window_flash(C, ignorepref = TRUE) //always play non-admin recipients the adminhelp sound diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 98c8046fc33b..9c148501fbd0 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -168,7 +168,7 @@ to_chat(M, msg) log_admin("DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]") - msg = " DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]" // yogs - Yog Tickets + msg = "DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]" // yogs - Yog Tickets message_admins(msg) admin_ticket_log(M, msg) SSblackbox.record_feedback("tally", "admin_verb", 1, "Direct Narrate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! From 0b10c96141c2e266d8bc76f39fc4b5c2dce47504 Mon Sep 17 00:00:00 2001 From: Gabriel Adamson Date: Thu, 26 Aug 2021 00:03:27 -0500 Subject: [PATCH 21/24] Remove extra parenthesis --- code/modules/admin/verbs/adminjump.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm index b6c015d93efc..a838a2d8dc9d 100644 --- a/code/modules/admin/verbs/adminjump.dm +++ b/code/modules/admin/verbs/adminjump.dm @@ -104,7 +104,7 @@ var/atom/loc = get_turf(usr) message_admins("[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(M)] to [ADMIN_VERBOSEJMP(loc)]" - var/msg = "[key_name(usr)] teleported [key_name(M)] to [AREACOORD(loc)]") + var/msg = "[key_name(usr)] teleported [key_name(M)] to [AREACOORD(loc)]" log_admin(msg) admin_ticket_log(M, msg) M.forceMove(loc) From 1d151930a223087dda48f355164c1c2a526848e0 Mon Sep 17 00:00:00 2001 From: Gabriel Adamson Date: Thu, 26 Aug 2021 00:11:50 -0500 Subject: [PATCH 22/24] Should fix tests --- code/modules/admin/verbs/adminjump.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm index a838a2d8dc9d..91b4c74e49ff 100644 --- a/code/modules/admin/verbs/adminjump.dm +++ b/code/modules/admin/verbs/adminjump.dm @@ -103,7 +103,7 @@ return var/atom/loc = get_turf(usr) - message_admins("[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(M)] to [ADMIN_VERBOSEJMP(loc)]" + message_admins("[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(M)] to [ADMIN_VERBOSEJMP(loc)]") var/msg = "[key_name(usr)] teleported [key_name(M)] to [AREACOORD(loc)]" log_admin(msg) admin_ticket_log(M, msg) From def5a9cee55bd7e8468a47c39979eb181cc40176 Mon Sep 17 00:00:00 2001 From: Gabriel Adamson Date: Sun, 29 Aug 2021 11:04:04 -0500 Subject: [PATCH 23/24] Improve the ui --- tgui/packages/tgui/index.js | 1 + .../tgui/interfaces/TicketListPanel.js | 216 +++++++-------- tgui/packages/tgui/interfaces/TicketPanel.js | 258 +++++++++--------- .../tgui/styles/themes/admintickets.scss | 30 ++ 4 files changed, 268 insertions(+), 237 deletions(-) create mode 100644 tgui/packages/tgui/styles/themes/admintickets.scss diff --git a/tgui/packages/tgui/index.js b/tgui/packages/tgui/index.js index 6ea1f6c4ceba..bccc0ef9160b 100644 --- a/tgui/packages/tgui/index.js +++ b/tgui/packages/tgui/index.js @@ -15,6 +15,7 @@ import './styles/themes/ntos.scss'; import './styles/themes/paper.scss'; import './styles/themes/retro.scss'; import './styles/themes/syndicate.scss'; +import './styles/themes/admintickets.scss'; import { perf } from 'common/perf'; import { setupHotReloading } from 'tgui-dev-server/link/client'; diff --git a/tgui/packages/tgui/interfaces/TicketListPanel.js b/tgui/packages/tgui/interfaces/TicketListPanel.js index 3c1ff553bc23..8ee5fc0b76ca 100644 --- a/tgui/packages/tgui/interfaces/TicketListPanel.js +++ b/tgui/packages/tgui/interfaces/TicketListPanel.js @@ -1,6 +1,6 @@ import { useBackend, useLocalState } from '../backend'; -import { Section, Collapsible, Button, Tabs } from '../components'; +import { Section, Collapsible, Button, Tabs, Flex } from '../components'; import { Window } from '../layouts'; import { Fragment } from 'inferno'; @@ -17,8 +17,9 @@ export const TicketListPanel = (props, context) => { return ( @@ -58,24 +59,26 @@ export const TicketListView = (props, context) => { return ( {data.unresolved_tickets.filter(filterTicket).reverse().map(ticket => ( + ticket={ticket} + user={data.user_key} /> ))} {data.resolved_tickets.filter(filterTicket).reverse().map(ticket => ( + ticket={ticket} + user={data.user_key} /> ))} @@ -83,11 +86,87 @@ export const TicketListView = (props, context) => { }; export const TicketSummary = (props, context) => { - const { ticket } = props; + const { ticket, user } = props; const { act } = useBackend(context); + const buttons = [ + [ + { + name: 'View', + act: 'view', + icon: 'eye', + }, + { + name: '', + act: 'adminmoreinfo', + icon: 'question', + disabled: !ticket.has_mob, + }, + { + name: 'PP', + act: 'PP', + icon: 'user', + disabled: !ticket.has_mob, + }, + { + name: 'VV', + act: 'VV', + icon: 'cog', + disabled: !ticket.has_mob, + }, + { + name: 'FLW', + act: 'FLW', + icon: 'arrow-up', + disabled: !ticket.has_mob, + }, + { + name: 'TP', + act: 'TP', + icon: 'book-dead', + disabled: !ticket.has_mob, + }, + { + name: 'Logs', + act: 'Logs', + icon: 'file', + disabled: !ticket.has_mob, + }, + ], + [ + { + name: 'Administer', + act: 'Administer', + icon: 'folder-open', + }, + { + name: 'Reject', + act: 'Reject', + icon: 'ban', + }, + { + name: ticket.is_resolved ? 'Unresolve' : 'Resolve', + act: 'Resolve', + icon: 'check', + }, + { + name: 'IC', + act: 'IC', + icon: 'male', + disabled: !ticket.has_client + }, + { + name: 'MHelp', + act: 'MHelp', + icon: 'info', + disabled: !ticket.has_client, + }, + ], + ]; + return (
Owner: @@ -102,112 +181,23 @@ export const TicketSummary = (props, context) => { {!ticket.has_client ? "DISCONNECTED" : ""}
- - - - - - - - - - - - - + {buttons.map(button_row => ( + + {button_row.map(button => ( + + + + ))} + + ))}
); diff --git a/tgui/packages/tgui/interfaces/TicketPanel.js b/tgui/packages/tgui/interfaces/TicketPanel.js index 026ebc2ffde9..90f05868ad02 100644 --- a/tgui/packages/tgui/interfaces/TicketPanel.js +++ b/tgui/packages/tgui/interfaces/TicketPanel.js @@ -1,153 +1,163 @@ import { useBackend, useLocalState } from '../backend'; -import { Section, Button, Table, Input, TextArea, Box } from '../components'; +import { Section, Button, Table, Input, TextArea, Box, Flex } from '../components'; import { Window } from '../layouts'; import { KEY_ENTER } from 'common/keycodes'; export const TicketPanel = (props, context) => { const { act, data } = useBackend(context); + const buttons = [ + [ + { + name: '', + act: 'adminmoreinfo', + icon: 'question', + disabled: !data.has_mob, + }, + { + name: 'PP', + act: 'PP', + icon: 'user', + disabled: !data.has_mob, + }, + { + name: 'VV', + act: 'VV', + icon: 'cog', + disabled: !data.has_mob, + }, + { + name: 'FLW', + act: 'FLW', + icon: 'arrow-up', + disabled: !data.has_mob, + }, + { + name: 'TP', + act: 'TP', + icon: 'book-dead', + disabled: !data.has_mob, + }, + { + name: 'Logs', + act: 'Logs', + icon: 'file', + disabled: !data.has_mob, + }, + { + name: 'Smite', + act: 'Smite', + icon: 'bolt', + disabled: !data.has_mob, + }, + ], + [ + { + name: 'Administer', + act: 'Administer', + icon: 'folder-open', + }, + { + name: data.popups ? 'Deactivate Popups' : 'Activate Popups', + act: 'togglePopups', + icon: 'window-restore', + selected: data.popups, + }, + { + name: 'Reject', + act: 'Reject', + icon: 'ban', + }, + ], + [ + { + name: data.is_resolved ? 'Unresolve' : 'Resolve', + act: 'Resolve', + icon: 'check', + }, + { + name: 'IC', + act: 'IC', + icon: 'male', + disabled: !data.has_client + }, + { + name: 'Wiki', + act: 'Wiki', + icon: 'film', + disabled: !data.has_mob + }, + { + name: 'Bug', + act: 'Bug', + icon: 'bug', + disabled: !data.has_mob, + }, + { + name: 'MHelp', + act: 'MHelp', + icon: 'info', + disabled: !data.has_client, + }, + ], + ]; if (data.is_admin) { return (
- - Assigned Admin: {data.admin || "Unassigned"}
- - Is{data.is_resolved ? "" : " not"} resolved + title={data.initiator_key_name + ': ' + data.name}> + + Assigned Admin: {data.admin || 'Unassigned'}
+ + Is{data.is_resolved ? '' : ' not'} resolved
+ level='2' + m='-5px'> Job: {data.role}
- Antag: {data.antag || "No"}
+ Antag: {data.antag || 'No'}
Location: {data.location}
- - - - - - - - -
- - - - - - - - - + m='-5px' + level='2' + inline='true' + > + {buttons.map(button_row => ( + + {button_row.map(button => ( + + + + ))} + + ))}
+ title='Messages' />
); } return ( @@ -168,23 +178,23 @@ export const TicketMessages = (props, context) => { const [ message, setMessage, - ] = useLocalState(context, 'text', ""); + ] = useLocalState(context, 'text', ''); return (
{ticket.log.map(entry => (!entry.for_admins || ticket.is_admin) && ( - + {entry.time} - {entry.user} - {entry.text} - ) || "")} + ) || '')} { if (e.keyCode === KEY_ENTER) { setMessage(''); @@ -195,7 +205,7 @@ export const TicketMessages = (props, context) => { } }} />
+ title="Messages" />
); } return ( @@ -185,13 +184,13 @@ export const TicketMessages = (props, context) => { lineHeight={1.25} title={title}> {ticket.log.map(entry => (!entry.for_admins || ticket.is_admin) && ( - + {entry.time} - {entry.user} - {entry.text} ) || '')} { } }} />