Fixes most tgui bugs (#16539)

* Fixes most tgui bugs

* the soul longs for oblivion

* skin fix

* hardsuit fix

* b

* the final fixes (for now)

* bb

* fix keys

* cl

* fuck off

* i'm alone i'm alone i'm alone

* the heart's whisper

* fffss

* je cherche la vérité tout en l'évitant

---------

Co-authored-by: Matt Atlas <liermattia@gmail.com>
This commit is contained in:
Matt Atlas
2023-06-26 15:36:11 +02:00
committed by GitHub
parent c6d87cc68e
commit 025b6e66d5
50 changed files with 672 additions and 463 deletions
+2 -2
View File
@@ -77,7 +77,7 @@ var/datum/controller/subsystem/statpanels/SSstatpanels
update_actions = TRUE
// We're not on a spell tab per se, but we have something fitting.
if(!length(target.spell_tabs) && locate(/obj/item/rig) in target_mob.contents)
if(!length(target.spell_tabs) && istype(target_mob.back, /obj/item/rig))
update_actions = TRUE
if(update_actions && num_fires % default_wait == 0)
@@ -109,7 +109,7 @@ var/datum/controller/subsystem/statpanels/SSstatpanels
target.stat_panel.send_message("update_mc", list(mc_data = mc_data, "coord_entry" = coord_entry))
/// Set up the various action tabs.
/datum/controller/subsystem/statpanels/proc/set_action_tabs (client/target, mob/target_mob)
/datum/controller/subsystem/statpanels/proc/set_action_tabs(client/target, mob/target_mob)
var/list/actions = target_mob.get_actions_for_statpanel()
target.spell_tabs.Cut()
+1
View File
@@ -112,6 +112,7 @@
new_character.make_vampire()
if(active)
new_character.key = key //now transfer the key to link the client to our new body
/datum/mind/proc/store_memory(new_text)
. = length(memory + new_text)
@@ -108,6 +108,7 @@
QDEL_IN(effect, 10)
H.forceMove(ling)
H.status_flags |= GODMODE
ling.client.init_verbs()
feedback_add_details("changeling_powers", "LF")
return TRUE
@@ -511,6 +512,7 @@
M.forceMove(ling) //move inside the new dude to hide him.
ling.occupant = M
M.status_flags |= GODMODE //dont want him to die or breathe or do ANYTHING
ling.client.init_verbs()
// Chiropteran Screech
/mob/proc/resonant_shriek()
+2 -2
View File
@@ -31,9 +31,9 @@
return B
/obj/item/material/sword/cultify()
var/obj/item/melee/cultblade/CBT = new /obj/item/melee/cultblade(get_turf(src)) // AHAHAHAHAHAHAHA - Geeves
var/obj/item/melee/cultblade/A = new /obj/item/melee/cultblade(get_turf(src))
qdel(src)
return CBT
return A
/obj/item/storage/backpack/cultify()
var/obj/item/storage/backpack/cultpack/CP = new /obj/item/storage/backpack/cultpack(get_turf(src))
+6
View File
@@ -550,3 +550,9 @@ Class Procs:
return
else
visible_message(SPAN_DANGER("\The [src] was hit by \the [AM]."))
/obj/machinery/ui_status(mob/user, datum/ui_state/state)
. = ..()
if(. < UI_INTERACTIVE)
if(user.machine)
user.unset_machine()
+3 -4
View File
@@ -368,10 +368,9 @@
if(panel_open)
wires.Interact(user)
user << browse(dat, "window=suit_cycler")
onclose(user, "suit_cycler")
return
var/datum/browser/suit_cycler = new(user, "suit_cycler", "Suit Cycler", 450, 500)
suit_cycler.set_content(dat)
suit_cycler.open()
/obj/machinery/suit_cycler/Topic(href, href_list)
if(!Adjacent(usr) && !issilicon(usr))
@@ -73,7 +73,7 @@
/obj/item/device/transfer_valve/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "TransferVavle", ui_x=540, ui_y=165)
ui = new(user, src, "TransferValve", ui_x=540, ui_y=165)
ui.open()
/obj/item/device/transfer_valve/ui_data(mob/user)
@@ -120,6 +120,8 @@
addtimer(CALLBACK(src, PROC_REF(bst_post_spawn), bst), 5)
addtimer(CALLBACK(src, PROC_REF(bst_spawn_cooldown)), 5 SECONDS)
bst.client.init_verbs()
log_debug("Bluespace Tech Spawned: X:[bst.x] Y:[bst.y] Z:[bst.z] User:[src]")
feedback_add_details("admin_verb","BST")
@@ -166,6 +168,7 @@
if(key)
if(client.holder && client.holder.original_mob)
client.holder.original_mob.key = key
client.init_verbs()
else
var/mob/abstract/observer/ghost = new(src) //Transfer safety to observer spawning proc.
ghost.key = key
@@ -173,6 +176,7 @@
ghost.name = "[ghost.key] BSTech"
ghost.real_name = "[ghost.key] BSTech"
ghost.voice_name = "[ghost.key] BSTech"
ghost.client.init_verbs()
/mob/living/carbon/human/bst/proc/bsc() //because we all have our unrealistic snowflakes right?
if(set_species(SPECIES_TAJARA))
@@ -347,6 +347,7 @@
update_icon(1)
if(is_in_cycler)
initiator.loc.update_icon()
SSstatpanels.set_action_tabs(initiator.client, initiator)
/obj/item/rig/proc/update_component_sealed()
for(var/obj/item/piece in list(helmet,boots,gloves,chest))
@@ -768,6 +769,7 @@
/obj/item/rig/dropped(var/mob/user)
..()
SSstatpanels.set_action_tabs(user.client, user)
null_wearer(user)
@@ -330,6 +330,7 @@
remove_verb(observer, /mob/abstract/observer/verb/toggle_antagHUD)
observer.ckey = ckey
observer.initialise_postkey()
observer.client.init_verbs()
qdel(src)
/mob/abstract/new_player/proc/show_lore_summary()
@@ -376,6 +376,8 @@ INITIALIZE_IMMEDIATE(/mob/abstract/new_player)
new_character.key = key //Manually transfer the key to log them in
new_character.client.init_verbs()
return new_character
/mob/abstract/new_player/proc/ViewManifest()
@@ -235,10 +235,10 @@ Works together with spawning an observer, noted above.
ghost.ckey = ckey
ghost.initialise_postkey(should_set_timer)
ghost.client?.init_verbs()
if(ghost.client)
if(!ghost.client.holder && !config.antag_hud_allowed) // For new ghosts we remove the verb from even showing up if it's not allowed.
remove_verb(ghost, /mob/abstract/observer/verb/toggle_antagHUD) // Poor guys, don't know what they are missing!
ghost.client.init_verbs()
return ghost
/*
@@ -77,6 +77,8 @@
set_stat(CONSCIOUS)
gestalt = adult
adult.client.init_verbs()
//What do you call a person with no arms or no legs?
var/list/organ_removal_priorities = list(BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG)
var/limbs_to_remove = (6 - limbs_can_grow)
@@ -1220,6 +1220,7 @@
if(H.brainmob.real_name == src.real_name)
if(H.brainmob.mind)
H.brainmob.mind.transfer_to(src)
H.brainmob.client.init_verbs()
qdel(H)
losebreath = 0
@@ -528,6 +528,7 @@
to_chat(src, "<b>Systems rebooted</b>. Loading base pattern maintenance protocol... <b>loaded</b>.")
full_law_reset()
welcome_drone()
client.init_verbs()
/mob/living/silicon/robot/drone/proc/welcome_drone()
to_chat(src, SPAN_NOTICE("<b>You are a maintenance drone, a tiny-brained robotic repair machine</b>."))
@@ -4,11 +4,11 @@
show_laws(0)
if(client.prefs.toggles_secondary & HOTKEY_DEFAULT)
winset(src, null, "mainwindow.macro=borghotkeymode hotkey_toggle.is-checked=true mapwindow.map.focus=true input.background-color=#D3B5B5")
winset(src, null, "mainwindow.macro=borghotkeymode hotkey_toggle.is-checked=true mapwindow.map.focus=true")
else
winset(src, null, "mainwindow.macro=borgmacro hotkey_toggle.is-checked=false input.focus=true input.background-color=#D3B5B5")
winset(src, null, "mainwindow.macro=borgmacro hotkey_toggle.is-checked=false input.focus=true")
// Forces synths to select an icon relevant to their module
if(module && !icon_selected)
choose_icon()
set_intent(a_intent) // to set the eye colour
set_intent(a_intent) // to set the eye colour
@@ -1291,3 +1291,6 @@
to_chat(src, SPAN_NOTICE("You have given up life and succumbed to death."))
else
to_chat(src, SPAN_NOTICE("You are not injured enough to succumb to death!"))
/mob/living/silicon/robot/GetIdCard()
return id_card
+2 -2
View File
@@ -86,9 +86,9 @@
//set macro to normal incase it was overriden (like cyborg currently does)
if(client.prefs.toggles_secondary & HOTKEY_DEFAULT)
winset(src, null, "mainwindow.macro=hotkeymode hotkey_toggle.is-checked=true mapwindow.map.focus=true input.background-color=#D3B5B5")
winset(src, null, "mainwindow.macro=hotkeymode hotkey_toggle.is-checked=true mapwindow.map.focus=true")
else
winset(src, null, "mainwindow.macro=macro hotkey_toggle.is-checked=false input.focus=true input.background-color=#D3B5B5")
winset(src, null, "mainwindow.macro=macro hotkey_toggle.is-checked=false input.focus=true")
MOB_STOP_THINKING(src)
clear_important_client_contents(client)
+4 -1
View File
@@ -543,6 +543,7 @@
M.key = key
if(M.mind)
M.mind.reset()
M.client.init_verbs()
return
/client/verb/changes()
@@ -551,7 +552,9 @@
var/datum/asset/changelog = get_asset_datum(/datum/asset/simple/changelog)
changelog.send(src)
src << browse('html/changelog.html', "window=changes;size=675x650")
var/datum/browser/changelog_win = new(src, "changes", "Changelog", 675, 650)
changelog_win.set_content('html/changelog.html')
changelog_win.open()
if(prefs.lastchangelog != changelog_hash)
prefs.lastchangelog = changelog_hash
prefs.save_preferences()
+5 -1
View File
@@ -143,6 +143,8 @@
O.add_ai_verbs()
O.rename_self("ai",1)
O.client.init_verbs()
spawn(0) // Mobs still instantly del themselves, thus we need to spawn or O will never be returned
qdel(src)
return O
@@ -170,7 +172,7 @@
O.gender = gender
O.set_invisibility(0)
if(mind) //TODO
mind.transfer_to(O)
if(O.mind.assigned_role == "Cyborg")
@@ -194,6 +196,8 @@
callHook("borgify", list(O))
O.Namepick()
if(O.client)
O.client.init_verbs()
spawn(0) // Mobs still instantly del themselves, thus we need to spawn or O will never be returned
qdel(src)
@@ -200,6 +200,7 @@
// On-click handling. Turns on the computer if it's off and opens the GUI.
/obj/item/modular_computer/attack_self(mob/user)
if(enabled && screen_on)
user.set_machine(src)
ui_interact(user)
else if(!enabled && screen_on)
turn_on(user)
@@ -183,3 +183,9 @@
. = TRUE
update_icon()
/obj/item/modular_computer/ui_status(mob/user, datum/ui_state/state)
. = ..()
if(. < UI_INTERACTIVE)
if(user.machine)
user.unset_machine()
@@ -16,7 +16,7 @@
tgui_theme = "hephaestus"
ui_auto_update = FALSE
/datum/computer_file/program/rcon_console/ui_static_data(mob/user)
/datum/computer_file/program/rcon_console/ui_data(mob/user)
var/list/data = initial_data()
var/list/smeslist = list()
@@ -246,6 +246,12 @@
if("security")
if(!(edit_type & RECORD_SECURITY))
return FALSE
if("fingerprint")
if(!(edit_type & RECORD_SECURITY))
return FALSE
if("criminal")
if(!(edit_type & RECORD_SECURITY))
return FALSE
if("physical_status")
if(!((edit_type & RECORD_MEDICAL) || (edit_type & RECORD_GENERAL)))
return FALSE
@@ -255,6 +261,24 @@
if("medical")
if(!(edit_type & RECORD_MEDICAL))
return FALSE
if("diseases")
if(!(edit_type & RECORD_MEDICAL))
return FALSE
if("allergies")
if(!(edit_type & RECORD_MEDICAL))
return FALSE
if("blood_dna")
if(!(edit_type & RECORD_MEDICAL) || (edit_type & RECORD_SECURITY))
return FALSE
if("species")
if(!(edit_type & RECORD_MEDICAL) || (edit_type & RECORD_SECURITY))
return FALSE
if("citizenship")
if(!(edit_type & RECORD_SECURITY) || (edit_type & RECORD_GENERAL))
return FALSE
if("religion")
if(!(edit_type & RECORD_SECURITY) || (edit_type & RECORD_GENERAL))
return FALSE
else
if(!(edit_type & RECORD_GENERAL))
return FALSE
@@ -46,7 +46,7 @@
switch(action)
if("sw_menu")
active_warrant = null
. = TRUE
SStgui.update_uis(computer)
if("editwarrant")
for(var/datum/record/warrant/W in SSrecords.warrants)
@@ -56,8 +56,8 @@
. = TRUE
if("back")
. = TRUE
active_warrant = null
SStgui.update_uis(computer)
// The following actions will only be possible if the user has an ID with security access equipped. This is in line with modular computer framework's authentication methods,
// which also use RFID scanning to allow or disallow access to some functions. Anyone can view warrants, editing requires ID.
@@ -96,14 +96,14 @@
active_warrant = W
if("savewarrant")
. = TRUE
SSrecords.update_record(active_warrant)
active_warrant = null
SStgui.update_uis(computer)
if("deletewarrant")
. = TRUE
SSrecords.remove_record(active_warrant)
active_warrant = null
SStgui.update_uis(computer)
if("editwarrantname")
. = TRUE
@@ -613,6 +613,7 @@
M.mind.transfer_to(new_mob)
else
new_mob.key = M.key
new_mob.client.init_verbs()
qdel(M)
/singleton/reagent/toxin/nanites
@@ -0,0 +1,41 @@
################################
# Example Changelog File
#
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
#
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
# When it is, any changes listed below will disappear.
#
# Valid Prefixes:
# bugfix
# wip (For works in progress)
# tweak
# soundadd
# sounddel
# rscadd (general adding of nice things)
# rscdel (general deleting of nice things)
# imageadd
# imagedel
# maptweak
# spellcheck (typo fixes)
# experiment
# balance
# admin
# backend
# security
# refactor
#################################
# Your name.
author: MattAtlas
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
delete-after: True
# Any changes you've made. See valid prefix list above.
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
# SCREW THIS UP AND IT WON'T WORK.
# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
changes:
- bugfix: "Fixed most of the early bugs with TGUI."
+1 -1
View File
@@ -631,7 +631,7 @@ macro "hotkeymode"
macro "borgmacro"
elem
name = "TAB"
command = ".winset \"mainwindow.macro=borghotkeymode hotkey_toggle.is-checked=true mapwindow.map.focus=true input.background-color=#F0F0F0\""
command = ".winset \"mainwindow.macro=borghotkeymode hotkey_toggle.is-checked=true mapwindow.map.focus=true""
elem
name = "CENTER+REP"
command = ".center"
@@ -335,11 +335,14 @@ em {
}
.ooc .everyone {
color: #002eb8;
color: #3c5dc0;
}
.ooc .looc {
color: #6699cc;
}
.ooc .adminlooc {
color: #3bbf6e;
}
.ooc .elevated {
color: #2e78d9;
}
@@ -347,11 +350,14 @@ em {
color: #184880;
}
.ooc .developer {
color: #1b521f;
color: #2c7731;
}
.ooc .admin {
color: #b82e00;
}
.aooc {
color: #d1021e;
}
/* Admin: Private Messages */
.pm .howto {
@@ -1,4 +1,4 @@
/**
f/**
* Copyright (c) 2020 Aleksej Komarov
* SPDX-License-Identifier: MIT
*/
@@ -216,6 +216,7 @@ a.popt {
.motd {
color: #a4bad6;
font-family: Verdana, sans-serif;
white-space: 'normal';
}
.motd h1,
.motd h2,
@@ -223,12 +224,9 @@ a.popt {
.motd h4,
.motd h5,
.motd h6 {
color: #a4bad6;
color: #638500;
text-decoration: underline;
}
.vote {
color: #9933ff;
}
.motd a,
.motd a:link,
.motd a:visited,
@@ -268,9 +266,9 @@ h3,
h4,
h5,
h6 {
color: #a4bad6;
color: #0000ff;
font-family: Georgia, Verdana, sans-serif;
margin-bottom: 20%;
line-height: 10%;
}
em {
@@ -467,6 +465,9 @@ em {
.alert {
color: #ff0000;
}
.vote {
color: #6c18c0;
}
h1.alert,
h2.alert {
color: #000080;
@@ -536,6 +537,18 @@ h2.alert {
.vaurca {
color: #9e9e39;
}
.vaurca_zora {
color: #9e3939;
}
.vaurca_cthur {
color: #39719e;
}
.vaurca_klax {
color: #399e4a;
}
.vaurca_liidra {
color: #b350b3;
}
.soghun {
color: #228b22;
}
@@ -558,7 +571,7 @@ h2.alert {
font-family: Georgia, Verdana, sans-serif;
}
.yassa {
color: #400987;
color: #801fff;
}
.delvahhi {
color: #5e2612;
@@ -567,6 +580,10 @@ h2.alert {
.siiktau {
color: #a52a2a;
}
.revenant {
color: #215a5c;
font-style: italic;
}
.freespeak {
color: #ff4500;
font-family: 'Trebuchet MS', cursive, sans-serif;
@@ -576,6 +593,11 @@ h2.alert {
font-family: Georgia, Verdana, sans-serif;
}
.singing {
font-family: 'Trebuchet MS', cursive, sans-serif;
font-style: italic;
}
.interface {
color: #750e75;
}
+140 -128
View File
@@ -144,13 +144,13 @@ export const AccountWindow = (props, context) => {
</Section>
</>
) : (
<SpecificAccount />
<SpecificAccountData />
)}
</Section>
);
};
export const SpecificAccount = (props, context) => {
export const SpecificAccountData = (props, context) => {
const { act, data } = useBackend<DatabaseData>(context);
const [active, setActive] = useLocalState(context, 'active', 'none');
const [tab, setTab] = useLocalState(context, 'tab', 'All Accounts');
@@ -171,138 +171,150 @@ export const SpecificAccount = (props, context) => {
0
);
return data.accounts.map((account) =>
account.account_number === active ? (
<Section
title="Account Details"
buttons={
<>
<Button
content={account.suspended ? 'Unsuspend' : 'Suspend'}
icon="exclamation-circle"
color="red"
onClick={() =>
act('suspend', { account: account.account_number })
}
/>
<Button
content="Revoke Payroll"
disabled={account.account_number === data.station_account_number}
icon="minus"
color="average"
onClick={() =>
act('revoke_payroll', { account: account.account_number })
}
/>
<Button
content="Print"
icon="print"
onClick={() => act('print', { print: account.account_number })}
/>
</>
}>
<LabeledList>
<LabeledList.Item label="Number">
{account.account_number}
</LabeledList.Item>
<LabeledList.Item label="Holder">{account.owner}</LabeledList.Item>
<LabeledList.Item label="Balance">{account.money}</LabeledList.Item>
<LabeledList.Item label="Status">
<Box as="span" color={account.suspended ? 'red' : 'good'}>
{account.suspended ? 'Suspended' : 'Active'}
</Box>
</LabeledList.Item>
{data.access_level === 2 ? (
<LabeledList.Item label="Fund Adjustment">
{!adding_funds ? (
return (
<Section>
{data.accounts.map((account) =>
account.account_number === active ? (
<Section
title="Account Details"
buttons={
<>
<Button
content="Add"
color="good"
icon="plus"
onClick={() => setAdding(1)}
content={account.suspended ? 'Unsuspend' : 'Suspend'}
icon="exclamation-circle"
color="red"
onClick={() =>
act('suspend', { account: account.account_number })
}
/>
) : (
<>
<NumberInput
value={funds_to_add}
unit="电"
minValue={0}
maxValue={10000}
onDrag={(e, value) => setFundsToAdd(value)}
/>
<Button
content="Add"
color="good"
icon="plus"
onClick={() =>
act('add_funds', {
account: account.account_number,
amount: funds_to_add,
})
}
/>
</>
)}
&nbsp;
{!adding_funds ? (
<Button
content="Remove"
color="bad"
content="Revoke Payroll"
disabled={
account.account_number === data.station_account_number
}
icon="minus"
onClick={() => setRemoving(1)}
color="average"
onClick={() =>
act('revoke_payroll', { account: account.account_number })
}
/>
<Button
content="Print"
icon="print"
onClick={() =>
act('print', { print: account.account_number })
}
/>
</>
}>
<LabeledList>
<LabeledList.Item label="Number">
{account.account_number}
</LabeledList.Item>
<LabeledList.Item label="Holder">
{account.owner}
</LabeledList.Item>
<LabeledList.Item label="Balance">
{account.money}
</LabeledList.Item>
<LabeledList.Item label="Status">
<Box as="span" color={account.suspended ? 'red' : 'good'}>
{account.suspended ? 'Suspended' : 'Active'}
</Box>
</LabeledList.Item>
{data.access_level === 2 ? (
<LabeledList.Item label="Fund Adjustment">
{!adding_funds ? (
<Button
content="Add"
color="good"
icon="plus"
onClick={() => setAdding(1)}
/>
) : (
<>
<NumberInput
value={funds_to_add}
unit="电"
minValue={0}
maxValue={10000}
onDrag={(e, value) => setFundsToAdd(value)}
/>
<Button
content="Add"
color="good"
icon="plus"
onClick={() =>
act('add_funds', {
account: account.account_number,
amount: funds_to_add,
})
}
/>
</>
)}
&nbsp;
{!adding_funds ? (
<Button
content="Remove"
color="bad"
icon="minus"
onClick={() => setRemoving(1)}
/>
) : (
<>
<NumberInput
value={funds_to_remove}
unit="电"
minValue={0}
maxValue={10000}
onDrag={(e, value) => setFundsToRemove(value)}
/>
<Button
content="Remove"
color="bad"
icon="minus"
onClick={() =>
act('remove_funds', {
account: account.account_number,
amount: funds_to_add,
})
}
/>
</>
)}
</LabeledList.Item>
) : (
<>
<NumberInput
value={funds_to_remove}
unit="电"
minValue={0}
maxValue={10000}
onDrag={(e, value) => setFundsToRemove(value)}
/>
<Button
content="Remove"
color="bad"
icon="minus"
onClick={() =>
act('remove_funds', {
account: account.account_number,
amount: funds_to_add,
})
}
/>
</>
''
)}
</LabeledList.Item>
) : (
''
)}
</LabeledList>
<Section title="Transactions">
<Table>
<Table.Row header>
<Table.Cell>Timestamp</Table.Cell>
<Table.Cell>Target</Table.Cell>
<Table.Cell>Reason</Table.Cell>
<Table.Cell>Value</Table.Cell>
<Table.Cell>Terminal</Table.Cell>
</Table.Row>
{account.transactions.map((transaction) => (
<Table.Row key={transaction.ref}>
<Table.Cell>
{transaction.date + ', ' + transaction.time}
</Table.Cell>
<Table.Cell>{transaction.target_name}</Table.Cell>
<Table.Cell>{transaction.purpose}</Table.Cell>
<Table.Cell>{transaction.amount}</Table.Cell>
<Table.Cell>{transaction.source_terminal}</Table.Cell>
</Table.Row>
))}
</Table>
</Section>
</Section>
) : (
''
)
</LabeledList>
<Section title="Transactions">
<Table>
<Table.Row header>
<Table.Cell>Timestamp</Table.Cell>
<Table.Cell>Target</Table.Cell>
<Table.Cell>Reason</Table.Cell>
<Table.Cell>Value</Table.Cell>
<Table.Cell>Terminal</Table.Cell>
</Table.Row>
{account.transactions.map((transaction) => (
<Table.Row key={transaction.ref}>
<Table.Cell>
{transaction.date + ', ' + transaction.time}
</Table.Cell>
<Table.Cell>{transaction.target_name}</Table.Cell>
<Table.Cell>{transaction.purpose}</Table.Cell>
<Table.Cell>{transaction.amount}</Table.Cell>
<Table.Cell>{transaction.source_terminal}</Table.Cell>
</Table.Row>
))}
</Table>
</Section>
</Section>
) : (
''
)
)}
</Section>
);
};
@@ -34,10 +34,10 @@ export const SensorData = (props, context) => {
return (
<Section>
{data.sensors.map((sensor) => (
<Box bold key={sensor}>
{sensor.name}
<Box bold key={sensor.id_tag}>
{sensor.name} ({sensor.id_tag})
{sensor.datapoints.map((datapoint) => (
<LabeledList key={datapoint}>
<LabeledList key={datapoint.datapoint}>
{datapoint.data !== null ? (
<LabeledList.Item label={capitalize(datapoint.datapoint)}>
{datapoint.data} {datapoint.unit}
@@ -97,7 +97,7 @@ export const ScannerWindow = (props, context) => {
<Table>
<Table.Row>
<Table.Cell>
<Section fill={0} title="Patient Status" scrollable>
<Section fill={false} title="Patient Status" scrollable>
<LabeledList>
<LabeledList.Item label="Name">{data.name}</LabeledList.Item>
<LabeledList.Item
@@ -567,7 +567,15 @@ export const OverviewShipments = (props, context) => {
export const Bounties = (props, context) => {
const { act, data } = useBackend<CargoData>(context);
return (
<Section title="Operations Bounties">
<Section
title="Operations Bounties"
button={
<Button
content="Print"
icon="Print"
onClick={() => act('bounty_print')}
/>
}>
<Table>
<Table.Row header>
<Table.Cell>Name</Table.Cell>
@@ -61,7 +61,14 @@ export const ChemicalDispenser = (props, context) => {
{data.chemicals ? <ChemTable /> : 'No chemicals detected.'}
</Section>
<Section
title="Container Display"
title={
'Container Display' + data.is_beaker_loaded &&
' (' +
data.beaker_current_volume +
'/' +
data.beaker_max_volume +
'u)'
}
buttons={
data.is_beaker_loaded ? (
<Button
@@ -270,45 +270,47 @@ export const MessageList = (props, context) => {
);
return viewingMessage ? (
data.messages
.filter((message) => message.id === viewingMessage)
.map((message) => (
<Section
title={message.title}
key={message.id}
buttons={
<>
<Button
content="Back"
icon="arrow-alt-circle-left"
onClick={() => setViewingMessage(null)}
/>
<Button
content="Print"
icon="print"
disabled={!data.have_printer}
onClick={() =>
act('printmessage', {
contents: message.contents,
title: message.title,
})
}
/>
<Button
content="Delete"
color="red"
icon="trash"
disabled={!data.message_deletion_allowed}
onClick={() => act('delmessage', { messageid: message.id })}
/>
</>
}>
<Box
style={{ 'white-space': 'pre-line' }}
dangerouslySetInnerHTML={processMessage(message.contents)}
/>
</Section>
))
<Section>
{data.messages
.filter((message) => message.id === viewingMessage)
.map((message) => (
<Section
title={message.title}
key={message.id}
buttons={
<>
<Button
content="Back"
icon="arrow-alt-circle-left"
onClick={() => setViewingMessage(null)}
/>
<Button
content="Print"
icon="print"
disabled={!data.have_printer}
onClick={() =>
act('printmessage', {
contents: message.contents,
title: message.title,
})
}
/>
<Button
content="Delete"
color="red"
icon="trash"
disabled={!data.message_deletion_allowed}
onClick={() => act('delmessage', { messageid: message.id })}
/>
</>
}>
<Box
style={{ 'white-space': 'pre-line' }}
dangerouslySetInnerHTML={processMessage(message.contents)}
/>
</Section>
))}
</Section>
) : (
<Section>
<Section>
+22 -8
View File
@@ -1,4 +1,4 @@
import { BooleanLike } from 'common/react';
import { BooleanLike } from '../../common/react';
import { useBackend } from '../backend';
import { Section, ProgressBar, Button, Box } from '../components';
import { Window } from '../layouts';
@@ -76,7 +76,9 @@ export const Doors = (props, context) => {
? data.wtime
: data.backup_power_lost_until
}
minValue={data.backup_power_lost_until ? data.backup_power_lost_at : 1}
minValue={
data.backup_power_lost_until ? data.backup_power_lost_at : 1
}
maxValue={data.backup_power_lost_until}>
{get_power_status_message(data.backup_power_lost_until, data.wtime)}
</ProgressBar>
@@ -126,7 +128,9 @@ export const Doors = (props, context) => {
</Section>
<Section title="Commands">
<Box>
<b>Bolts: </b>
<Box as="span" bold>
Bolts:{' '}
</Box>
<Button
content="Raised"
disabled={data.isAi && !data.isAdmin && data.aiCanBolt}
@@ -151,7 +155,9 @@ export const Doors = (props, context) => {
/>
</Box>
<Box>
<b>IDScan: </b>
<Box as="span" bold>
IDScan:{' '}
</Box>
<Button
content="On"
color={data.idscan && 'good'}
@@ -164,7 +170,9 @@ export const Doors = (props, context) => {
/>
</Box>
<Box>
<b>Bolt Lights: </b>
<Box as="span" bold>
Bolt Lights:{' '}
</Box>
<Button
content="On"
color={data.lights && 'good'}
@@ -177,7 +185,9 @@ export const Doors = (props, context) => {
/>
</Box>
<Box>
<b>Safeties: </b>
<Box as="span" bold>
Safeties:{' '}
</Box>
<Button
content="Nominal"
color={data.safeties && 'good'}
@@ -190,7 +200,9 @@ export const Doors = (props, context) => {
/>
</Box>
<Box>
<b>Timing: </b>
<Box as="span" bold>
Timing:{' '}
</Box>
<Button
content="Nominal"
color={data.timing && 'good'}
@@ -203,7 +215,9 @@ export const Doors = (props, context) => {
/>
</Box>
<Box>
<b>Door State: </b>
<Box as="span" bold>
Door State:{' '}
</Box>
<Button
content="Open"
color={data.open && 'good'}
+3 -3
View File
@@ -6,7 +6,7 @@ import { Window } from '../layouts';
export type InfraredData = {
active: BooleanLike;
visible: BooleanLike;
}
};
export const Infrared = (props, context) => {
const { act, data } = useBackend<InfraredData>(context);
@@ -15,12 +15,12 @@ export const Infrared = (props, context) => {
<Window resizable>
<Window.Content scrollable>
<Button
content={data.active ? "Active" : "Inactive"}
content={data.active ? 'Active' : 'Inactive'}
checked={data.active}
onClick={() => act('state')}
/>
<Button.Checkbox
content={data.visible ? "Visible" : "Invisible"}
content={data.visible ? 'Visible' : 'Invisible'}
checked={data.visible}
onClick={() => act('visible')}
/>
+15 -18
View File
@@ -43,24 +43,21 @@ export const Janitor = (props, context) => {
<Table.Cell>Direction</Table.Cell>
<Table.Cell>Status</Table.Cell>
</Table.Row>
{data.supplies.map((supply) => (
supply.supply_type === tab && (
<Table.Row key={supply.name}>
<Table.Cell>
{supply.name} (#{supply.key})
</Table.Cell>
<Table.Cell>
({supply.x}, {supply.y})
</Table.Cell>
<Table.Cell>
{supply.dir}
</Table.Cell>
<Table.Cell>
{supply.status}
</Table.Cell>
</Table.Row>
)
))}
{data.supplies.map(
(supply) =>
supply.supply_type === tab && (
<Table.Row key={supply.name}>
<Table.Cell>
{supply.name} (#{supply.key})
</Table.Cell>
<Table.Cell>
({supply.x}, {supply.y})
</Table.Cell>
<Table.Cell>{supply.dir}</Table.Cell>
<Table.Cell>{supply.status}</Table.Cell>
</Table.Row>
)
)}
<Table.Row>
User Location: ({data.user_x}, {data.user_y})
</Table.Row>
+27 -15
View File
@@ -1,5 +1,5 @@
import { useBackend } from '../backend';
import { Button, NumberInput, Section, LabeledList } from '../components';
import { Button, Section, LabeledList, Box } from '../components';
import { Window } from '../layouts';
import { BooleanLike } from '../../common/react';
@@ -16,28 +16,41 @@ export const NTNetRelay = (props, context) => {
return (
<Window resizable>
<Window.Content scrollable>
{data.dos_crashed ?(
{data.dos_crashed ? (
<Section title="NETWORK ERROR">
<h2>NETWORK BUFFERS OVERLOADED</h2>
<h3>Overload Recovery Mode</h3>
<i>This system is suffering temporary outage due to overflow of traffic buffers. Until buffered traffic is processed, all further requests will be dropped. Frequent occurences of this error may indicate insufficient hardware capacity of your network. Please contact your network planning department for instructions on how to resolve this issue.</i>
<h3>ADMINISTRATIVE OVERRIDE</h3>
<b> CAUTION - Data loss may occur </b>
<Box fontSize={1.3} bold>
NETWORK BUFFERS OVERLOADED
</Box>
<Box fontSize={1.2}>Overload Recovery Mode</Box>
<Box italic>
This system is suffering temporary outage due to overflow of
traffic buffers. Until buffered traffic is processed, all further
requests will be dropped. Frequent occurences of this error may
indicate insufficient hardware capacity of your network. Please
contact your network planning department for instructions on how
to resolve this issue.
</Box>
<Box fontSize={1.3} bold>
ADMINISTRATIVE OVERRIDE
</Box>
<Box bold> CAUTION - Data loss may occur </Box>
<Button
content="Purge buffered traffic"
onClick={() => act('restart')} />
content="Purge buffered traffic"
onClick={() => act('restart')}
/>
</Section>
) : (
<Section title="NTNet Server Status">
<LabeledList>
<LabeledList.Item label="Network buffer status">
{data.dos_overload} / {data.dos_capacity} GQ
{data.dos_overload} / {data.dos_capacity} GQ
</LabeledList.Item>
<LabeledList.Item label="Toggle Status">
<Button
content={data.enabled?("ENABLED"):("DISABLED")}
onClick={() => act('toggle')} />
</LabeledList.Item>
<Button
content={data.enabled ? 'ENABLED' : 'DISABLED'}
onClick={() => act('toggle')}
/>
</LabeledList.Item>
</LabeledList>
</Section>
)}
@@ -45,4 +58,3 @@ export const NTNetRelay = (props, context) => {
</Window>
);
};
+35 -29
View File
@@ -1,45 +1,49 @@
import { useBackend } from '../backend';
import { Button, NumberInput, Section, LabeledList } from '../components';
import { Button, Section, LabeledList } from '../components';
import { Window } from '../layouts';
import { BooleanLike } from '../../common/react';
export type ScannerData = {
enabled: BooleanLike;
search_ores: String[];
ore_names: String[];
search_ores: string[];
ore_names: string[];
};
export const OreDetector = (props, context) => {
const { act, data } = useBackend<ScannerData>(context);
function ore_enabled(ore_name){
if(!data.search_ores){
return false
const ore_enabled = (ore_name) => {
if (!data.search_ores) {
return false;
}
return data.search_ores.includes(ore_name)
}
return data.search_ores.includes(ore_name);
};
function get_status(){
if(data.search_ores.length == 0){
return "CANT ENABLE - SELECT ORES"
const get_status = () => {
if (data.search_ores.length === 0) {
return 'CANT ENABLE - SELECT ORES';
}
if(data.enabled){
return "ENALBED"
}else{
return "DISABLED"
if (data.enabled) {
return 'ENALBED';
} else {
return 'DISABLED';
}
}
};
return (
<Window resizable>
<Window.Content scrollable>
<Section title="Ore Detector">
<LabeledList>
<LabeledList.Item label="Status" buttons={
<Button icon="power-off"
disabled={!(data.search_ores.length)}
onClick={() => act('toggle')}
/>}>
<LabeledList.Item
label="Status"
buttons={
<Button
icon="power-off"
disabled={!data.search_ores.length}
onClick={() => act('toggle')}
/>
}>
{get_status()}
</LabeledList.Item>
</LabeledList>
@@ -47,13 +51,16 @@ export const OreDetector = (props, context) => {
<Section title="Selected Ores">
<LabeledList>
{data.ore_names.map((ore) => (
<LabeledList.Item label={ore} buttons={
<Button
onClick={() => act('select_ore',{ore_name:ore})}
>Toggle</Button>
}>
{(ore_enabled(ore)) ? 'ENABLED' : 'DISABLED'}
</LabeledList.Item>
<LabeledList.Item
key={ore}
label={ore}
buttons={
<Button onClick={() => act('select_ore', { ore_name: ore })}>
Toggle
</Button>
}>
{ore_enabled(ore) ? 'ENABLED' : 'DISABLED'}
</LabeledList.Item>
))}
</LabeledList>
</Section>
@@ -61,4 +68,3 @@ export const OreDetector = (props, context) => {
</Window>
);
};
@@ -54,8 +54,8 @@ export const PlayerPanel = (props, context) => {
<Table.Cell>Name</Table.Cell>
<Table.Cell>Assignment</Table.Cell>
<Table.Cell>Key</Table.Cell>
{data.is_mod && <Table.Cell>Age</Table.Cell>}
{data.is_mod && <Table.Cell>Antag</Table.Cell>}
{data.is_mod ? <Table.Cell>Age</Table.Cell> : ''}
{data.is_mod ? <Table.Cell>Antag</Table.Cell> : ''}
<Table.Cell textAlign="right">Actions</Table.Cell>
</Table.Row>
{data.players
@@ -86,7 +86,7 @@ export const PlayerPanel = (props, context) => {
: player.assigment}
</Table.Cell>
<Table.Cell>
{!data.is_mod ? '' : player.key}
{player.key}
{!player.connected ? ' (DC)' : ''}
</Table.Cell>
<Table.Cell>{data.is_mod ? player.age : ''}</Table.Cell>
@@ -69,7 +69,14 @@ export const SuitSensors = (props, context) => {
</Table.Cell>
<Table.Cell>
{crewmember.stype > 2
? crewmember.x + ', ' + crewmember.y + ', ' + crewmember.z
? crewmember.area +
' (' +
crewmember.x +
', ' +
crewmember.y +
', ' +
crewmember.z +
')'
: 'N/A'}
</Table.Cell>
{data.isAI ? (
+30 -21
View File
@@ -7,10 +7,10 @@ import { BooleanLike } from '../../common/react';
export type TankData = {
tankPressure: number;
releasePressure: number;
defaultReleasePressure: number
defaultReleasePressure: number;
maxReleasePressure: number;
valveOpen: BooleanLike;
maskConnected: BooleanLike
maskConnected: BooleanLike;
};
export const Tank = (props, context) => {
@@ -19,14 +19,14 @@ export const Tank = (props, context) => {
const [tank_color, setColor] = useLocalState(context, 'color', '');
const tank_presure_color = tank_color
? { color: tank_color }
: {
ranges: {
good: [200, Infinity],
bad: [-Infinity, 100],
average: [100, 200],
},
};
? { color: tank_color }
: {
ranges: {
good: [200, Infinity],
bad: [-Infinity, 100],
average: [100, 200],
},
};
return (
<Window resizable>
@@ -34,19 +34,27 @@ export const Tank = (props, context) => {
<Section title="Gas Tank">
<LabeledList>
<LabeledList.Item label="Tank Pressure">
<ProgressBar {...tank_presure_color} minValue={0} maxValue={1024} value={data.tankPressure}>
<ProgressBar
{...tank_presure_color}
minValue={0}
maxValue={1024}
value={data.tankPressure}>
{data.tankPressure} kPa
</ProgressBar>
</LabeledList.Item>
<LabeledList.Item label="Mask Status">
{data.maskConnected ? 'CONNECTED' : 'NOT CONNECTED'}
</LabeledList.Item>
<LabeledList.Item label="Mask Release Valve" buttons={
<Button icon="power-off"
disabled={!(data.maskConnected)}
onClick={() => act('toggleReleaseValve')}
/>}>
{data.valveOpen ? 'OPEN' : 'CLOSED'}
<LabeledList.Item
label="Mask Release Valve"
buttons={
<Button
icon="power-off"
disabled={!data.maskConnected}
onClick={() => act('toggleReleaseValve')}
/>
}>
{data.valveOpen ? 'OPEN' : 'CLOSED'}
</LabeledList.Item>
<LabeledList.Item label="Mask Release Pressure">
@@ -57,14 +65,15 @@ export const Tank = (props, context) => {
value={data.releasePressure}
minValue={0}
maxValue={data.maxReleasePressure}
onChange={(e, value) => act("setReleasePressure",{release_pressure:value})}
>{data.releasePressure} kPa</Slider>
onChange={(e, value) =>
act('setReleasePressure', { release_pressure: value })
}>
{data.releasePressure} kPa
</Slider>
</LabeledList.Item>
</LabeledList>
</Section>
</Window.Content>
</Window>
);
};
@@ -0,0 +1,93 @@
import { useBackend } from '../backend';
import { Button, Section, LabeledList, Flex } from '../components';
import { Window } from '../layouts';
import { BooleanLike } from '../../common/react';
export type TransferValveData = {
tankOne: String[];
tankTwo: String[];
valveAttachment: String[];
valveOpen: BooleanLike;
};
export const TransferValve = (props, context) => {
const { act, data } = useBackend<TransferValveData>(context);
return (
<Window resizable>
<Window.Content>
<Flex direction="row" align="stretch">
<Flex.Item grow={1}>
<Section fill title="Tank 1">
<LabeledList>
<LabeledList.Item label="Name">
{data.tankOne ? data.tankOne : 'NOT ATTACHED'}
</LabeledList.Item>
<LabeledList.Item label="Actions">
<Button
content="Interact"
disabled={!data.tankOne}
onClick={() => act('interact', { object: 'tankOne' })}
/>
</LabeledList.Item>
<LabeledList.Item>
<Button
content="Detach"
disabled={!data.tankOne}
onClick={() => act('remove', { object: 'tankOne' })}
/>
</LabeledList.Item>
</LabeledList>
</Section>
</Flex.Item>
<Flex.Item grow={1}>
<Section fill title="Vavle Attachment">
<LabeledList>
<LabeledList.Item label="Name">
{data.valveAttachment ? data.valveAttachment : 'NOT ATTACHED'}
</LabeledList.Item>
<LabeledList.Item label="Actions">
<Button
content="Interact"
disabled={!data.valveAttachment}
onClick={() => act('interact', { object: 'device' })}
/>
</LabeledList.Item>
<LabeledList.Item>
<Button
content="Detach"
disabled={!data.valveAttachment}
onClick={() => act('remove', { object: 'device' })}
/>
</LabeledList.Item>
</LabeledList>
</Section>
</Flex.Item>
<Flex.Item grow={1}>
<Section fill title="Tank 2">
<LabeledList>
<LabeledList.Item label="Name">
{data.tankTwo ? data.tankTwo : 'NOT ATTACHED'}
</LabeledList.Item>
<LabeledList.Item label="Actions">
<Button
content="Interact"
disabled={!data.tankTwo}
onClick={() => act('interact', { object: 'tankTwo' })}
/>
</LabeledList.Item>
<LabeledList.Item>
<Button
content="Detach"
disabled={!data.tankTwo}
onClick={() => act('remove', { object: 'tankTwo' })}
/>
</LabeledList.Item>
</LabeledList>
</Section>
</Flex.Item>
</Flex>
</Window.Content>
</Window>
);
};
@@ -1,94 +0,0 @@
import { useBackend } from '../backend';
import { Button, Section, LabeledList, Flex } from '../components';
import { Window } from '../layouts';
import { BooleanLike } from '../../common/react';
export type TransferVavleData = {
tankOne: String[];
tankTwo: String[];
valveAttachment: String[];
valveOpen: BooleanLike;
};
export const TransferVavle = (props, context) => {
const { act, data } = useBackend<TransferVavleData>(context);
return (
<Window resizable>
<Window.Content>
<Flex direction="row" align="stretch">
<Flex.Item grow={1}>
<Section fill={true} title="Tank 1">
<LabeledList>
<LabeledList.Item label="Name">
{data.tankOne ? data.tankOne : 'NOT ATTACHED'}
</LabeledList.Item>
<LabeledList.Item label="Actions">
<Button
content="Interact"
disabled={!(data.tankOne)}
onClick={() => act('interact',{object:"tankOne"})}
/>
</LabeledList.Item>
<LabeledList.Item>
<Button
content="Detach"
disabled={!(data.tankOne)}
onClick={() => act('remove',{object:"tankOne"})}
/>
</LabeledList.Item>
</LabeledList>
</Section>
</Flex.Item>
<Flex.Item grow={1}>
<Section fill={true} title="Vavle Attachment">
<LabeledList>
<LabeledList.Item label="Name">
{data.valveAttachment ? data.valveAttachment : 'NOT ATTACHED'}
</LabeledList.Item>
<LabeledList.Item label="Actions">
<Button
content="Interact"
disabled={!(data.valveAttachment)}
onClick={() => act('interact',{object:"device"})}
/>
</LabeledList.Item>
<LabeledList.Item>
<Button
content="Detach"
disabled={!(data.valveAttachment)}
onClick={() => act('remove',{object:"device"})}
/>
</LabeledList.Item>
</LabeledList>
</Section>
</Flex.Item>
<Flex.Item grow={1}>
<Section fill={true} title="Tank 2">
<LabeledList>
<LabeledList.Item label="Name">
{data.tankTwo ? data.tankTwo : 'NOT ATTACHED'}
</LabeledList.Item>
<LabeledList.Item label="Actions">
<Button
content="Interact"
disabled={!(data.tankTwo)}
onClick={() => act('interact',{object:"tankTwo"})}
/>
</LabeledList.Item>
<LabeledList.Item>
<Button
content="Detach"
disabled={!(data.tankTwo)}
onClick={() => act('remove',{object:"tankTwo"})}
/>
</LabeledList.Item>
</LabeledList>
</Section>
</Flex.Item>
</Flex>
</Window.Content>
</Window>
);
};
+53 -49
View File
@@ -105,54 +105,58 @@ export const ControlWindow = (props, context) => {
export const TurretsWindow = (props, context) => {
const { act, data } = useBackend<TurretData>(context);
return data.turrets.map((turret) => (
<Section title={turret.name} key={turret.name}>
<LabeledList>
<LabeledList.Item label="Turret Status">
<Button
content={turret.enabled ? 'Enabled' : 'Disabled'}
color={turret.enabled ? 'bad' : 'good'}
disabled={data.locked}
onClick={() =>
act('command', {
turret_ref: turret.ref,
value: !turret.enabled,
command: 'enable',
})
}
/>
</LabeledList.Item>
<LabeledList.Item label="Lethal Mode">
<Button
content={turret.lethal ? 'On' : 'Off'}
color={turret.lethal ? 'bad' : 'average'}
disabled={data.locked}
onClick={() =>
act('command', {
turret_ref: turret.ref,
value: !turret.lethal,
command: 'lethal',
})
}
/>
</LabeledList.Item>
{turret.settings.map((setting) => (
<LabeledList.Item label={setting.category} key={setting.category}>
<Button
content={setting.value ? 'On' : 'Off'}
selected={setting.value}
disabled={data.locked}
onClick={() =>
act('command', {
turret_ref: turret.ref,
value: !setting.value,
command: setting.variable_name,
})
}
/>
</LabeledList.Item>
))}
</LabeledList>
return (
<Section>
{data.turrets.map((turret) => (
<Section title={turret.name} key={turret.name}>
<LabeledList>
<LabeledList.Item label="Turret Status">
<Button
content={turret.enabled ? 'Enabled' : 'Disabled'}
color={turret.enabled ? 'bad' : 'good'}
disabled={data.locked}
onClick={() =>
act('command', {
turret_ref: turret.ref,
value: !turret.enabled,
command: 'enable',
})
}
/>
</LabeledList.Item>
<LabeledList.Item label="Lethal Mode">
<Button
content={turret.lethal ? 'On' : 'Off'}
color={turret.lethal ? 'bad' : 'average'}
disabled={data.locked}
onClick={() =>
act('command', {
turret_ref: turret.ref,
value: !turret.lethal,
command: 'lethal',
})
}
/>
</LabeledList.Item>
{turret.settings.map((setting) => (
<LabeledList.Item label={setting.category} key={setting.category}>
<Button
content={setting.value ? 'On' : 'Off'}
selected={setting.value}
disabled={data.locked}
onClick={() =>
act('command', {
turret_ref: turret.ref,
value: !setting.value,
command: setting.variable_name,
})
}
/>
</LabeledList.Item>
))}
</LabeledList>
</Section>
))}
</Section>
));
);
};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long