diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index a14106cafc..c78614ca43 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -218,7 +218,6 @@ var/global/floorIsLava = 0 /datum/player_info/var/content // text content of the information /datum/player_info/var/timestamp // Because this is bloody annoying -#define PLAYER_NOTES_ENTRIES_PER_PAGE 50 /datum/admins/proc/PlayerNotes() set category = "Admin" set name = "Player Notes" @@ -235,56 +234,20 @@ var/global/floorIsLava = 0 if (!istype(src,/datum/admins)) to_chat(usr, "Error: you are not an admin!") return - var/filter = input(usr, "Filter string (case-insensitive regex)", "Player notes filter") as text|null + var/filter = tgui_input_text(usr, "Filter string (case-insensitive regex)", "Player notes filter") PlayerNotesPage(1, filter) /datum/admins/proc/PlayerNotesPage(page, filter) - var/dat = "Player notes - Apply Filter
" var/savefile/S=new("data/player_notes.sav") var/list/note_keys S >> note_keys - if(!note_keys) - dat += "No notes found." - else - dat += "" + + if(note_keys) note_keys = sortList(note_keys) - if(filter) - var/list/results = list() - var/regex/needle = regex(filter, "i") - for(var/haystack in note_keys) - if(needle.Find(haystack)) - results += haystack - note_keys = results - - // Display the notes on the current page - var/number_pages = note_keys.len / PLAYER_NOTES_ENTRIES_PER_PAGE - // Emulate CEILING(why does BYOND not have ceil, 1) - if(number_pages != round(number_pages)) - number_pages = round(number_pages) + 1 - var/page_index = page - 1 - - if(page_index < 0 || page_index >= number_pages) - dat += "" - else - var/lower_bound = page_index * PLAYER_NOTES_ENTRIES_PER_PAGE + 1 - var/upper_bound = (page_index + 1) * PLAYER_NOTES_ENTRIES_PER_PAGE - upper_bound = min(upper_bound, note_keys.len) - for(var/index = lower_bound, index <= upper_bound, index++) - var/t = note_keys[index] - dat += "" - - dat += "
No keys found.
[t]

" - - // Display a footer to select different pages - for(var/index = 1, index <= number_pages, index++) - if(index == page) - dat += "" - dat += "[index] " - if(index == page) - dat += "" - - usr << browse(dat, "window=player_notes;size=400x400") + var/datum/tgui_module/player_notes/A = new(src) + A.ckeys = note_keys + A.tgui_interact(usr) /datum/admins/proc/player_has_info(var/key as text) @@ -303,44 +266,10 @@ var/global/floorIsLava = 0 if (!istype(src,/datum/admins)) to_chat(usr, "Error: you are not an admin!") return - var/dat = "Info on [key]" - dat += "" - - var/p_age = "unknown" - for(var/client/C in GLOB.clients) - if(C.ckey == key) - p_age = C.player_age - break - dat +="Player age: [p_age]
" - - var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") - var/list/infos - info >> infos - if(!infos) - dat += "No information found on the given key.
" - else - var/update_file = 0 - var/i = 0 - for(var/datum/player_info/I in infos) - i += 1 - if(!I.timestamp) - I.timestamp = "Pre-4/3/2012" - update_file = 1 - if(!I.rank) - I.rank = "N/A" - update_file = 1 - dat += "[I.content] by [I.author] ([I.rank]) on [I.timestamp] " - if(I.author == usr.key || I.author == "Adminbot" || ishost(usr)) - dat += "Remove" - dat += "

