messy reimplementation of missing Ntos modules

for some reason we were missing a bunch of .js files for various Ntos apps. i painstakingly readded and refactored them by copying them over from the tgstation codebase and editing them.
This commit is contained in:
sarcoph
2022-03-03 23:03:53 -09:00
parent 418c41e003
commit fc115d9c6b
19 changed files with 1683 additions and 308 deletions
@@ -8,7 +8,7 @@
usage_flags = PROGRAM_CONSOLE
transfer_access = ACCESS_HEADS
available_on_ntnet = 1
tgui_id = "ntos_ai_restorer"
tgui_id = "NtosAiRestorer"
ui_x = 600
ui_y = 400
@@ -7,7 +7,7 @@
requires_ntnet = 1
network_destination = "alarm monitoring network"
size = 5
tgui_id = "ntos_station_alert"
tgui_id = "NtosStationAlertConsole"
ui_x = 315
ui_y = 500
@@ -7,7 +7,7 @@
requires_ntnet = 1
available_on_ntnet = 0
available_on_syndinet = 1
tgui_id = "ntos_net_dos"
tgui_id = "NtosNetDos"
ui_style = "syndicate"
ui_x = 400
ui_y = 250
@@ -80,17 +80,8 @@
else if(target && executed)
data["target"] = 1
data["speed"] = dos_speed
// This is mostly visual, generate some strings of 1s and 0s
// Probability of 1 is equal of completion percentage of DoS attack on this relay.
// Combined with UI updates this adds quite nice effect to the UI
var/percentage = target.dos_overload * 100 / target.dos_capacity
data["dos_strings"] = list()
for(var/j, j<10, j++)
var/string = ""
for(var/i, i<20, i++)
string = "[string][prob(percentage)]"
data["dos_strings"] += list(list("nums" = string))
data["overload"] = target.dos_overload
data["capacity"] = target.dos_capacity
else
data["relays"] = list()
for(var/obj/machinery/ntnet_relay/R in SSnetworks.station_network.relays)
@@ -7,7 +7,7 @@
requires_ntnet = 0
available_on_ntnet = 0
available_on_syndinet = 1
tgui_id = "ntos_revelation"
tgui_id = "NtosRevelation"
ui_style = "syndicate"
ui_x = 400
ui_y = 250
@@ -6,7 +6,7 @@
transfer_access = ACCESS_HEADS
requires_ntnet = 0
size = 8
tgui_id = "ntos_card"
tgui_id = "NtosCard"
ui_x = 600
ui_y = 700
@@ -15,7 +15,7 @@
var/show_assignments = 0
var/minor = 0
var/authenticated = 0
var/list/reg_ids = list()
var/reg_ids = 1
var/list/region_access = null
var/list/head_subordinates = null
var/target_dept = 0 //Which department this computer has access to. 0=all departments
@@ -94,6 +94,134 @@
return formatted
/datum/computer_file/program/card_mod/ui_data(mob/user)
var/list/data = get_header_data()
var/obj/item/computer_hardware/card_slot/card_slot
var/obj/item/computer_hardware/printer/printer
if(computer)
card_slot = computer.all_components[MC_CARD]
printer = computer.all_components[MC_PRINT]
data["mmode"] = mod_mode
var/authed = 0
if(computer)
if(card_slot)
var/obj/item/card/id/auth_card = card_slot.stored_card2
data["auth_name"] = auth_card ? strip_html_simple(auth_card.name) : "-----"
authed = authorized()
if(mod_mode == 2)
data["slots"] = list()
var/list/pos = list()
for(var/datum/job/job in SSjob.occupations)
if(job.title in blacklisted)
continue
var/list/status_open = build_manage(job,1)
var/list/status_close = build_manage(job,0)
pos.Add(list(list(
"title" = job.title,
"current" = job.current_positions,
"total" = job.total_positions,
"status_open" = (authed && !minor) ? status_open["enable"]: 0,
"status_close" = (authed && !minor) ? status_close["enable"] : 0,
"desc_open" = status_open["desc"],
"desc_close" = status_close["desc"])))
data["slots"] = pos
data["src"] = "[REF(src)]"
if(!mod_mode)
data["manifest"] = list()
var/list/crew = list()
for(var/datum/data/record/t in sortRecord(GLOB.data_core.general))
crew.Add(list(list(
"name" = t.fields["name"],
"rank" = t.fields["rank"])))
data["manifest"] = crew
data["assignments"] = show_assignments
if(computer)
data["have_id_slot"] = !!card_slot
data["have_printer"] = !!printer
if(!card_slot && mod_mode == 1)
mod_mode = 0 //We can't modify IDs when there is no card reader
else
data["have_id_slot"] = 0
data["have_printer"] = 0
data["authenticated"] = authed
if(mod_mode == 1 && computer)
if(card_slot)
var/obj/item/card/id/id_card = card_slot.stored_card
data["has_id"] = !!id_card
data["id_rank"] = id_card && id_card.assignment ? html_encode(id_card.assignment) : "Unassigned"
data["id_owner"] = id_card && id_card.registered_name ? html_encode(id_card.registered_name) : "-----"
data["id_name"] = id_card ? strip_html_simple(id_card.name) : "-----"
if(card_slot.stored_card)
var/obj/item/card/id/id_card = card_slot.stored_card
if(is_centcom)
var/list/all_centcom_access = list()
for(var/access in get_all_centcom_access())
all_centcom_access.Add(list(list(
"desc" = replacetext(get_centcom_access_desc(access), "&nbsp", " "),
"ref" = access,
"allowed" = (access in id_card.access) ? 1 : 0)))
data["all_centcom_access"] = all_centcom_access
else
var/list/accesses = list()
for(var/access in get_region_accesses(reg_ids))
if (get_access_desc(access))
accesses.Add(list(list(
"desc" = replacetext(get_access_desc(access), "&nbsp", " "),
"ref" = access,
"allowed" = (access in id_card.access) ? 1 : 0)))
var/list/regions = list()
for(var/i = 1; i <= 7; i++)
if((minor || target_dept) && !(i in region_access))
continue
regions.Add(list(list(
"name" = get_region_accesses_name(i),
"regid" = i,
"selected" = (reg_ids == i) ? 1 : null,
"accesses" = (reg_ids == i) ? accesses : null)))
data["regions"] = regions
return data
/datum/computer_file/program/card_mod/ui_static_data(mob/user)
var/list/data = list()
data["station_name"] = station_name()
data["centcom_access"] = is_centcom
data["minor"] = target_dept || minor ? TRUE : FALSE
if(authenticated)
data["engineering_jobs"] = format_jobs(GLOB.engineering_positions)
data["medical_jobs"] = format_jobs(GLOB.medical_positions)
data["science_jobs"] = format_jobs(GLOB.science_positions)
data["security_jobs"] = format_jobs(GLOB.security_positions)
data["cargo_jobs"] = format_jobs(GLOB.supply_positions)
data["civilian_jobs"] = format_jobs(GLOB.civilian_positions)
data["centcom_jobs"] = format_jobs(get_all_centcom_jobs())
return data
/datum/computer_file/program/card_mod/ui_act(action, params)
if(..())
return 1
@@ -127,11 +255,6 @@
mod_mode = 0
else if (params["target"] == "manage")
mod_mode = 2
if("PRG_togglea")
if(show_assignments)
show_assignments = 0
else
show_assignments = 1
if("PRG_print")
if(computer && printer) //This option should never be called if there is no printer
if(mod_mode)
@@ -270,13 +393,8 @@
j.total_positions--
opened_positions[edit_job_target]--
if("PRG_regsel")
if(!reg_ids)
reg_ids = list()
var/regsel = text2num(params["region"])
if(regsel in reg_ids)
reg_ids -= regsel
else
reg_ids += regsel
reg_ids = regsel
if(id_card)
id_card.name = text("[id_card.registered_name]'s ID Card ([id_card.assignment])")
@@ -290,133 +408,6 @@
/datum/computer_file/program/card_mod/proc/apply_access(obj/item/card/id/id_card, list/accesses)
id_card.access |= accesses
/datum/computer_file/program/card_mod/ui_data(mob/user)
var/list/data = get_header_data()
var/obj/item/computer_hardware/card_slot/card_slot
var/obj/item/computer_hardware/printer/printer
if(computer)
card_slot = computer.all_components[MC_CARD]
printer = computer.all_components[MC_PRINT]
data["mmode"] = mod_mode
var/authed = 0
if(computer)
if(card_slot)
var/obj/item/card/id/auth_card = card_slot.stored_card2
data["auth_name"] = auth_card ? strip_html_simple(auth_card.name) : "-----"
authed = authorized()
if(mod_mode == 2)
data["slots"] = list()
var/list/pos = list()
for(var/datum/job/job in SSjob.occupations)
if(job.title in blacklisted)
continue
var/list/status_open = build_manage(job,1)
var/list/status_close = build_manage(job,0)
pos.Add(list(list(
"title" = job.title,
"current" = job.current_positions,
"total" = job.total_positions,
"status_open" = (authed && !minor) ? status_open["enable"]: 0,
"status_close" = (authed && !minor) ? status_close["enable"] : 0,
"desc_open" = status_open["desc"],
"desc_close" = status_close["desc"])))
data["slots"] = pos
data["src"] = "[REF(src)]"
data["station_name"] = station_name()
if(!mod_mode)
data["manifest"] = list()
var/list/crew = list()
for(var/datum/data/record/t in sortRecord(GLOB.data_core.general))
crew.Add(list(list(
"name" = t.fields["name"],
"rank" = t.fields["rank"])))
data["manifest"] = crew
data["assignments"] = show_assignments
if(computer)
data["have_id_slot"] = !!card_slot
data["have_printer"] = !!printer
if(!card_slot && mod_mode == 1)
mod_mode = 0 //We can't modify IDs when there is no card reader
else
data["have_id_slot"] = 0
data["have_printer"] = 0
data["centcom_access"] = is_centcom
data["authenticated"] = authed
if(mod_mode == 1 && computer)
if(card_slot)
var/obj/item/card/id/id_card = card_slot.stored_card
data["has_id"] = !!id_card
data["id_rank"] = id_card && id_card.assignment ? html_encode(id_card.assignment) : "Unassigned"
data["id_owner"] = id_card && id_card.registered_name ? html_encode(id_card.registered_name) : "-----"
data["id_name"] = id_card ? strip_html_simple(id_card.name) : "-----"
if(show_assignments)
data["engineering_jobs"] = format_jobs(GLOB.engineering_positions)
data["medical_jobs"] = format_jobs(GLOB.medical_positions)
data["science_jobs"] = format_jobs(GLOB.science_positions)
data["security_jobs"] = format_jobs(GLOB.security_positions)
data["cargo_jobs"] = format_jobs(GLOB.supply_positions)
data["civilian_jobs"] = format_jobs(GLOB.civilian_positions)
data["centcom_jobs"] = format_jobs(get_all_centcom_jobs())
if(card_slot.stored_card)
var/obj/item/card/id/id_card = card_slot.stored_card
if(is_centcom)
var/list/all_centcom_access = list()
for(var/access in get_all_centcom_access())
all_centcom_access.Add(list(list(
"desc" = replacetext(get_centcom_access_desc(access), "&nbsp", " "),
"ref" = access,
"allowed" = (access in id_card.access) ? 1 : 0)))
data["all_centcom_access"] = all_centcom_access
else
var/list/regions = list()
for(var/i = 1; i <= 7; i++)
if((minor || target_dept) && !(i in region_access))
continue
var/list/accesses = list()
if(i in reg_ids)
for(var/access in get_region_accesses(i))
if (get_access_desc(access))
accesses.Add(list(list(
"desc" = replacetext(get_access_desc(access), "&nbsp", " "),
"ref" = access,
"allowed" = (access in id_card.access) ? 1 : 0)))
regions.Add(list(list(
"name" = get_region_accesses_name(i),
"regid" = i,
"selected" = (i in reg_ids) ? 1 : null,
"accesses" = accesses)))
data["regions"] = regions
data["minor"] = target_dept || minor ? 1 : 0
return data
/datum/computer_file/program/card_mod/proc/build_manage(datum/job,open = FALSE)
var/out = "Denied"
var/can_change= 0
@@ -7,10 +7,7 @@
requires_ntnet = 0
available_on_ntnet = 0
undeletable = 1
tgui_id = "ntos_file_manager"
var/open_file
var/error
tgui_id = "NtosFileManager"
/datum/computer_file/program/filemanager/ui_act(action, params)
if(..())
@@ -18,23 +15,8 @@
var/obj/item/computer_hardware/hard_drive/HDD = computer.all_components[MC_HDD]
var/obj/item/computer_hardware/hard_drive/RHDD = computer.all_components[MC_SDD]
var/obj/item/computer_hardware/printer/printer = computer.all_components[MC_PRINT]
switch(action)
if("PRG_openfile")
. = 1
open_file = params["name"]
if("PRG_newtextfile")
. = 1
var/newname = stripped_input(usr, "Enter file name or leave blank to cancel:", "File rename", max_length=50)
if(!newname)
return 1
if(!HDD)
return 1
var/datum/computer_file/data/F = new/datum/computer_file/data()
F.filename = newname
F.filetype = "TXT"
HDD.store_file(F)
if("PRG_deletefile")
. = 1
if(!HDD)
@@ -51,19 +33,6 @@
if(!file || file.undeletable)
return 1
RHDD.remove_file(file)
if("PRG_closefile")
. = 1
open_file = null
error = null
if("PRG_clone")
. = 1
if(!HDD)
return 1
var/datum/computer_file/F = HDD.find_file_by_name(params["name"])
if(!F || !istype(F))
return 1
var/datum/computer_file/C = F.clone(1)
HDD.store_file(C)
if("PRG_rename")
. = 1
if(!HDD)
@@ -74,47 +43,15 @@
var/newname = stripped_input(usr, "Enter new file name:", "File rename", file.filename, max_length=50)
if(file && newname)
file.filename = newname
if("PRG_edit")
. = 1
if(!open_file)
if("PRG_usbrenamefile")
if(!RHDD)
return 1
if(!HDD)
return 1
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
if(!F || !istype(F))
return 1
if(F.do_not_edit && (alert("WARNING: This file is not compatible with editor. Editing it may result in permanently corrupted formatting or damaged data consistency. Edit anyway?", "Incompatible File", "No", "Yes") == "No"))
return 1
// 16384 is the limit for file length in characters. Currently, papers have value of 2048 so this is 8 times as long, since we can't edit parts of the file independently.
var/newtext = stripped_multiline_input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", html_decode(F.stored_data), 16384, TRUE)
if(!newtext)
return
if(F)
var/datum/computer_file/data/backup = F.clone()
HDD.remove_file(F)
F.stored_data = newtext
F.calculate_size()
// We can't store the updated file, it's probably too large. Print an error and restore backed up version.
// This is mostly intended to prevent people from losing texts they spent lot of time working on due to running out of space.
// They will be able to copy-paste the text from error screen and store it in notepad or something.
if(!HDD.store_file(F))
error = "I/O error: Unable to overwrite file. Hard drive is probably full. You may want to backup your changes before closing this window:<br><br>[F.stored_data]<br><br>"
HDD.store_file(backup)
if("PRG_printfile")
. = 1
if(!open_file)
return 1
if(!HDD)
return 1
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
if(!F || !istype(F))
return 1
if(!printer)
error = "Missing Hardware: Your computer does not have required hardware to complete this operation."
return 1
if(!printer.print_text("<font face=\"[(computer.obj_flags & EMAGGED) ? CRAYON_FONT : PRINTER_FONT]\">" + prepare_printjob(F.stored_data) + "</font>", open_file))
error = "Hardware error: Printer was unable to print the file. It may be out of paper."
var/datum/computer_file/file = RHDD.find_file_by_name(params["name"])
if(!file || !istype(file))
return 1
var/newname = stripped_input(usr, "Enter new file name:", "File rename", file.filename, max_length=50)
if(file && newname)
file.filename = newname
if("PRG_copytousb")
. = 1
if(!HDD || !RHDD)
@@ -190,43 +127,29 @@
var/obj/item/computer_hardware/hard_drive/HDD = computer.all_components[MC_HDD]
var/obj/item/computer_hardware/hard_drive/portable/RHDD = computer.all_components[MC_SDD]
if(error)
data["error"] = error
if(open_file)
var/datum/computer_file/data/file
if(!computer || !HDD)
data["error"] = "I/O ERROR: Unable to access hard drive."
else
file = HDD.find_file_by_name(open_file)
if(!istype(file))
data["error"] = "I/O ERROR: Unable to open file."
else
data["filedata"] = parse_tags(file.stored_data)
data["filename"] = "[file.filename].[file.filetype]"
if(!computer || !HDD)
data["error"] = "I/O ERROR: Unable to access hard drive."
else
if(!computer || !HDD)
data["error"] = "I/O ERROR: Unable to access hard drive."
else
var/list/files[0]
for(var/datum/computer_file/F in HDD.stored_files)
files.Add(list(list(
var/list/files[0]
for(var/datum/computer_file/F in HDD.stored_files)
files.Add(list(list(
"name" = F.filename,
"type" = F.filetype,
"size" = F.size,
"undeletable" = F.undeletable
)))
data["files"] = files
if(RHDD)
data["usbconnected"] = TRUE
var/list/usbfiles[0]
for(var/datum/computer_file/F in RHDD.stored_files)
usbfiles.Add(list(list(
"name" = F.filename,
"type" = F.filetype,
"size" = F.size,
"undeletable" = F.undeletable
)))
data["files"] = files
if(RHDD)
data["usbconnected"] = 1
var/list/usbfiles[0]
for(var/datum/computer_file/F in RHDD.stored_files)
usbfiles.Add(list(list(
"name" = F.filename,
"type" = F.filetype,
"size" = F.size,
"undeletable" = F.undeletable
)))
data["usbfiles"] = usbfiles
data["usbfiles"] = usbfiles
return data
@@ -7,7 +7,7 @@
requires_ntnet = 1
required_access = ACCESS_NETWORK //NETWORK CONTROL IS A MORE SECURE PROGRAM.
available_on_ntnet = 1
tgui_id = "ntos_net_monitor"
tgui_id = "NtosNetMonitor"
/datum/computer_file/program/ntnetmonitor/ui_act(action, params)
if(..())
@@ -8,7 +8,7 @@
requires_ntnet_feature = NTNET_PEERTOPEER
network_destination = "other device via P2P tunnel"
available_on_ntnet = 1
tgui_id = "ntos_net_transfer"
tgui_id = "NtosNetTransfer"
var/error = "" // Error screen
var/server_password = "" // Optional password to download the file.
@@ -0,0 +1,90 @@
import { useBackend } from '../backend';
import { Box, Button, LabeledList, NoticeBox, ProgressBar, Section, Table } from '../components';
import { NtosWindow } from '../layouts';
export const NtosAiRestorer = (props, context) => {
const { act, data } = useBackend(context);
const {
restoring,
error,
name,
nocard,
isDead,
health,
no_ai,
ai_laws = [],
} = data;
return (
<NtosWindow>
<NtosWindow.Content scrollable>
<Section title="Insert AI">
<Box>
Inserted AI:
</Box>
<Button
icon="eject"
content={nocard ? "---" : name}
onClick={() => act('PRG_eject')}
disabled={nocard} />
</Section>
{!!restoring && (
<NoticeBox>
Reconstruction in progress!
</NoticeBox>
)}
{!!error && (
<NoticeBox>
ERROR: {error}
</NoticeBox>
) || (
<Section title="System Status">
<LabeledList>
<LabeledList.Item
label="AI Name">
{name}
</LabeledList.Item>
<LabeledList.Item
label="Status">
{isDead ? "Non-functional" : "Functional"}
</LabeledList.Item>
<LabeledList.Item
label="System Integrity">
<ProgressBar
minValue={0}
maxValue={100}
value={health}
ranges={{
good: [70, Infinity],
average: [50, 70],
bad: [-Infinity, 50],
}} />
</LabeledList.Item>
<LabeledList.Item
label="Active Laws" />
{ai_laws.length > 0 && (ai_laws.map((law, index) => (
<LabeledList.Item className="candystripe" key={'law_' + index.toString()}>
{law}
</LabeledList.Item>
))
) || (
<LabeledList.Item>
<NoticeBox danger>
No laws found.
</NoticeBox>
</LabeledList.Item>
)}
<LabeledList.Item
label="Operations">
<Button
icon="plus"
disabled={restoring}
onClick={() => act('PRG_beginReconstruction')} />
</LabeledList.Item>
</LabeledList>
</Section>
)}
</NtosWindow.Content>
</NtosWindow>
);
};
+461
View File
@@ -0,0 +1,461 @@
import { useBackend, useLocalState } from '../backend';
import { Box, Button, Collapsible, Flex, NoticeBox, Section, Table, Tabs } from '../components';
import { NtosWindow } from '../layouts';
export const NtosCard = (props, context) => {
const { act, data } = useBackend(context);
const {
have_id_slot,
manifest,
slots,
has_id,
authenticated,
all_centcom_access,
station_name,
regions,
id_name,
auth_name,
minor,
centcom_access,
id_owner,
id_rank,
} = data;
const [tab, setTab] = useLocalState(context, 'tab', 0);
return (
<NtosWindow>
<NtosWindow.Content scrollable>
<Tabs>
{!!have_id_slot && (
<Tabs.Tab
icon="folder-open"
selected={tab===0}
onClick={() => {
setTab(0);
act('PRG_switchm', { target: 'mod' });
}}>
Access Modification
</Tabs.Tab>
)}
<Tabs.Tab
icon="folder-open"
selected={tab===1}
onClick={() => {
setTab(1);
act('PRG_switchm', { target: 'manage' });
}}>
Job Management
</Tabs.Tab>
<Tabs.Tab
icon="folder-open"
selected={tab===2}
onClick={() => {
setTab(2);
act('PRG_switchm', { target: 'manifest' });
}}>
Crew Manifest
</Tabs.Tab>
<Button
icon="print"
content="Print"
disabled={tab===1 || (tab===0 && !has_id)}
onClick={() => act('PRG_print')} />
</Tabs>
{tab === 0 && (
<Section title="Access Modification">
<NtosCardAccessAuth id_name={id_name} auth_name={auth_name} />
{authenticated && has_id && (
<>
<NtosCardAccessDetails
minor={minor}
id_owner={id_owner}
id_rank={id_rank}
act={act} />
<NtosCardAccessAssignments centcom_access={centcom_access} />
<NtosCardAccessRegions
centcom_access={centcom_access}
all_centcom_access={all_centcom_access}
station_name={station_name}
regions={regions}
act={act} />
</>
) || null}
</Section>
)}
{tab === 1 && (
<Section title="Job Management">
<NtosCardJobManagement slots={slots} act={act} />
</Section>
)}
{tab === 2 && (
<Section title="Crew Manifest">
<NoticeBox>
Please use a <b>security records console</b> to modify entries.
</NoticeBox>
<Box>
{manifest && manifest.map(crewmember => (
<><b>{crewmember.name}</b> - {crewmember.rank}</>
))}
</Box>
</Section>
)}
</NtosWindow.Content>
</NtosWindow>
);
};
const NtosCardAccessRegions = (props, context) => {
const {
centcom_access,
all_centcom_access,
station_name,
regions = [],
act,
} = props;
const [regionTab, setRegionTab] = useLocalState(context, 'regionTab', 0);
if (centcom_access) {
return (
<Section title="Central Command" level={2}>
{all_centcom_access && all_centcom_access.map(access => (
<Button.Checkbox
key={access.desc}
content={access.desc}
checked={access.allowed}
onClick={() => act('PRG_access', {
access_target: access.ref,
allowed: access.allowed,
})} />
))}
</Section>
);
}
else {
const activeRegion = regions[regionTab];
return (
<Section title={station_name} level={2}>
<Tabs>
{regions.map(region => (
<Tabs.Tab
key={region.regid}
selected={region.selected}
onClick={() => {
act('PRG_regsel', { region: region.regid });
setRegionTab(region.regid-1);
}}>
{region.name}
</Tabs.Tab>
))}
</Tabs>
{activeRegion.accesses && (
<Box>
{activeRegion.accesses.map(access => (
<Button.Checkbox
key={access.desc}
content={access.desc}
checked={access.allowed}
onClick={() => act('PRG_access', {
access_target: access.ref,
allowed: access.allowed,
})} />
))}
</Box>
)}
</Section>
);
}
};
const NtosCardJobManagement = (props, context) => {
const { slots, act } = props;
return (
<Table>
<Table.Row header>
<Table.Cell>Job</Table.Cell>
<Table.Cell>Slots</Table.Cell>
<Table.Cell>Open Job</Table.Cell>
<Table.Cell>Close Job</Table.Cell>
</Table.Row>
{!!slots && slots.map(slot => (
<Table.Row key={slot.title}>
<Table.Cell>{slot.title}</Table.Cell>
<Table.Cell>{slot.current}/{slot.total}</Table.Cell>
<Table.Cell>
<Button
content={slot.desc_open}
disabled={!slot.status_open}
onClick={() => act('PRG_open_job', {
target: slot.title,
})} />
</Table.Cell>
<Table.Cell>
<Button
content={slot.desc_close}
disabled={!slot.status_close}
onClick={() => act('PRG_close_job', {
target: slot.title,
})} />
</Table.Cell>
</Table.Row>
))}
</Table>
);
};
const NtosCardAccessAuth = (props, context) => {
const { act, data } = useBackend(context);
const {
id_name,
auth_name,
} = props;
return (
<>
<NoticeBox>
Please insert the ID into the terminal to proceed.
</NoticeBox>
<Flex justify="space-between" direction="row" wrap="wrap">
<Flex.Item>
<Box>Target Identity:</Box>
<Button
icon="eject"
content={id_name}
onClick={() => act('PRG_eject', { target: 'id' })} />
</Flex.Item>
<Flex.Item>
<Box>Auth Identity:</Box>
<Button
icon="eject"
content={auth_name}
onClick={() => act('PRG_eject', { target: 'auth' })} />
</Flex.Item>
</Flex>
</>
);
};
const NtosCardAccessDetails = (props, context) => {
const {
minor,
id_owner,
id_rank,
act,
} = props;
return (
<Section
title="Details"
level={2}>
{!!minor && (
<>
<Box>
<b>Registered Name:</b> {id_owner}
</Box>
<Box>
<b>Rank:</b> {id_rank}
</Box>
<Box>
<Button
icon="gear"
onClick={() => act('PRG_terminate')}
disabled={id_rank === 'Unassigned'}
label={"Demote " + id_owner} />
</Box>
</>
) || (
<Box>
Registered Name:
<Button
content={id_owner.trim()}
icon="pencil-alt"
onClick={() => act('PRG_edit', { name: true })} />
</Box>
)}
</Section>
);
};
const NtosCardAccessAssignments = (props, context) => {
const { data } = useBackend(context);
const { centcom_access } = props;
const {
engineering_jobs = [],
medical_jobs = [],
science_jobs = [],
security_jobs = [],
cargo_jobs = [],
civilian_jobs = [],
centcom_jobs = [],
} = data;
return (
<Section
title="Assigments"
level={2}>
<Collapsible title="Job Presets">
<Table>
<Table.Row>
<Table.Cell header>
Special
</Table.Cell>
<Table.Cell>
<NtosCardAssignButton
selectable
icon="pencil-alt"
assignJob={{
display_name: 'Custom Job Title',
job: 'Custom',
}} />
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell header>
Command
</Table.Cell>
<Table.Cell>
<NtosCardAssignButton selectable assignJob={{
display_name: 'Captain',
job: 'Captain',
}} />
</Table.Cell>
</Table.Row>
{!!engineering_jobs && (
<Table.Row>
<Table.Cell header>
Engineering
</Table.Cell>
<Table.Cell>
{engineering_jobs.map(target => (
<NtosCardAssignButton
key={target.display_name}
selectable
assignJob={target} />
))}
</Table.Cell>
</Table.Row>
)}
{!!medical_jobs && (
<Table.Row>
<Table.Cell header>
Medical
</Table.Cell>
<Table.Cell>
{medical_jobs.map(target => (
<NtosCardAssignButton
key={target.display_name}
selectable
assignJob={target} />
))}
</Table.Cell>
</Table.Row>
)}
{!!science_jobs && (
<Table.Row>
<Table.Cell header>
Science
</Table.Cell>
<Table.Cell>
{science_jobs.map(target => (
<NtosCardAssignButton
key={target.display_name}
selectable
assignJob={target} />
))}
</Table.Cell>
</Table.Row>
)}
{!!security_jobs && (
<Table.Row>
<Table.Cell header>
Security
</Table.Cell>
<Table.Cell>
{security_jobs.map(target => (
<NtosCardAssignButton
key={target.display_name}
selectable
assignJob={target} />
))}
</Table.Cell>
</Table.Row>
)}
{!!cargo_jobs && (
<Table.Row>
<Table.Cell header>
Cargo
</Table.Cell>
<Table.Cell>
{cargo_jobs.map(target => (
<NtosCardAssignButton
key={target.display_name}
selectable
assignJob={target} />
))}
</Table.Cell>
</Table.Row>
)}
{!!civilian_jobs && (
<Table.Row>
<Table.Cell header>
Civilian
</Table.Cell>
<Table.Cell>
{civilian_jobs.map(target => (
<NtosCardAssignButton
key={target.display_name}
selectable
assignJob={target} />
))}
</Table.Cell>
</Table.Row>
)}
{!!centcom_access && !!centcom_jobs && (
<Table.Row>
<Table.Cell header>
Centcom
</Table.Cell>
<Table.Cell>
{centcom_jobs.map(target => (
<NtosCardAssignButton
key={target.display_name}
selectable
assignJob={target} />
))}
</Table.Cell>
{/* {JSON.stringify(centcom_jobs)} */}
</Table.Row>
) || null}
</Table>
</Collapsible>
</Section>
);
};
const NtosCardAssignButton = (props, context) => {
const { act, data } = useBackend(context);
const { id_rank } = data;
const { assignJob, selectable, icon } = props;
const { display_name, job } = assignJob;
return (
<Button
content={display_name}
icon={icon}
selected={selectable && id_rank === job}
onClick={() => act('PRG_assign', {
assign_target: job,
})} />
);
};
@@ -0,0 +1,100 @@
import { useBackend } from '../backend';
import { Box, Button, Divider, NoticeBox, Section, Table } from '../components';
import { NtosWindow } from '../layouts';
export const NtosFileManager = (props, context) => {
const { act, data } = useBackend(context);
const {
error,
usbconnected,
files = [],
usbfiles = [],
} = data;
if (error) {
return (
<NtosWindow>
<NtosWindow.Content scrollable>
<NoticeBox danger>
{error}
<br />
<i>Please try again. If the problem persists contact your system administrator for assistance.</i>
</NoticeBox>
</NtosWindow.Content>
</NtosWindow>
);
}
return (
<NtosWindow>
<NtosWindow.Content scrollable>
<Section title="Available files (local)">
<Table>
<Table.Row header>
<Table.Cell>File name</Table.Cell>
<Table.Cell>File type</Table.Cell>
<Table.Cell>File size (GQ)</Table.Cell>
<Table.Cell>Operations</Table.Cell>
</Table.Row>
{files.map(file => (
<Table.Row key={file.name}>
<Table.Cell>{file.name}</Table.Cell>
<Table.Cell>.{file.type}</Table.Cell>
<Table.Cell>{file.size}GQ</Table.Cell>
<Table.Cell>
<Button
content="DELETE"
disabled={file.undeletable}
onClick={() => act('PRG_deletefile', { name: file.name })} />
<Button
content="RENAME"
disabled={file.undeletable}
onClick={() => act('PRG_rename', { name: file.name })} />
{!!usbconnected && (
<Button
content="EXPORT"
disabled={file.undeletable}
onClick={() => act('PRG_copytousb', { name: file.name })} />
)}
</Table.Cell>
</Table.Row>
))}
</Table>
</Section>
{usbconnected && (
<Section title="Available files (portable device)">
<Table>
<Table.Row header>
<Table.Cell>File name</Table.Cell>
<Table.Cell>File type</Table.Cell>
<Table.Cell>File size (GQ)</Table.Cell>
<Table.Cell>Operations</Table.Cell>
</Table.Row>
{usbfiles.map(file => (
<Table.Row key={file.name}>
<Table.Cell>{file.name}</Table.Cell>
<Table.Cell>.{file.type}</Table.Cell>
<Table.Cell>{file.size}GQ</Table.Cell>
<Table.Cell>
<Button
content="DELETE"
disabled={file.undeletable}
onClick={() => act('PRG_usbdeletefile', { name: file.name })} />
<Button
content="RENAME"
disabled={file.undeletable}
onClick={() => act('PRG_usbrenamefile', { name: file.name })} />
<Button
content="IMPORT"
disabled={file.undeletable}
onClick={() => act('PRG_copyfromusb', { name: file.name })} />
</Table.Cell>
</Table.Row>
))}
</Table>
</Section>
)}
</NtosWindow.Content>
</NtosWindow>
);
};
+116
View File
@@ -0,0 +1,116 @@
import { useBackend } from '../backend';
import { Box, Button, LabeledList, NoticeBox, Section } from '../components';
import { NtosWindow } from '../layouts';
export const NtosNetDos = (props, context) => {
return (
<NtosWindow
width={400}
height={250}
theme="syndicate">
<NtosWindow.Content>
<NtosNetDosContent />
</NtosWindow.Content>
</NtosWindow>
);
};
export const NtosNetDosContent = (props, context) => {
const { act, data } = useBackend(context);
const {
relays = [],
focus,
target,
speed,
overload,
capacity,
error,
} = data;
if (error) {
return (
<>
<NoticeBox>
{error}
</NoticeBox>
<Button
fluid
content="Reset"
textAlign="center"
onClick={() => act('PRG_reset')}
/>
</>
);
}
const generate10String = length => {
let outString = "";
const factor = (overload / capacity);
while (outString.length < length) {
if (Math.random() > factor) {
outString += "0";
} else {
outString += "1";
}
}
return outString;
};
const lineLength = 45;
if (target) {
return (
<Section fontFamily="monospace" textAlign="center">
<Box>
CURRENT SPEED: {speed} GQ/s
</Box>
<Box>
{/* I don't care anymore */}
{generate10String(lineLength)}
</Box>
<Box>
{generate10String(lineLength)}
</Box>
<Box>
{generate10String(lineLength)}
</Box>
<Box>
{generate10String(lineLength)}
</Box>
<Box>
{generate10String(lineLength)}
</Box>
</Section>
);
}
return (
<Section>
<LabeledList>
<LabeledList.Item label="Target">
{relays.map(relay => (
<Button
key={relay.id}
content={relay.id}
selected={focus === relay.id}
onClick={() => act('PRG_target_relay', {
targid: relay.id,
})}
/>
))}
</LabeledList.Item>
</LabeledList>
<Button
fluid
bold
content="EXECUTE"
color="bad"
textAlign="center"
disabled={!focus}
mt={1}
onClick={() => act('PRG_execute')}
/>
</Section>
);
};
@@ -0,0 +1,142 @@
import { useBackend } from '../backend';
import { Box, Button, LabeledList, NoticeBox, NumberInput, Section } from '../components';
import { NtosWindow } from '../layouts';
export const NtosNetMonitor = (props, context) => {
const { act, data } = useBackend(context);
const {
ntnetrelays,
ntnetstatus,
idsalarm,
idsstatus,
config_softwaredownload,
config_peertopeer,
config_communication,
config_systemcontrol,
ntnetlogs = [],
ntnetmaxlogs,
} = data;
return (
<NtosWindow>
<NtosWindow.Content scrollable>
<NoticeBox>
WARNING: Disabling wireless transmitters when using
a wireless device may prevent you from reenabling them!
</NoticeBox>
<Section
title="Wireless Connectivity"
buttons={(
<Button.Confirm
icon={ntnetstatus ? 'power-off' : 'times'}
content={ntnetstatus ? 'ENABLED' : 'DISABLED'}
selected={ntnetstatus}
onClick={() => act('toggleWireless')} />
)}>
{ntnetrelays ? (
<LabeledList>
<LabeledList.Item label="Active NTNet Relays">
{ntnetrelays}
</LabeledList.Item>
</LabeledList>
) : "No Relays Connected"}
</Section>
<Section title="Firewall Configuration">
<LabeledList>
<LabeledList.Item
label="Software Downloads"
buttons={(
<Button
icon={config_softwaredownload ? 'power-off' : 'times'}
content={config_softwaredownload ? 'ENABLED' : 'DISABLED'}
selected={config_softwaredownload}
onClick={() => act('toggle_function', { id: "1" })} />
)} />
<LabeledList.Item
label="Peer to Peer Traffic"
buttons={(
<Button
icon={config_peertopeer ? 'power-off' : 'times'}
content={config_peertopeer ? 'ENABLED' : 'DISABLED'}
selected={config_peertopeer}
onClick={() => act('toggle_function', { id: "2" })} />
)} />
<LabeledList.Item
label="Communication Systems"
buttons={(
<Button
icon={config_communication ? 'power-off' : 'times'}
content={config_communication ? 'ENABLED' : 'DISABLED'}
selected={config_communication}
onClick={() => act('toggle_function', { id: "3" })} />
)} />
<LabeledList.Item
label="Remote System Control"
buttons={(
<Button
icon={config_systemcontrol ? 'power-off' : 'times'}
content={config_systemcontrol ? 'ENABLED' : 'DISABLED'}
selected={config_systemcontrol}
onClick={() => act('toggle_function', { id: "4" })} />
)} />
</LabeledList>
</Section>
<Section title="Security Systems">
{!!idsalarm && (
<>
<NoticeBox>
NETWORK INCURSION DETECTED
</NoticeBox>
<Box italics>
Abnormal activity has been detected in the network.
Check system logs for more information
</Box>
</>
)}
<LabeledList>
<LabeledList.Item
label="IDS Status"
buttons={(
<>
<Button
icon={idsstatus ? 'power-off' : 'times'}
content={idsstatus ? 'ENABLED' : 'DISABLED'}
selected={idsstatus}
onClick={() => act('toggleIDS')} />
<Button
icon="sync"
content="Reset"
color="bad"
onClick={() => act('resetIDS')} />
</>
)} />
<LabeledList.Item
label="Max Log Count"
buttons={(
<Button
value={ntnetmaxlogs}
width="39px"
onClick={() => act('updatemaxlogs')} />
)} />
</LabeledList>
<Section
title="System Log"
level={2}
buttons={(
<Button.Confirm
icon="trash"
content="Clear Logs"
onClick={() => act('purgelogs')} />
)}>
{ntnetlogs.map(log => (
<Box key={log.entry} className="candystripe">
{log.entry}
</Box>
))}
</Section>
</Section>
</NtosWindow.Content>
</NtosWindow>
);
};
@@ -0,0 +1,195 @@
import { useBackend } from '../backend';
import { Button, Box, LabeledList, ProgressBar, Section, Icon } from '../components';
import { NtosWindow } from '../layouts';
export const NtosNetTransfer = (props, context) => {
const { act, data } = useBackend(context);
const {
error,
downloading,
uploading,
upload_filelist = [],
} = data;
let body = <P2PAvailable />;
if (error) {
body = <P2PError />;
} else if (downloading) {
body = <P2PDownload />;
} else if (uploading) {
body = <P2PUpload />;
} else if (upload_filelist.length) {
body = <P2PUploadServer />;
}
return (
<NtosWindow width={575} height={700} resizable>
<NtosWindow.Content scrollable>
{body}
</NtosWindow.Content>
</NtosWindow>
);
};
const P2PError = (props, context) => {
const { act, data } = useBackend(context);
const {
error,
} = data;
return (
<Section title="An error has occured during operation." buttons={
<Button
icon="undo"
onClick={() => act("PRG_reset")}>
Reset
</Button>
}>
Additional Information: {error}
</Section>
);
};
const P2PDownload = (props, context) => {
const { act, data } = useBackend(context);
const {
download_name,
download_progress,
download_size,
download_netspeed,
} = data;
return (
<Section title="Download in progress">
<LabeledList>
<LabeledList.Item label="Downloaded File">
{download_name}
</LabeledList.Item>
<LabeledList.Item label="Progress">
<ProgressBar
value={download_progress}
maxValue={download_size}>
{download_progress} / {download_size} GQ
</ProgressBar>
</LabeledList.Item>
<LabeledList.Item label="Transfer Speed">
{download_netspeed} GQ/s
</LabeledList.Item>
<LabeledList.Item label="Controls">
<Button
icon="ban"
onClick={() => act("PRG_reset")}>
Cancel Download
</Button>
</LabeledList.Item>
</LabeledList>
</Section>
);
};
const P2PUpload = (props, context) => {
const { act, data } = useBackend(context);
const {
upload_clients,
upload_filename,
upload_haspassword,
} = data;
return (
<Section title="Server enabled">
<LabeledList>
<LabeledList.Item label="Clients Connected">
{upload_clients}
</LabeledList.Item>
<LabeledList.Item label="Provided file">
{upload_filename}
</LabeledList.Item>
<LabeledList.Item label="Server Password">
{upload_haspassword ? "Enabled" : "Disabled"}
</LabeledList.Item>
<LabeledList.Item label="Commands">
<Button
icon="lock"
onClick={() => act("PRG_setpassword")}>
Set Password
</Button>
<Button
icon="ban"
onClick={() => act("PRG_reset")}>
Cancel Upload
</Button>
</LabeledList.Item>
</LabeledList>
</Section>
);
};
const P2PUploadServer = (props, context) => {
const { act, data } = useBackend(context);
const {
upload_filelist,
} = data;
return (
<Section title="File transfer server ready." buttons={
<Button
icon="undo"
onClick={() => act("PRG_reset")}>
Cancel
</Button>
}>
<Button
fluid
icon="lock"
onClick={() => act("PRG_setpassword")}>
Set Password
</Button>
<Section title="Pick file to serve." level={2}>
{upload_filelist.map(file => (
<Button
key={file.uid}
fluid
icon="upload"
onClick={() => act("PRG_uploadfile", { id: file.uid })}>
{file.filename} ({file.size}GQ)
</Button>
))}
</Section>
</Section>
);
};
const P2PAvailable = (props, context) => {
const { act, data } = useBackend(context);
const {
servers,
} = data;
return (
<Section title="Available Files" buttons={
<Button
icon="upload"
onClick={() => act("PRG_uploadmenu")}>
Send File
</Button>
}>
{servers.length && (
<LabeledList>
{servers.map(server => (
<LabeledList.Item label={server.uid} key={server.uid}>
{!!server.haspassword && <Icon name="lock" mr={1} />}
{server.filename}&nbsp;
({server.size}GQ)&nbsp;
<Button
icon="download"
onClick={() => act("PRG_downloadfile", { uid: server.uid })}>
Download
</Button>
</LabeledList.Item>
))}
</LabeledList>
) || (
<Box>
No upload servers found.
</Box>
)}
</Section>
);
};
@@ -0,0 +1,44 @@
import { Section, Button, LabeledList } from '../components';
import { useBackend } from '../backend';
import { NtosWindow } from '../layouts';
export const NtosRevelation = (props, context) => {
const { act, data } = useBackend(context);
return (
<NtosWindow
width={400}
height={250}
theme="syndicate">
<NtosWindow.Content>
<Section>
<Button.Input
fluid
content="Obfuscate Name..."
onCommit={(e, value) => act('PRG_obfuscate', {
new_name: value,
})}
mb={1} />
<LabeledList>
<LabeledList.Item
label="Payload Status"
buttons={(
<Button
content={data.armed ? 'ARMED' : 'DISARMED'}
color={data.armed ? 'bad' : 'average'}
onClick={() => act('PRG_arm')} />
)} />
</LabeledList>
<Button
fluid
bold
icon="radiation"
content="ACTIVATE"
textAlign="center"
color="bad"
disabled={!data.armed}
onClick={() => act('PRG_activate')} />
</Section>
</NtosWindow.Content>
</NtosWindow>
);
};
@@ -0,0 +1,14 @@
import { NtosWindow } from '../layouts';
import { StationAlertConsoleContent } from './StationAlertConsole';
export const NtosStationAlertConsole = () => {
return (
<NtosWindow
width={335}
height={587}>
<NtosWindow.Content scrollable>
<StationAlertConsoleContent />
</NtosWindow.Content>
</NtosWindow>
);
};
@@ -1,59 +1,70 @@
import { Fragment } from 'inferno';
import { useBackend } from '../backend';
import { Section } from '../components';
import { Window } from '../layouts';
export const StationAlertConsole = (props, context) => {
return (
<Window>
<Window.Content scrollable>
<StationAlertConsoleContent />
</Window.Content>
</Window>
);
};
export const StationAlertConsoleContent = (props, context) => {
const { data } = useBackend(context);
const categories = data.alarms || [];
const fire = categories['Fire'] || [];
const atmos = categories['Atmosphere'] || [];
const power = categories['Power'] || [];
return (
<Window>
<Window.Content scrollable>
<Section title="Fire Alarms">
<ul>
{fire.length === 0 && (
<li className="color-good">
Systems Nominal
</li>
)}
{fire.map(alert => (
<li key={alert} className="color-average">
{alert}
</li>
))}
</ul>
</Section>
<Section title="Atmospherics Alarms">
<ul>
{atmos.length === 0 && (
<li className="color-good">
Systems Nominal
</li>
)}
{atmos.map(alert => (
<li key={alert} className="color-average">
{alert}
</li>
))}
</ul>
</Section>
<Section title="Power Alarms">
<ul>
{power.length === 0 && (
<li className="color-good">
Systems Nominal
</li>
)}
{power.map(alert => (
<li key={alert} className="color-average">
{alert}
</li>
))}
</ul>
</Section>
</Window.Content>
</Window>
<Fragment>
<Section title="Fire Alarms">
<ul>
{fire.length === 0 && (
<li className="color-good">
Systems Nominal
</li>
)}
{fire.map(alert => (
<li key={alert} className="color-average">
{alert}
</li>
))}
</ul>
</Section>
<Section title="Atmospherics Alarms">
<ul>
{atmos.length === 0 && (
<li className="color-good">
Systems Nominal
</li>
)}
{atmos.map(alert => (
<li key={alert} className="color-average">
{alert}
</li>
))}
</ul>
</Section>
<Section title="Power Alarms">
<ul>
{power.length === 0 && (
<li className="color-good">
Systems Nominal
</li>
)}
{power.map(alert => (
<li key={alert} className="color-average">
{alert}
</li>
))}
</ul>
</Section>
</Fragment>
);
};
@@ -0,0 +1,297 @@
import { sortBy } from 'common/collections';
import { useSharedState } from '../../backend';
import { Button, Flex, Section, Tabs } from '../../components';
export const AccessList = (props, context) => {
const {
accesses = [],
wildcardSlots = {},
selectedList = [],
accessMod,
trimAccess = [],
accessFlags = {},
accessFlagNames = {},
wildcardFlags = {},
extraButtons,
showBasic,
} = props;
const [
wildcardTab,
setWildcardTab,
] = useSharedState(context, "wildcardSelected", showBasic ? "None" : Object.keys(wildcardSlots)[0]);
let selectedWildcard;
if ((wildcardTab !== "None") && !wildcardSlots[wildcardTab]) {
selectedWildcard = showBasic ? "None" : Object.keys(wildcardSlots)[0];
setWildcardTab(selectedWildcard);
}
else {
selectedWildcard = wildcardTab;
}
const parsedRegions = [];
const selectedTrimAccess = [];
accesses.forEach(region => {
const regionName = region.name;
const regionAccess = region.accesses;
const parsedRegion = {
name: regionName,
accesses: [],
hasSelected: false,
allSelected: true,
};
// If we're showing the basic accesses included as part of the trim,
// we want to figure out how many are selected for later formatting
// logic.
if (showBasic) {
regionAccess.forEach(access => {
if (trimAccess.includes(access.ref)
&& selectedList.includes(access.ref)
&& !selectedTrimAccess.includes(access.ref)
) {
selectedTrimAccess.push(access.ref);
}
});
}
// If there's no wildcard selected, grab accesses in
// the trimAccess list as they require no wildcard.
if (selectedWildcard === "None") {
regionAccess.forEach(access => {
if (!trimAccess.includes(access.ref)) {
return;
}
parsedRegion.accesses.push(access);
if (selectedList.includes(access.ref)) {
parsedRegion.hasSelected = true;
}
else {
parsedRegion.allSelected = false;
}
});
if (parsedRegion.accesses.length) {
parsedRegions.push(parsedRegion);
}
return;
}
// Otherwise, a trim is selected. We want to grab all
// accesses not in trimAccess that are compatible with
// the given wildcard.
regionAccess.forEach(access => {
if (trimAccess.includes(access.ref)) {
return;
}
if (accessFlags[access.ref] & wildcardFlags[selectedWildcard]) {
parsedRegion.accesses.push(access);
if (selectedList.includes(access.ref)) {
parsedRegion.hasSelected = true;
}
else {
parsedRegion.allSelected = false;
}
}
});
if (parsedRegion.accesses.length) {
parsedRegions.push(parsedRegion);
}
});
return (
<Section
title="Access"
buttons={extraButtons} >
<Flex wrap="wrap">
<Flex.Item width="100%">
<FormatWildcards
wildcardSlots={wildcardSlots}
selectedList={selectedList}
showBasic={showBasic}
basicUsed={selectedTrimAccess.length}
basicMax={trimAccess.length} />
</Flex.Item>
<Flex.Item>
<RegionTabList
accesses={parsedRegions} />
</Flex.Item>
<Flex.Item grow={1}>
<RegionAccessList
accesses={parsedRegions}
selectedList={selectedList}
accessMod={accessMod}
trimAccess={trimAccess}
accessFlags={accessFlags}
accessFlagNames={accessFlagNames}
wildcardSlots={wildcardSlots}
showBasic={showBasic} />
</Flex.Item>
</Flex>
</Section>
);
};
export const FormatWildcards = (props, context) => {
const {
wildcardSlots = {},
showBasic,
basicUsed = 0,
basicMax = 0,
} = props;
const [
wildcardTab,
setWildcardTab,
] = useSharedState(context, "wildcardSelected", showBasic ? "None" : Object.keys(wildcardSlots)[0]);
let selectedWildcard;
if ((wildcardTab !== "None") && !wildcardSlots[wildcardTab]) {
selectedWildcard = showBasic ? "None" : Object.keys(wildcardSlots)[0];
setWildcardTab(selectedWildcard);
}
else {
selectedWildcard = wildcardTab;
}
return (
<Tabs>
{showBasic && (
<Tabs.Tab
selected={selectedWildcard === "None"}
onClick={() => setWildcardTab("None")} >
Trim:<br />{basicUsed + "/" + basicMax}
</Tabs.Tab>
)}
{Object.keys(wildcardSlots).map(wildcard => {
const wcObj = wildcardSlots[wildcard];
let wcLimit = wcObj.limit;
const wcUsage = wcObj.usage.length;
const wcLeft = wcLimit - wcUsage;
if (wcLeft < 0) {
wcLimit = "∞";
}
const wcLeftStr = `${wcUsage}/${wcLimit}`;
return (
<Tabs.Tab
key={wildcard}
selected={selectedWildcard === wildcard}
onClick={() => setWildcardTab(wildcard)} >
{wildcard + ":"}<br />{wcLeftStr}
</Tabs.Tab>
);
})}
</Tabs>
);
};
const RegionTabList = (props, context) => {
const {
accesses = [],
} = props;
const [
selectedAccessName,
setSelectedAccessName,
] = useSharedState(context, 'accessName', accesses[0]?.name);
return (
<Tabs vertical>
{accesses.map(access => {
const icon = (access.allSelected && "check")
|| (access.hasSelected && "minus")
|| "times";
return (
<Tabs.Tab
key={access.name}
icon={icon}
minWidth={"100%"}
altSelection
selected={access.name === selectedAccessName}
onClick={() => setSelectedAccessName(access.name)}>
{access.name}
</Tabs.Tab>
);
})}
</Tabs>
);
};
const RegionAccessList = (props, context) => {
const {
accesses = [],
selectedList = [],
accessMod,
trimAccess = [],
accessFlags = {},
accessFlagNames = {},
wildcardSlots = {},
showBasic,
} = props;
const [
wildcardTab,
setWildcardTab,
] = useSharedState(context, "wildcardSelected", showBasic ? "None" : Object.keys(wildcardSlots)[0]);
let selWildcard;
if ((wildcardTab !== "None") && !wildcardSlots[wildcardTab]) {
selWildcard = showBasic ? "None" : Object.keys(wildcardSlots)[0];
setWildcardTab(selWildcard);
}
else {
selWildcard = wildcardTab;
}
const [
selectedAccessName,
] = useSharedState(context, 'accessName', accesses[0]?.name);
const selectedAccess = accesses
.find(access => access.name === selectedAccessName);
const selectedAccessEntries = sortBy(
entry => entry.desc,
)(selectedAccess?.accesses || []);
const allWildcards = Object.keys(wildcardSlots);
let wcAccess = {};
allWildcards.forEach(wildcard => {
wildcardSlots[wildcard].usage.forEach(access => {
wcAccess[access] = wildcard;
});
});
const wildcard = wildcardSlots[selWildcard];
// If there's no wildcard, -1 limit as there's infinite basic slots.
const wcLimit = wildcard ? wildcard.limit : -1;
const wcUsage = wildcard ? wildcard.usage.length : 0;
const wcAvail = wcLimit - wcUsage;
return (
selectedAccessEntries.map(entry => {
const id = entry.ref;
const disableButton = (
((wcAvail === 0) && (wcAccess[id] !== selWildcard))
|| ((wcAvail > 0) && wcAccess[id] && wcAccess[id] !== selWildcard));
const entryName = (!wcAccess[id] && trimAccess.includes(id))
? entry.desc
: entry.desc + " (" + accessFlagNames[accessFlags[id]] + ")";
return (
<Button.Checkbox
ml={1}
fluid
key={entry.desc}
content={entryName}
disabled={disableButton}
checked={selectedList.includes(entry.ref)}
onClick={() => accessMod(
entry.ref,
(selWildcard === "None") ? null : selWildcard)} />
);
})
);
};
File diff suppressed because one or more lines are too long