Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions archinstall/lib/disk/encryption_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,21 +262,21 @@ def select_encrypted_password() -> Password | None:


def select_hsm(preset: Fido2Device | None = None) -> Fido2Device | None:
header = str(_('Select a FIDO2 device to use for HSM'))
header = str(_('Select a FIDO2 device to use for HSM')) + '\n'

try:
fido_devices = Fido2.get_fido2_devices()
except ValueError:
return None

if fido_devices:
group, table_header = MenuHelper.create_table(data=fido_devices)
header = f'{header}\n\n{table_header}'
group = MenuHelper(data=fido_devices).create_menu_group()

result = SelectMenu[Fido2Device](
group,
header=header,
alignment=Alignment.CENTER,
allow_skip=True
).run()

match result.type_:
Expand Down Expand Up @@ -307,13 +307,14 @@ def select_partitions_to_encrypt(
avail_partitions = [p for p in partitions if not p.exists()]

if avail_partitions:
group, header = MenuHelper.create_table(data=avail_partitions)
group = MenuHelper(data=avail_partitions).create_menu_group()
group.set_selected_by_value(preset)

result = SelectMenu[PartitionModification](
group,
header=header,
alignment=Alignment.CENTER,
multi=True
multi=True,
allow_skip=True
).run()

match result.type_:
Expand All @@ -335,11 +336,10 @@ def select_lvm_vols_to_encrypt(
volumes: list[LvmVolume] = lvm_config.get_all_volumes()

if volumes:
group, header = MenuHelper.create_table(data=volumes)
group = MenuHelper(data=volumes).create_menu_group()

result = SelectMenu[LvmVolume](
group,
header=header,
alignment=Alignment.CENTER,
multi=True
).run()
Expand Down
3 changes: 1 addition & 2 deletions archinstall/lib/interactions/disk_conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,12 @@ def _preview_device_selection(item: MenuItem) -> str | None:
options = [d.device_info for d in devices]
presets = [p.device_info for p in preset]

group, header = MenuHelper.create_table(data=options)
group = MenuHelper(options).create_menu_group()
group.set_selected_by_value(presets)
group.set_preview_for_all(_preview_device_selection)

result = SelectMenu[_DeviceInfo](
group,
header=header,
alignment=Alignment.CENTER,
search_enabled=False,
multi=True,
Expand Down
6 changes: 3 additions & 3 deletions archinstall/lib/menu/abstract_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ def __exit__(self, *args: Any, **kwargs: Any) -> None:
self.sync_all_to_config()

def _sync_from_config(self) -> None:
for item in self._menu_item_group.menu_items:
for item in self._menu_item_group._menu_items:
if item.key is not None and not item.key.startswith(CONFIG_KEY):
config_value = getattr(self._config, item.key)
if config_value is not None:
item.value = config_value

def sync_all_to_config(self) -> None:
for item in self._menu_item_group.menu_items:
for item in self._menu_item_group._menu_items:
if item.key:
setattr(self._config, item.key, item.value)

Expand Down Expand Up @@ -135,7 +135,7 @@ def __init__(
allow_reset: bool = False
):
back_text = f'{Chars.Right_arrow} ' + str(_('Back'))
item_group.menu_items.append(MenuItem(text=back_text))
item_group.add_item(MenuItem(text=back_text))

super().__init__(
item_group,
Expand Down
65 changes: 12 additions & 53 deletions archinstall/lib/menu/list_manager.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import copy
from typing import TYPE_CHECKING, Any, cast
from typing import TYPE_CHECKING, cast

from archinstall.lib.menu.menu_helper import MenuHelper
from archinstall.tui.curses_menu import SelectMenu
from archinstall.tui.menu_item import MenuItem, MenuItemGroup
from archinstall.tui.result import ResultType
from archinstall.tui.types import Alignment

from ..output import FormattedOutput

if TYPE_CHECKING:
from collections.abc import Callable

Expand Down Expand Up @@ -63,23 +62,23 @@ def is_last_choice_cancel(self) -> bool:
return False

def run(self) -> list[ValueT]:
while True:
# this will return a dictionary with the key as the menu entry to be displayed
# and the value is the original value from the self._data container
data_formatted = self.reformat(self._data)
options = self._prepare_selection(data_formatted)
additional_options = self._base_actions + self._terminate_actions

header = self._get_header(data_formatted)
while True:
group = MenuHelper(
data=self._data,
additional_options=additional_options
).create_menu_group()

prompt = None
if self._prompt is not None:
header = f'{self._prompt}\n\n{header}'
prompt = f'{self._prompt}\n\n'

items = [MenuItem(o[0], value=o[1]) for o in options]
group = MenuItemGroup(items, sort_items=False)
prompt = None

result = SelectMenu[ValueT | str](
group,
header=header,
header=prompt,
search_enabled=False,
allow_skip=False,
alignment=Alignment.CENTER
Expand Down Expand Up @@ -109,25 +108,6 @@ def run(self) -> list[ValueT]:
else:
return self._data

def _get_header(self, data_formatted: dict[str, Any]) -> str:
table_header = [key for key, val in data_formatted.items() if val is None]
header = '\n'.join(table_header)
return header

def _prepare_selection(self, data_formatted: dict[str, Any]) -> list[tuple[str, str | ValueT]]:
# header rows are mapped to None so make sure
# to exclude those from the selectable data
options = [(key, val) for key, val in data_formatted.items() if val is not None]

if len(options) > 0:
options.append((self._separator, None))

additional_options = self._base_actions + self._terminate_actions
for o in additional_options:
options.append((o, o))

return options

def _run_actions_on_entry(self, entry: ValueT) -> None:
options = self.filter_options(entry, self._sub_menu_actions) + [self._cancel_action]

Expand All @@ -153,27 +133,6 @@ def _run_actions_on_entry(self, entry: ValueT) -> None:
if value != self._cancel_action:
self._data = self.handle_action(value, entry, self._data)

def reformat(self, data: list[Any]) -> dict[str, Any | None]:
"""
Default implementation of the table to be displayed.
Override if any custom formatting is needed
"""
display_data: dict[str, Any | None] = {}

if data:
table = FormattedOutput.as_table(data)
rows = table.split('\n')

# these are the header rows of the table and do not map to any User obviously
# we're adding 2 spaces as prefix because the menu selector '> ' will be put before
# the selectable rows so the header has to be aligned
display_data = {f'{rows[0]}': None, f'{rows[1]}': None}

for row, entry in zip(rows[2:], data):
display_data[row] = entry

return display_data

def selected_action_display(self, selection: ValueT) -> str:
"""
this will return the value to be displayed in the
Expand Down
87 changes: 41 additions & 46 deletions archinstall/lib/menu/menu_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,52 @@


class MenuHelper:
@staticmethod
def create_table(
data: list[Any] | None = None,
table_data: tuple[list[Any], str] | None = None,
) -> tuple[MenuItemGroup, str]:
if data is not None:
table_text = FormattedOutput.as_table(data)
rows = table_text.split('\n')
table = MenuHelper._create_table(data, rows)
elif table_data is not None:
# we assume the table to be
# h1 | h2
# -----------
# r1 | r2
data = table_data[0]
rows = table_data[1].split('\n')
table = MenuHelper._create_table(data, rows)
else:
raise ValueError('Either "data" or "table_data" must be provided')

table, header = MenuHelper._prepare_selection(table)

items = [
MenuItem(text, value=entry)
for text, entry in table.items()
]
def __init__(
self,
data: list[Any],
additional_options: list[str] = []
) -> None:
self._separator = ''
self._data = data
self._additional_options = additional_options

def create_menu_group(self) -> MenuItemGroup:
table_data_mapping = self._table_to_data_mapping(self._data)

items = []
for key, value in table_data_mapping.items():
item = MenuItem(key, value=value)

if value is None:
item.read_only = True

items.append(item)

group = MenuItemGroup(items, sort_items=False)

return group, header
return group

@staticmethod
def _create_table(data: list[Any], rows: list[str], header_padding: int = 2) -> dict[str, Any]:
# these are the header rows of the table and do not map to any data obviously
# we're adding 2 spaces as prefix because the menu selector '> ' will be put before
# the selectable rows so the header has to be aligned
padding = ' ' * header_padding
display_data = {f'{padding}{rows[0]}': None, f'{padding}{rows[1]}': None}
def _get_table_header(self, data_formatted: dict[str, Any]) -> list[str]:
table_header = [key for key, val in data_formatted.items() if val is None]
return table_header

for row, entry in zip(rows[2:], data):
display_data[row] = entry
def _table_to_data_mapping(self, data: list[Any]) -> dict[str, Any | None]:
display_data: dict[str, Any | None] = {}

return display_data
if data:
table = FormattedOutput.as_table(data)
rows = table.split('\n')

# these are the header rows of the table
display_data = {f'{rows[0]}': None, f'{rows[1]}': None}

@staticmethod
def _prepare_selection(table: dict[str, Any]) -> tuple[dict[str, Any], str]:
# header rows are mapped to None so make sure to exclude those from the selectable data
options = {key: val for key, val in table.items() if val is not None}
header = ''
for row, entry in zip(rows[2:], data):
display_data[row] = entry

if len(options) > 0:
table_header = [key for key, val in table.items() if val is None]
header = '\n'.join(table_header)
if self._additional_options:
display_data[self._separator] = None

return options, header
for option in self._additional_options:
display_data[option] = option

return display_data
Loading