" - if(update_file) info << infos - - dat += "
" - dat += "Add Comment
" - - dat += "" - usr << browse(dat, "window=adminplayerinfo;size=480x480") + var/datum/tgui_module/player_notes_info/A = new(src) + A.key = key + A.tgui_interact(usr) /datum/admins/proc/access_news_network() //MARKER diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 3a8b32585a..3b4b817c00 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -2019,21 +2019,6 @@ // player info stuff - if(href_list["add_player_info"]) - var/key = href_list["add_player_info"] - var/add = sanitize(input(usr, "Add Player Info") as null|text) - if(!add) return - - notes_add(key,add,usr) - show_player_info(key) - - if(href_list["remove_player_info"]) - var/key = href_list["remove_player_info"] - var/index = text2num(href_list["remove_index"]) - - notes_del(key, index) - show_player_info(key) - if(href_list["notes"]) var/ckey = href_list["ckey"] if(!ckey) @@ -2043,7 +2028,9 @@ switch(href_list["notes"]) if("show") - show_player_info(ckey) + var/datum/tgui_module/player_notes_info/A = new(src) + A.key = ckey + A.tgui_interact(usr) if("list") var/filter if(href_list["filter"] && href_list["filter"] != "0") diff --git a/code/modules/tgui/modules/admin/player_notes.dm b/code/modules/tgui/modules/admin/player_notes.dm new file mode 100644 index 0000000000..492cc5288b --- /dev/null +++ b/code/modules/tgui/modules/admin/player_notes.dm @@ -0,0 +1,326 @@ +#define PLAYER_NOTES_ENTRIES_PER_PAGE 50 + +/datum/tgui_module/player_notes + name = "Player Notes" + tgui_id = "PlayerNotes" + + var/ckeys = list() + + var/current_filter = "" + var/current_page = 1 + + var/number_pages = 0 + +/datum/tgui_module/player_notes/proc/filter_ckeys(var/page, var/filter) + var/savefile/S=new("data/player_notes.sav") + var/list/note_keys + S >> note_keys + if(!note_keys) + to_chat(usr, "No notes found.") + else + note_keys = sortList(note_keys) + + if(filter) + var/list/results = list() + var/regex/needle = regex(filter, "i") + for(var/haystack in note_keys) + if(needle.Find(haystack)) + results += haystack + note_keys = results + + // Display the notes on the current page + number_pages = note_keys.len / PLAYER_NOTES_ENTRIES_PER_PAGE + // Emulate CEILING(why does BYOND not have ceil, 1) + if(number_pages != round(number_pages)) + number_pages = round(number_pages) + 1 + var/page_index = page - 1 + + if(page_index < 0 || page_index >= number_pages) + to_chat(usr, "No keys found.") + else + var/lower_bound = page_index * PLAYER_NOTES_ENTRIES_PER_PAGE + 1 + var/upper_bound = (page_index + 1) * PLAYER_NOTES_ENTRIES_PER_PAGE + upper_bound = min(upper_bound, note_keys.len) + ckeys = list() + for(var/index = lower_bound, index <= upper_bound, index++) + ckeys += note_keys[index] + + current_filter = filter + +/datum/tgui_module/player_notes/proc/open_legacy() + var/datum/admins/A = admin_datums[usr.ckey] + A.PlayerNotesLegacy() + +/datum/tgui_module/player_notes/tgui_state(mob/user) + return GLOB.tgui_admin_state + +/datum/tgui_module/player_notes/tgui_act(action, params, datum/tgui/ui) + if(..()) + return TRUE + + switch(action) + if("__fallback") + log_runtime(EXCEPTION("TGUI Fallback Triggered: \"[ui.user]\" tried to use/open \"[ui.title]/[ui.interface]\"! Trying to open legacy UI!")) + open_legacy() + + if("show_player_info") + var/datum/tgui_module/player_notes_info/A = new(src) + A.key = params["name"] + A.tgui_interact(usr) + + if("filter_player_notes") + var/input = tgui_input_text(usr, "Filter string (case-insensitive regex)", "Player notes filter") + current_filter = input + + if("set_page") + var/page = params["index"] + current_page = page + + if("clear_player_info_filter") + current_filter = "" + + if("open_legacy_ui") + open_legacy() + +/datum/tgui_module/player_notes/tgui_data(mob/user) + var/list/data = list() + + filter_ckeys(current_page, current_filter) + data["ckeys"] = list() + data["pages"] = number_pages + 1 + data["filter"] = current_filter + + for(var/ckey in ckeys) + data["ckeys"] += list(list( + "name" = ckey + )) + + return data + +// PLAYER NOTES INFO +/datum/tgui_module/player_notes_info + name = "Player Notes Info" + tgui_id = "PlayerNotesInfo" + + var/key = null + +/datum/tgui_module/player_notes_info/tgui_state(mob/user) + return GLOB.tgui_admin_state + +/datum/tgui_module/player_notes_info/tgui_act(action, params, datum/tgui/ui) + if(..()) + return TRUE + + switch(action) + if("__fallback") + var/datum/admins/A = admin_datums[usr.ckey] + A.show_player_info_legacy(key) + + if("add_player_info") + var/key = params["ckey"] + var/add = tgui_input_message(usr, "Write your comment below.", "Add Player Info") + if(!add) return + + notes_add(key,add,usr) + + if("remove_player_info") + var/key = params["ckey"] + var/index = params["index"] + + notes_del(key, index) + +/datum/tgui_module/player_notes_info/tgui_data(mob/user) + var/list/data = list() + + if(!key) + return + + var/p_age = "unknown" + for(var/client/C in GLOB.clients) + if(C.ckey == key) + p_age = C.player_age + break + + data["entries"] = list() + + var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") + var/list/infos + info >> infos + if(infos) + var/update_file = 0 + var/i = 0 + for(var/datum/player_info/I in infos) + i += 1 + if(!I.timestamp) + I.timestamp = "Pre-4/3/2012" + update_file = 1 + if(!I.rank) + I.rank = "N/A" + update_file = 1 + + data["entries"] += list(list( + "comment" = I.content, + "author" = "[I.author] ([I.rank])", + "date" = "[I.timestamp]" + )) + if(update_file) info << infos + + data["ckey"] = key + data["age"] = p_age + + return data + +// ==== LEGACY UI ==== + +/datum/admins/proc/PlayerNotesLegacy() + if (!istype(src,/datum/admins)) + src = usr.client.holder + if (!istype(src,/datum/admins)) + to_chat(usr, "Error: you are not an admin!") + return + PlayerNotesPageLegacy(1) + +/datum/admins/proc/PlayerNotesFilterLegacy() + if (!istype(src,/datum/admins)) + src = usr.client.holder + if (!istype(src,/datum/admins)) + to_chat(usr, "Error: you are not an admin!") + return + var/filter = input(usr, "Filter string (case-insensitive regex)", "Player notes filter") as text|null + PlayerNotesPageLegacy(1, filter) + +/datum/admins/proc/PlayerNotesPageLegacy(page, filter) + var/dat = "Player notes - Apply Filter
" + var/savefile/S=new("data/player_notes.sav") + var/list/note_keys + S >> note_keys + if(!note_keys) + dat += "No notes found." + else + dat += "" + note_keys = sortList(note_keys) + + if(filter) + var/list/results = list() + var/regex/needle = regex(filter, "i") + for(var/haystack in note_keys) + if(needle.Find(haystack)) + results += haystack + note_keys = results + + // Display the notes on the current page + var/number_pages = note_keys.len / PLAYER_NOTES_ENTRIES_PER_PAGE + // Emulate CEILING(why does BYOND not have ceil, 1) + if(number_pages != round(number_pages)) + number_pages = round(number_pages) + 1 + var/page_index = page - 1 + + if(page_index < 0 || page_index >= number_pages) + dat += "" + else + var/lower_bound = page_index * PLAYER_NOTES_ENTRIES_PER_PAGE + 1 + var/upper_bound = (page_index + 1) * PLAYER_NOTES_ENTRIES_PER_PAGE + upper_bound = min(upper_bound, note_keys.len) + for(var/index = lower_bound, index <= upper_bound, index++) + var/t = note_keys[index] + dat += "" + + dat += "
No keys found.
[t]

