Skip to content

Commit

Permalink
Revert of a Revert | ListInputModal (#82854)
Browse files Browse the repository at this point in the history
This reverts commit 9acf5bd.

MSO determined that because we use `file(...)` instead of a string
instead of an asset being locked to its initial state via a cache object
we are sending it as it is on disk every time. which means that when a
new server deployment updates the tgui it will send this new tgui code
even if the currently running DM code does not support it.
  • Loading branch information
ZephyrTFA committed Apr 26, 2024
1 parent cd29b12 commit cf4cc89
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 97 deletions.
22 changes: 22 additions & 0 deletions code/modules/asset_cache/assets/tgui.dm
@@ -1,3 +1,23 @@
// If you use a file(...) object, instead of caching the asset it will be loaded from disk every time it's requested.
// This is useful for development, but not recommended for production.
// And if TGS is defined, we're being run in a production environment.

#ifdef TGS
/datum/asset/simple/tgui
keep_local_name = FALSE
assets = list(
"tgui.bundle.js" = "tgui/public/tgui.bundle.js",
"tgui.bundle.css" = "tgui/public/tgui.bundle.css",
)

/datum/asset/simple/tgui_panel
keep_local_name = FALSE
assets = list(
"tgui-panel.bundle.js" = "tgui/public/tgui-panel.bundle.js",
"tgui-panel.bundle.css" = "tgui/public/tgui-panel.bundle.css",
)

#else
/datum/asset/simple/tgui
keep_local_name = TRUE
assets = list(
Expand All @@ -11,3 +31,5 @@
"tgui-panel.bundle.js" = file("tgui/public/tgui-panel.bundle.js"),
"tgui-panel.bundle.css" = file("tgui/public/tgui-panel.bundle.css"),
)

#endif
2 changes: 1 addition & 1 deletion code/modules/tgui_input/list.dm
Expand Up @@ -111,7 +111,7 @@
/datum/tgui_list_input/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ListInputModal")
ui = new(user, src, "ListInputWindow")
ui.open()

/datum/tgui_list_input/ui_close(mob/user)
Expand Down
Expand Up @@ -7,35 +7,26 @@ import {
KEY_ESCAPE,
KEY_UP,
KEY_Z,
} from '../../common/keycodes';
import { useBackend } from '../backend';
import { Autofocus, Button, Input, Section, Stack } from '../components';
import { Window } from '../layouts';
import { InputButtons } from './common/InputButtons';
import { Loader } from './common/Loader';
} from '../../../common/keycodes';
import { useBackend } from '../../backend';
import { Autofocus, Button, Input, Section, Stack } from '../../components';
import { InputButtons } from '../common/InputButtons';

