ID Card Console tweaks (#20462)

* Fix ID consoles denying management access to head IDs witih custom titles

* Update proc name

* Make ID consoles highlight current rank regardless of custom title

* Fix ID consoles improperly checking Demoted/Terminated status

* Fix un-terminations not requiring a full ID console

* Fix missing `selected` properties; readability

* Fix console not disabling the Demote option on already demoted cards

* Deduplicate full and departmental ID console UI code

* Move the tab-agnostic authentication UI above tabs

* Angry feedback message consistency

* I forget this shorthand operator exists
This commit is contained in:
Nathan Winters
2023-03-25 15:45:43 +01:00
committed by GitHub
parent 86275bf5f7
commit e7acbdd6d0
4 changed files with 188 additions and 228 deletions

View File

@@ -632,7 +632,7 @@ SUBSYSTEM_DEF(jobs)
if(tgtcard)
var/mob/M = tgtcard.getPlayer()
for(var/datum/job/job in occupations)
if(tgtcard.assignment && tgtcard.assignment == job.title)
if(tgtcard.rank && tgtcard.rank == job.title)
jobs_to_formats[job.title] = "green" // the job they already have is pre-selected
else if(tgtcard.assignment == "Demoted" || tgtcard.assignment == "Terminated")
jobs_to_formats[job.title] = "grey"

View File

@@ -79,9 +79,6 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
return check_access(scan)
return FALSE
/obj/machinery/computer/card/proc/get_target_rank()
return modify && modify.assignment ? modify.assignment : "Unassigned"
/obj/machinery/computer/card/proc/format_jobs(list/jobs, targetrank, list/jobformats)
var/list/formatted = list()
for(var/job in jobs)
@@ -239,7 +236,7 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
return TRUE
if(!targetjob || !targetjob.title)
return FALSE
if(targetjob.title in get_subordinates(scan.assignment, include_assistants))
if(targetjob.title in get_subordinates(scan.rank, include_assistants))
return TRUE
return FALSE
@@ -311,7 +308,8 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
data["mode"] = mode
data["modify_name"] = modify ? modify.name : FALSE
data["modify_owner"] = modify && modify.registered_name ? modify.registered_name : "-----"
data["modify_rank"] = get_target_rank()
data["modify_rank"] = modify?.rank ? modify.rank : FALSE
data["modify_assignment"] = modify?.assignment ? modify.assignment : "Unassigned"
data["modify_lastlog"] = modify && modify.lastlog ? modify.lastlog : FALSE
data["scan_name"] = scan ? scan.name : FALSE
data["scan_rank"] = scan ? scan.rank : FALSE
@@ -327,9 +325,13 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
if(modify)
if(!scan)
return data
else if(target_dept)
data["jobs_dept"] = get_subordinates(scan.assignment, FALSE)
data["canterminate"] = has_idchange_access()
data["jobFormats"] = SSjobs.format_jobs_for_id_computer(modify)
data["jobs_assistant"] = GLOB.assistant_positions
data["canterminate"] = has_idchange_access()
if(target_dept)
data["jobs_dept"] = get_subordinates(scan.rank, FALSE)
else
data["account_number"] = modify ? modify.associated_account_number : null
data["jobs_top"] = list("Captain", "Custom")
@@ -339,9 +341,7 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
data["jobs_security"] = GLOB.security_positions
data["jobs_service"] = GLOB.service_positions
data["jobs_supply"] = GLOB.supply_positions - "Head of Personnel"
data["jobs_assistant"] = GLOB.assistant_positions
data["jobs_centcom"] = get_all_centcom_jobs() + get_all_ERT_jobs()
data["jobFormats"] = SSjobs.format_jobs_for_id_computer(modify)
data["current_skin"] = modify.icon_state
data["card_skins"] = format_card_skins(get_station_card_skins())
data["all_centcom_skins"] = is_centcom() ? format_card_skins(get_centcom_card_skins()) : FALSE
@@ -368,7 +368,7 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
data["records"] = SSjobs.format_job_change_records(data["iscentcom"])
if(IDCOMPUTER_SCREEN_DEPT) // DEPARTMENT EMPLOYEE LIST
if(is_authenticated(user) && scan) // .requires both (aghosts don't count)
data["jobs_dept"] = get_subordinates(scan.assignment, FALSE)
data["jobs_dept"] = get_subordinates(scan.rank, FALSE)
data["people_dept"] = get_employees(data["jobs_dept"])
return data
@@ -447,9 +447,9 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
return
var/t1 = params["assign_target"]
if(target_dept)
if(modify.assignment == "Demoted")
if(modify.assignment == "Demoted" || modify.assignment == "Terminated")
playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 0)
visible_message("<span class='warning'>[src]: Reassigning a demoted individual requires a full ID computer.</span>")
visible_message("<span class='warning'>[src]: Reassigning a demoted or terminated individual requires a full ID computer.</span>")
return FALSE
if(!job_in_department(SSjobs.GetJob(modify.rank), FALSE))
playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 0)
@@ -510,11 +510,11 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
if("demote")
if(modify.assignment == "Demoted")
playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 0)
visible_message("<span class='notice'>[src]: Demoted crew cannot be demoted any further. If further action is warranted, ask the Captain about Termination.</span>")
visible_message("<span class='warning'>[src]: Demoted crew cannot be demoted any further. If further action is warranted, ask the Captain about Termination.</span>")
return FALSE
if(!job_in_department(SSjobs.GetJob(modify.rank), FALSE))
playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 0)
visible_message("<span class='notice'>[src]: Heads may only demote members of their own department.</span>")
visible_message("<span class='warning'>[src]: Heads may only demote members of their own department.</span>")
return FALSE
var/reason = sanitize(copytext(input("Enter legal reason for demotion. Enter nothing to cancel.","Legal Demotion"), 1, MAX_MESSAGE_LEN))
if(!reason || !is_authenticated(usr) || !modify)
@@ -540,7 +540,7 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
if("terminate")
if(!has_idchange_access()) // because captain/HOP can use this even on dept consoles
playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 0)
visible_message("<span class='notice'>[src]: Only the Captain or HOP may completely terminate the employment of a crew member.</span>")
visible_message("<span class='warning'>[src]: Only the Captain or HOP may completely terminate the employment of a crew member.</span>")
return FALSE
var/jobnamedata = modify.getRankAndAssignment()
var/reason = sanitize(copytext(input("Enter legal reason for termination. Enter nothing to cancel.", "Employment Termination"), 1, MAX_MESSAGE_LEN))
@@ -634,7 +634,7 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
var/temp_name = reject_bad_name(input(usr, "Who is this ID for?", "ID Card Renaming", modify.registered_name), TRUE)
if(!modify || !temp_name)
playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 0)
visible_message("<span class='notice'>[src] buzzes rudely.</span>")
visible_message("<span class='warning'>[src] buzzes rudely.</span>")
return FALSE
modify.registered_name = temp_name
regenerate_id_name()