" + + // Display a footer to select different pages + for(var/index = 1, index <= number_pages, index++) + if(index == page) + dat += "" + dat += "[index] " + if(index == page) + dat += "" + + usr << browse(dat, "window=player_notes;size=400x400") + +/datum/admins/proc/player_has_info_legacy(var/key as text) + var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") + var/list/infos + info >> infos + if(!infos || !infos.len) return 0 + else return 1 + +/datum/admins/proc/show_player_info_legacy(var/key as text) + if (!istype(src,/datum/admins)) + src = usr.client.holder + if (!istype(src,/datum/admins)) + to_chat(usr, "Error: you are not an admin!") + return + var/dat = "Info on [key]" + dat += "" + + var/p_age = "unknown" + for(var/client/C in GLOB.clients) + if(C.ckey == key) + p_age = C.player_age + break + dat +="Player age: [p_age]
" + + var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") + var/list/infos + info >> infos + if(!infos) + dat += "No information found on the given key.
" + else + var/update_file = 0 + var/i = 0 + for(var/datum/player_info/I in infos) + i += 1 + if(!I.timestamp) + I.timestamp = "Pre-4/3/2012" + update_file = 1 + if(!I.rank) + I.rank = "N/A" + update_file = 1 + dat += "[I.content] by [I.author] ([I.rank]) on [I.timestamp] " + if(I.author == usr.key || I.author == "Adminbot" || ishost(usr)) + dat += "Remove" + dat += "