type ListInputData = {
init_value: string;
type ListInputModalProps = {
items: string[];
large_buttons: boolean;
default_item: string;
message: string;
timeout: number;
title: string;
on_selected: (entry: string) => void;
on_cancel: () => void;
};

export const ListInputModal = (props) => {
const { act, data } = useBackend<ListInputData>();
const {
items = [],
message = '',
init_value,
large_buttons,
timeout,
title,
} = data;
const [selected, setSelected] = useState(items.indexOf(init_value));
export const ListInputModal = (props: ListInputModalProps) => {
const { items = [], default_item, message, on_selected, on_cancel } = props;

const [selected, setSelected] = useState(items.indexOf(default_item));
const [searchBarVisible, setSearchBarVisible] = useState(items.length > 9);
const [searchQuery, setSearchQuery] = useState('');

// User presses up or down on keyboard
// Simulates clicking an item
const onArrowKey = (key: number) => {
Expand Down Expand Up @@ -99,82 +90,77 @@ export const ListInputModal = (props) => {
const filteredItems = items.filter((item) =>
item?.toLowerCase().includes(searchQuery.toLowerCase()),
);
// Dynamically changes the window height based on the message.
const windowHeight =
325 + Math.ceil(message.length / 3) + (large_buttons ? 5 : 0);
// Grabs the cursor when no search bar is visible.
if (!searchBarVisible) {
setTimeout(() => document!.getElementById(selected.toString())?.focus(), 1);
}

return (
<Window title={title} width={325} height={windowHeight}>
{timeout && <Loader value={timeout} />}
<Window.Content
onKeyDown={(event) => {
const keyCode = window.event ? event.which : event.keyCode;
if (keyCode === KEY_DOWN || keyCode === KEY_UP) {
event.preventDefault();
onArrowKey(keyCode);
}
if (keyCode === KEY_ENTER) {
event.preventDefault();
act('submit', { entry: filteredItems[selected] });
}
if (!searchBarVisible && keyCode >= KEY_A && keyCode <= KEY_Z) {
event.preventDefault();
onLetterSearch(keyCode);
}
if (keyCode === KEY_ESCAPE) {
event.preventDefault();
act('cancel');
}
}}
>
<Section
buttons={
<Button
compact
icon={searchBarVisible ? 'search' : 'font'}
selected
tooltip={
searchBarVisible
? 'Search Mode. Type to search or use arrow keys to select manually.'
: 'Hotkey Mode. Type a letter to jump to the first match. Enter to select.'
}
tooltipPosition="left"
onClick={() => onSearchBarToggle()}
/>
<Section
onKeyDown={(event) => {
const keyCode = window.event ? event.which : event.keyCode;
if (keyCode === KEY_DOWN || keyCode === KEY_UP) {
event.preventDefault();
onArrowKey(keyCode);
}
if (keyCode === KEY_ENTER) {
event.preventDefault();
on_selected(filteredItems[selected]);
}
if (!searchBarVisible && keyCode >= KEY_A && keyCode <= KEY_Z) {
event.preventDefault();
onLetterSearch(keyCode);
}
if (keyCode === KEY_ESCAPE) {
event.preventDefault();
on_cancel();
}
}}
buttons={
<Button
compact
icon={searchBarVisible ? 'search' : 'font'}
selected
tooltip={
searchBarVisible
? 'Search Mode. Type to search or use arrow keys to select manually.'
: 'Hotkey Mode. Type a letter to jump to the first match. Enter to select.'
}
className="ListInput__Section"
fill
title={message}
>
<Stack fill vertical>
<Stack.Item grow>
<ListDisplay
filteredItems={filteredItems}
onClick={onClick}
onFocusSearch={onFocusSearch}
searchBarVisible={searchBarVisible}
selected={selected}
/>
</Stack.Item>
{searchBarVisible && (
<SearchBar
filteredItems={filteredItems}
onSearch={onSearch}
searchQuery={searchQuery}
selected={selected}
/>
)}
<Stack.Item>
<InputButtons input={filteredItems[selected]} />
</Stack.Item>
</Stack>
</Section>
</Window.Content>
</Window>
tooltipPosition="left"
onClick={() => onSearchBarToggle()}
/>
}
className="ListInput__Section"
fill
title={message}
>
<Stack fill vertical>
<Stack.Item grow>
<ListDisplay
filteredItems={filteredItems}
onClick={onClick}
onFocusSearch={onFocusSearch}
searchBarVisible={searchBarVisible}
selected={selected}
/>
</Stack.Item>
{searchBarVisible && (
<SearchBar
filteredItems={filteredItems}
onSearch={onSearch}
searchQuery={searchQuery}
selected={selected}
/>
)}
<Stack.Item>
<InputButtons
input={filteredItems[selected]}
on_submit={() => on_selected(filteredItems[selected])}
on_cancel={on_cancel}
/>
</Stack.Item>
</Stack>
</Section>
);
};

Expand All @@ -183,7 +169,7 @@ export const ListInputModal = (props) => {
* If a search query is provided, filters the items.
*/
const ListDisplay = (props) => {
const { act } = useBackend<ListInputData>();
const { act } = useBackend();
const { filteredItems, onClick, onFocusSearch, searchBarVisible, selected } =
props;

Expand Down Expand Up @@ -227,7 +213,7 @@ const ListDisplay = (props) => {
* Closing the bar defaults input to an empty string.
*/
const SearchBar = (props) => {
const { act } = useBackend<ListInputData>();
const { act } = useBackend();
const { filteredItems, onSearch, searchQuery, selected } = props;

return (
Expand Down
44 changes: 44 additions & 0 deletions tgui/packages/tgui/interfaces/ListInputWindow/index.tsx
@@ -0,0 +1,44 @@
import { useBackend } from '../../backend';
import { Window } from '../../layouts';
import { Loader } from '../common/Loader';
import { ListInputModal } from './ListInputModal';

type ListInputData = {
init_value: string;
items: string[];
large_buttons: boolean;
message: string;
timeout: number;
title: string;
};

export const ListInputWindow = () => {
const { act, data } = useBackend<ListInputData>();
const {
items = [],
message = '',
init_value,
large_buttons,
timeout,
title,
} = data;

// Dynamically changes the window height based on the message.
const windowHeight =
325 + Math.ceil(message.length / 3) + (large_buttons ? 5 : 0);

return (
<Window title={title} width={325} height={windowHeight}>
{timeout && <Loader value={timeout} />}
<Window.Content>
<ListInputModal
items={items}
default_item={init_value}
message={message}
on_selected={(entry) => act('submit', { entry })}
on_cancel={() => act('cancel')}
/>
</Window.Content>
</Window>
);
};
23 changes: 20 additions & 3 deletions tgui/packages/tgui/interfaces/common/InputButtons.tsx
Expand Up @@ -8,19 +8,36 @@ type InputButtonsData = {

type InputButtonsProps = {
input: string | number | string[];
on_submit?: () => void;
on_cancel?: () => void;
message?: string;
};

export const InputButtons = (props: InputButtonsProps) => {
const { act, data } = useBackend<InputButtonsData>();
const { large_buttons, swapped_buttons } = data;
const { input, message } = props;
const { input, message, on_submit, on_cancel } = props;

let on_submit_actual = on_submit;
if (!on_submit_actual) {
on_submit_actual = () => {
act('submit', { entry: input });
};
}

let on_cancel_actual = on_cancel;
if (!on_cancel_actual) {
on_cancel_actual = () => {
act('cancel');
};
}

const submitButton = (
<Button
color="good"
fluid={!!large_buttons}
height={!!large_buttons && 2}
onClick={() => act('submit', { entry: input })}
onClick={on_submit_actual}
m={0.5}
pl={2}
pr={2}
Expand All @@ -37,7 +54,7 @@ export const InputButtons = (props: InputButtonsProps) => {
color="bad"
fluid={!!large_buttons}
height={!!large_buttons && 2}
onClick={() => act('cancel')}
onClick={on_cancel_actual}
m={0.5}
pl={2}
pr={2}
Expand Down

0 comments on commit cf4cc89

Please sign in to comment.