View File

@@ -93,178 +93,137 @@ export const CardComputer = (props, context) => {
No card to modify.
</Section>
);
} else if (data.target_dept) {
bodyBlock = (
<Section title="Department Job Transfer">
<LabeledList>
{!!data.modify_lastlog && (
<LabeledList.Item label="Latest Transfer">
{data.modify_lastlog}
</LabeledList.Item>
)}
<LabeledList.Item label="Department">
{data.jobs_dept.map((v) => (
<Button
selected={v === data.modify_rank}
key={v}
content={v}
onClick={() => act('assign', { assign_target: v })}
/>
))}
</LabeledList.Item>
<LabeledList.Item label="Retirement">
<Button
selected={'Assistant' === data.modify_rank}
key="Assistant"
content="Assistant"
onClick={() => act('assign', { assign_target: 'Assistant' })}
/>
</LabeledList.Item>
<LabeledList.Item label="Demotion">
<Button
selected={'Demoted' === data.modify_rank}
key="Demoted"
content="Demoted"
tooltip="Assistant access, 'demoted' title."
color="red"
icon="times"
onClick={() => act('demote')}
/>
</LabeledList.Item>
{!!data.canterminate && (
<LabeledList.Item label="Non-Crew">
<Button
disabled={'Terminated' === data.modify_rank}
key="Terminate"
content="Terminated"
tooltip="Zero access. Not crew."
color="red"
icon="eraser"
onClick={() => act('terminate')}
/>
</LabeledList.Item>
)}
</LabeledList>
</Section>
);
} else {
bodyBlock = (
<Fragment>
<Section title="Card Information">
<LabeledList.Item label="Registered Name">
<Button
icon={
!data.modify_owner || data.modify_owner === 'Unknown'
? 'exclamation-triangle'
: 'pencil-alt'
}
selected={data.modify_name}
content={data.modify_owner}
onClick={() => act('reg')}
/>
</LabeledList.Item>
<LabeledList.Item label="Account Number">
<Button
icon={
data.account_number ? 'pencil-alt' : 'exclamation-triangle'
}
selected={data.account_number}
content={data.account_number ? data.account_number : 'None'}
onClick={() => act('account')}
/>
</LabeledList.Item>
{!!data.modify_lastlog && (
<LabeledList.Item label="Latest Transfer">
{data.modify_lastlog}
</LabeledList.Item>
{!data.target_dept && (
<Fragment>
<LabeledList.Item label="Registered Name">
<Button
icon={
!data.modify_owner || data.modify_owner === 'Unknown'
? 'exclamation-triangle'
: 'pencil-alt'
}
selected={data.modify_name}
content={data.modify_owner}
onClick={() => act('reg')}
/>
</LabeledList.Item>
<LabeledList.Item label="Account Number">
<Button
icon={data.account_number ? 'pencil-alt' : 'exclamation-triangle'}
selected={data.account_number}
content={data.account_number ? data.account_number : 'None'}
onClick={() => act('account')}
/>
</LabeledList.Item>
</Fragment>
)}
<LabeledList.Item label="Latest Transfer">
{data.modify_lastlog || "---"}
</LabeledList.Item>
</Section>
<Section title="Job Transfer">
<Section title={data.target_dept ? "Department Job Transfer" : "Job Transfer"}>
<LabeledList>
<LabeledList.Item label="Special">
{data.jobs_top.map((v) => (
<Button
selected={v === data.modify_rank}
key={v}
content={v}
color={data.jobFormats[v] ? data.jobFormats[v] : ''}
onClick={() => act('assign', { assign_target: v })}
/>
))}
</LabeledList.Item>
<LabeledList.Item
label="Engineering"
labelColor={deptCols.engineering}
>
{data.jobs_engineering.map((v) => (
<Button
key={v}
content={v}
color={data.jobFormats[v] ? data.jobFormats[v] : ''}
onClick={() => act('assign', { assign_target: v })}
/>
))}
</LabeledList.Item>
<LabeledList.Item label="Medical" labelColor={deptCols.medical}>
{data.jobs_medical.map((v) => (
<Button
key={v}
content={v}
color={data.jobFormats[v] ? data.jobFormats[v] : ''}
onClick={() => act('assign', { assign_target: v })}
/>
))}
</LabeledList.Item>
<LabeledList.Item label="Science" labelColor={deptCols.science}>
{data.jobs_science.map((v) => (
<Button
key={v}
content={v}
color={data.jobFormats[v] ? data.jobFormats[v] : ''}
onClick={() => act('assign', { assign_target: v })}
/>
))}
</LabeledList.Item>
<LabeledList.Item
label="Security"
labelColor={deptCols.security}
>
{data.jobs_security.map((v) => (
<Button
selected={v === data.modify_rank}
key={v}
content={v}
color={data.jobFormats[v] ? data.jobFormats[v] : ''}
onClick={() => act('assign', { assign_target: v })}
/>
))}
</LabeledList.Item>
<LabeledList.Item label="Service" labelColor={deptCols.service}>
{data.jobs_service.map((v) => (
<Button
selected={v === data.modify_rank}
key={v}
content={v}
color={data.jobFormats[v] ? data.jobFormats[v] : ''}
onClick={() => act('assign', { assign_target: v })}
/>
))}
</LabeledList.Item>
<LabeledList.Item label="Supply" labelColor={deptCols.supply}>
{data.jobs_supply.map((v) => (
<Button
selected={v === data.modify_rank}
key={v}
content={v}
color={data.jobFormats[v] ? data.jobFormats[v] : ''}
onClick={() => act('assign', { assign_target: v })}
/>
))}
</LabeledList.Item>
<LabeledList.Item label="Assistant">
{data.target_dept ? (
<LabeledList.Item label="Department">
{data.jobs_dept.map((v) => (
<Button
selected={data.modify_rank === v}
key={v}
content={v}
color={data.jobFormats[v] ? data.jobFormats[v] : ''}
onClick={() => act('assign', { assign_target: v })}
/>
))}
</LabeledList.Item>
) : (
<Fragment>
<LabeledList.Item label="Special">
{data.jobs_top.map((v) => (
<Button
selected={data.modify_rank === v}
key={v}
content={v}
color={data.jobFormats[v] ? data.jobFormats[v] : ''}
onClick={() => act('assign', { assign_target: v })}
/>
))}
</LabeledList.Item>
<LabeledList.Item label="Engineering" labelColor={deptCols.engineering}>
{data.jobs_engineering.map((v) => (
<Button
selected={data.modify_rank === v}
key={v}
content={v}
color={data.jobFormats[v] ? data.jobFormats[v] : ''}
onClick={() => act('assign', { assign_target: v })}
/>
))}
</LabeledList.Item>
<LabeledList.Item label="Medical" labelColor={deptCols.medical}>
{data.jobs_medical.map((v) => (
<Button
selected={data.modify_rank === v}
key={v}
content={v}
color={data.jobFormats[v] ? data.jobFormats[v] : ''}
onClick={() => act('assign', { assign_target: v })}
/>
))}
</LabeledList.Item>
<LabeledList.Item label="Science" labelColor={deptCols.science}>
{data.jobs_science.map((v) => (
<Button
selected={data.modify_rank === v}
key={v}
content={v}
color={data.jobFormats[v] ? data.jobFormats[v] : ''}
onClick={() => act('assign', { assign_target: v })}
/>
))}
</LabeledList.Item>
<LabeledList.Item label="Security" labelColor={deptCols.security}>
{data.jobs_security.map((v) => (
<Button
selected={data.modify_rank === v}
key={v}
content={v}
color={data.jobFormats[v] ? data.jobFormats[v] : ''}
onClick={() => act('assign', { assign_target: v })}
/>
))}
</LabeledList.Item>
<LabeledList.Item label="Service" labelColor={deptCols.service}>
{data.jobs_service.map((v) => (
<Button
selected={data.modify_rank === v}
key={v}
content={v}
color={data.jobFormats[v] ? data.jobFormats[v] : ''}
onClick={() => act('assign', { assign_target: v })}
/>
))}
</LabeledList.Item>
<LabeledList.Item label="Supply" labelColor={deptCols.supply}>
{data.jobs_supply.map((v) => (
<Button
selected={data.modify_rank === v}
key={v}
content={v}
color={data.jobFormats[v] ? data.jobFormats[v] : ''}
onClick={() => act('assign', { assign_target: v })}
/>
))}
</LabeledList.Item>
</Fragment>
)}
<LabeledList.Item label="Retirement">
{data.jobs_assistant.map((v) => (
<Button
selected={v === data.modify_rank}
selected={data.modify_rank === v}
key={v}
content={v}
color={data.jobFormats[v] ? data.jobFormats[v] : ''}
@@ -273,71 +232,72 @@ export const CardComputer = (props, context) => {
))}
</LabeledList.Item>
{!!data.iscentcom && (
<LabeledList.Item
label="CentCom"
labelColor={deptCols.centcom}
>
<LabeledList.Item label="CentCom" labelColor={deptCols.centcom}>
{data.jobs_centcom.map((v) => (
<Button
selected={v === data.modify_rank}
color={
data.jobFormats[v] ? data.jobFormats[v] : 'purple'
}
selected={data.modify_rank === v}
key={v}
content={v}
color={data.jobFormats[v] ? data.jobFormats[v] : 'purple'}
onClick={() => act('assign', { assign_target: v })}
/>
))}
</LabeledList.Item>
)}
<LabeledList.Item label="Demotions">
<LabeledList.Item label="Demotion">
<Button
disabled={'Terminated' === data.modify_rank}
disabled={
data.modify_assignment === "Demoted" ||
data.modify_assignment === "Terminated"
}
key="Demoted"
content="Demoted"
selected={'Demoted' === data.modify_rank}
tooltip="Assistant access, 'demoted' title."
color="red"
icon="times"
onClick={() => act('demote')}
/>
</LabeledList.Item>
<LabeledList.Item label="Non-Crew">
<Button
disabled={'Terminated' === data.modify_rank}
key="Terminate"
content="Terminated"
tooltip="Zero access. Not crew."
color="red"
icon="eraser"
onClick={() => act('terminate')}
/>
</LabeledList.Item>
{!!data.canterminate && (
<LabeledList.Item label="Non-Crew">
<Button
disabled={data.modify_assignment === 'Terminated'}
key="Terminate"
content="Terminated"
tooltip="Zero access. Not crew."
color="red"
icon="eraser"
onClick={() => act('terminate')}
/>
</LabeledList.Item>
)}
</LabeledList>
</Section>
<Section title="Card Skins">
{data.card_skins.map((v) => (
<Button
selected={v.skin === data.current_skin}
key={v.skin}
content={v.display_name}
onClick={() => act('skin', { skin_target: v.skin })}
/>
))}
{!!data.iscentcom && (
<Box>
{data.all_centcom_skins.map((v) => (
<Button
selected={v.skin === data.current_skin}
key={v.skin}
content={v.display_name}
color="purple"
onClick={() => act('skin', { skin_target: v.skin })}
/>
))}
</Box>
)}
</Section>
{!data.target_dept && (
<Section title="Card Skins">
{data.card_skins.map((v) => (
<Button
selected={data.current_skin === v.skin}
key={v.skin}
content={v.display_name}
onClick={() => act('skin', { skin_target: v.skin })}
/>
))}
{!!data.iscentcom && (
<Box>
{data.all_centcom_skins.map((v) => (
<Button
selected={data.current_skin === v.skin}
key={v.skin}
content={v.display_name}
color="purple"
onClick={() => act('skin', { skin_target: v.skin })}
/>
))}
</Box>
)}
</Section>
)}
</Fragment>
);
}
@@ -602,8 +562,8 @@ export const CardComputer = (props, context) => {
return (
<Window resizable>
<Window.Content scrollable>
{menuBlock}
{authBlock}
{menuBlock}
{bodyBlock}
</Window.Content>
</Window>

File diff suppressed because one or more lines are too long