" + if(update_file) info << infos + + dat += "
" + dat += "Add Comment
" + + dat += "" + usr << browse(dat, "window=adminplayerinfo;size=480x480") + +/datum/admins/Topic(href, href_list) + ..() + + if(href_list["add_player_info_legacy"]) + var/key = href_list["add_player_info_legacy"] + var/add = sanitize(input(usr, "Add Player Info (Legacy)") as null|text) + if(!add) return + + notes_add(key,add,usr) + show_player_info_legacy(key) + + if(href_list["remove_player_info_legacy"]) + var/key = href_list["remove_player_info_legacy"] + var/index = text2num(href_list["remove_index"]) + + notes_del(key, index) + show_player_info_legacy(key) + + if(href_list["notes_legacy"]) + var/ckey = href_list["ckey"] + if(!ckey) + var/mob/M = locate(href_list["mob"]) + if(ismob(M)) + ckey = M.ckey + + switch(href_list["notes_legacy"]) + if("show") + show_player_info_legacy(ckey) + if("list") + var/filter + if(href_list["filter"] && href_list["filter"] != "0") + filter = url_decode(href_list["filter"]) + PlayerNotesPageLegacy(text2num(href_list["index"]), filter) + if("filter") + PlayerNotesFilterLegacy() + return \ No newline at end of file diff --git a/tgui/packages/tgui-panel/Notifications.js b/tgui/packages/tgui-panel/Notifications.js deleted file mode 100644 index a64ddd8e30..0000000000 --- a/tgui/packages/tgui-panel/Notifications.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * @file - * @copyright 2020 Aleksej Komarov - * @license MIT - */ - -import { Flex } from 'tgui/components'; - -export const Notifications = props => { - const { children } = props; - return ( -
- {children} -
- ); -}; - -const NotificationsItem = props => { - const { - rightSlot, - children, - } = props; - return ( - - - {children} - - {rightSlot && ( - - {rightSlot} - - )} - - ); -}; - -Notifications.Item = NotificationsItem; diff --git a/tgui/packages/tgui-panel/Panel.js b/tgui/packages/tgui-panel/Panel.js deleted file mode 100644 index d6cc9eb7ef..0000000000 --- a/tgui/packages/tgui-panel/Panel.js +++ /dev/null @@ -1,138 +0,0 @@ -/** - * @file - * @copyright 2020 Aleksej Komarov - * @license MIT - */ - -import { Button, Section, Stack } from 'tgui/components'; -import { Pane } from 'tgui/layouts'; -import { NowPlayingWidget, useAudio } from './audio'; -import { ChatPanel, ChatTabs } from './chat'; -import { useGame } from './game'; -import { Notifications } from './Notifications'; -import { PingIndicator } from './ping'; -import { SettingsPanel, useSettings } from './settings'; - -export const Panel = (props, context) => { - // IE8-10: Needs special treatment due to missing Flex support - if (Byond.IS_LTE_IE10) { - return ( - - ); - } - const audio = useAudio(context); - const settings = useSettings(context); - const game = useGame(context); - if (process.env.NODE_ENV !== 'production') { - const { useDebug, KitchenSink } = require('tgui/debug'); - const debug = useDebug(context); - if (debug.kitchenSink) { - return ( - - ); - } - } - return ( - - - -
- - - - - - - - -
-
- {audio.visible && ( - -
- -
-
- )} - {settings.visible && ( - - - - )} - -
- - - - - {game.connectionLostAt && ( - Byond.command('.reconnect')}> - Reconnect - - )}> - You are either AFK, experiencing lag or the connection - has closed. - - )} - {game.roundRestartedAt && ( - - The connection has been closed because the server is - restarting. Please wait while you automatically reconnect. - - )} - -
-
-
-
- ); -}; - -const HoboPanel = (props, context) => { - const settings = useSettings(context); - return ( - - - - {settings.visible && ( - - ) || ( - - )} - - - ); -}; diff --git a/tgui/packages/tgui-panel/audio/NowPlayingWidget.js b/tgui/packages/tgui-panel/audio/NowPlayingWidget.js deleted file mode 100644 index e4fe04eed1..0000000000 --- a/tgui/packages/tgui-panel/audio/NowPlayingWidget.js +++ /dev/null @@ -1,68 +0,0 @@ -/** - * @file - * @copyright 2020 Aleksej Komarov - * @license MIT - */ - -import { toFixed } from 'common/math'; -import { useDispatch, useSelector } from 'common/redux'; -import { Button, Flex, Knob } from 'tgui/components'; -import { useSettings } from '../settings'; -import { selectAudio } from './selectors'; - -export const NowPlayingWidget = (props, context) => { - const audio = useSelector(context, selectAudio); - const dispatch = useDispatch(context); - const settings = useSettings(context); - const title = audio.meta?.title; - return ( - - {audio.playing && ( - <> - - Now playing: - - - {title || 'Unknown Track'} - - - ) || ( - - Nothing to play. - - )} - {audio.playing && ( - - - - - -
- {MESSAGE_TYPES - .filter(typeDef => !typeDef.important && !typeDef.admin) - .map(typeDef => ( - dispatch(toggleAcceptedType({ - pageId: page.id, - type: typeDef.type, - }))}> - {typeDef.name} - - ))} - - {MESSAGE_TYPES - .filter(typeDef => !typeDef.important && typeDef.admin) - .map(typeDef => ( - dispatch(toggleAcceptedType({ - pageId: page.id, - type: typeDef.type, - }))}> - {typeDef.name} - - ))} - -
- - ); -}; diff --git a/tgui/packages/tgui-panel/chat/ChatPanel.js b/tgui/packages/tgui-panel/chat/ChatPanel.js deleted file mode 100644 index 0a5deaf9fe..0000000000 --- a/tgui/packages/tgui-panel/chat/ChatPanel.js +++ /dev/null @@ -1,71 +0,0 @@ -/** - * @file - * @copyright 2020 Aleksej Komarov - * @license MIT - */ - -import { shallowDiffers } from 'common/react'; -import { Component, createRef } from 'inferno'; -import { Button } from 'tgui/components'; -import { chatRenderer } from './renderer'; - -export class ChatPanel extends Component { - constructor() { - super(); - this.ref = createRef(); - this.state = { - scrollTracking: true, - }; - this.handleScrollTrackingChange = value => this.setState({ - scrollTracking: value, - }); - } - - componentDidMount() { - chatRenderer.mount(this.ref.current); - chatRenderer.events.on('scrollTrackingChanged', - this.handleScrollTrackingChange); - this.componentDidUpdate(); - } - - componentWillUnmount() { - chatRenderer.events.off('scrollTrackingChanged', - this.handleScrollTrackingChange); - } - - componentDidUpdate(prevProps) { - requestAnimationFrame(() => { - chatRenderer.ensureScrollTracking(); - }); - const shouldUpdateStyle = ( - !prevProps || shallowDiffers(this.props, prevProps) - ); - if (shouldUpdateStyle) { - chatRenderer.assignStyle({ - 'width': '100%', - 'white-space': 'pre-wrap', - 'font-size': this.props.fontSize, - 'line-height': this.props.lineHeight, - }); - } - } - - render() { - const { - scrollTracking, - } = this.state; - return ( - <> -
- {!scrollTracking && ( - - )} - - ); - } -} diff --git a/tgui/packages/tgui-panel/chat/ChatTabs.js b/tgui/packages/tgui-panel/chat/ChatTabs.js deleted file mode 100644 index a0e6cc59e5..0000000000 --- a/tgui/packages/tgui-panel/chat/ChatTabs.js +++ /dev/null @@ -1,61 +0,0 @@ -/** - * @file - * @copyright 2020 Aleksej Komarov - * @license MIT - */ - -import { useDispatch, useSelector } from 'common/redux'; -import { Box, Tabs, Flex, Button } from 'tgui/components'; -import { changeChatPage, addChatPage } from './actions'; -import { selectChatPages, selectCurrentChatPage } from './selectors'; -import { openChatSettings } from '../settings/actions'; - -const UnreadCountWidget = ({ value }) => ( - - {Math.min(value, 99)} - -); - -export const ChatTabs = (props, context) => { - const pages = useSelector(context, selectChatPages); - const currentPage = useSelector(context, selectCurrentChatPage); - const dispatch = useDispatch(context); - return ( - - - - {pages.map(page => ( - 0 && ( - - )} - onClick={() => dispatch(changeChatPage({ - pageId: page.id, - }))}> - {page.name} - - ))} - - - -