Skip to content
Open
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
13 changes: 1 addition & 12 deletions archinstall/lib/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,10 @@ def as_summary(self) -> str:
label_width = max(len(label) for label, _ in rows) + 2
return '\n'.join(f'{label:<{label_width}}{value}' for label, value in rows)

async def confirm_config(self, show_install_warnings: bool = False) -> bool:
async def confirm_config(self) -> bool:
header = f'{tr("The specified configuration will be applied")}. '
header += tr('Would you like to continue?') + '\n'

if show_install_warnings:
header += self._render_install_warnings()

group = MenuItemGroup.yes_no()
group.set_preview_for_all(lambda x: self.user_config_to_json())

Expand All @@ -156,14 +153,6 @@ def get_install_warnings(self) -> list[str]:

return warnings

def _render_install_warnings(self) -> str:
warnings = self.get_install_warnings()

if not warnings:
return ''

return '\n' + '\n'.join(f'[yellow]{w}[/]' for w in warnings) + '\n'

def _is_valid_path(self, dest_path: Path) -> bool:
dest_path_ok = dest_path.exists() and dest_path.is_dir()
if not dest_path_ok:
Expand Down
46 changes: 35 additions & 11 deletions archinstall/lib/global_menu.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from typing import override

from rich.markup import escape as _escape_markup

from archinstall.default_profiles.profile import GreeterType
from archinstall.lib.applications.application_menu import ApplicationMenu
from archinstall.lib.args import ArchConfig
Expand Down Expand Up @@ -183,6 +185,7 @@ def _get_menu_options(self) -> list[MenuItem]:
MenuItem(
text=tr('Install'),
preview_action=self._prev_install_invalid_config,
preview_markup=True,
key=SpecialMenuKey.INSTALL.value,
),
MenuItem(
Expand Down Expand Up @@ -495,20 +498,41 @@ def _validate_bootloader(self) -> str | None:
return None

def _prev_install_invalid_config(self, item: MenuItem) -> str | None:
if missing := self._missing_configs():
text = tr('Missing configurations:\n')
for m in missing:
text += f'- {m}\n'
return text[:-1] # remove last new line
self.sync_all_to_config()
config_output = ConfigurationOutput(self._arch_config)

if error := self._validate_bootloader():
return tr(f'Invalid configuration: {error}')
warnings = config_output.get_install_warnings()
warnings_text = ''
if warnings:
warnings_text = f'\n\n[yellow]{_escape_markup(tr("Warnings:"))}\n'
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets reuse the pattern we have with the Input validation

class InputInfoType(Enum):
	MsgInfo = auto()
	MsgWarning = auto()
	MsgError = auto()


@dataclass
class InputInfo:
	message: str
	info_type: InputInfoType

which means the preview_action return value should be changed from a str to a dataclass holding different attributes, for now only the type. We can probably rename the InputInfoType to MsgLevelType and reuse that.

Then the MenuItem becomes something like

@dataclass
class PreviewActionResult:
	message: str
	msg_level_type: MsgLevelType


preview_action: Callable[[Self], PreviewActionResult | None] | None = None

for w in warnings:
warnings_text += f'- {_escape_markup(w)}\n'
warnings_text = warnings_text.rstrip('\n') + '[/yellow]'

self.sync_all_to_config()
summary = ConfigurationOutput(self._arch_config).as_summary()
blocks = ''

if missing := self._missing_configs():
text = f'[red]{_escape_markup(tr("Missing configurations:"))}\n'
for m in missing:
text += f'- {_escape_markup(m)}\n'
blocks += text.rstrip('\n') + '[/red]'

disk_item = self._item_group.find_by_key('disk_config')
if disk_item.has_value():
if error := self._validate_bootloader():
if blocks:
blocks += '\n\n'
text = f'[red]{_escape_markup(tr("Invalid configuration:"))}\n'
text += f'- {_escape_markup(error)}'
blocks += text + '[/red]'

if blocks:
return blocks + warnings_text

summary = config_output.as_summary()
if summary:
return f'{tr("Ready to install")}\n\n{summary}'
return tr('Ready to install')
return f'[green]{_escape_markup(tr("Ready to install"))}[/green]{warnings_text}\n\n{_escape_markup(summary)}'
return f'[green]{_escape_markup(tr("Ready to install"))}[/green]{warnings_text}'

def _prev_profile(self, item: MenuItem) -> str | None:
profile_config: ProfileConfiguration | None = item.value
Expand Down
2 changes: 1 addition & 1 deletion archinstall/scripts/guided.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ def main(arch_config_handler: ArchConfigHandler | None = None) -> None:

if not arch_config_handler.args.silent:
aborted = False
res: bool = tui.run(lambda: config.confirm_config(show_install_warnings=True))
res: bool = tui.run(config.confirm_config)

if not res:
debug('Installation aborted')
Expand Down
2 changes: 1 addition & 1 deletion archinstall/scripts/minimal.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ async def main(arch_config_handler: ArchConfigHandler | None = None) -> None:

if not arch_config_handler.args.silent:
aborted = False
res: bool = tui.run(lambda: config.confirm_config(show_install_warnings=True))
res: bool = tui.run(config.confirm_config)

if not res:
debug('Installation aborted')
Expand Down
13 changes: 9 additions & 4 deletions archinstall/tui/ui/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from enum import Enum, auto
from typing import Any, ClassVar, Literal, TypeVar, cast, override

from rich.text import Text
from textual import work
from textual.app import App, ComposeResult
from textual.binding import Binding, BindingsMap
Expand Down Expand Up @@ -359,7 +360,8 @@ def _set_preview(self, item_id: str) -> None:
maybe_preview = item.preview_action(item)

if maybe_preview is not None:
preview_widget.update(maybe_preview)
content = Text.from_markup(maybe_preview) if item.preview_markup else maybe_preview
preview_widget.update(content)
return

preview_widget.update('')
Expand Down Expand Up @@ -601,7 +603,8 @@ def _set_preview(self, item: MenuItem) -> None:
if item.preview_action is not None:
maybe_preview = item.preview_action(item)
if maybe_preview is not None:
preview_widget.update(maybe_preview)
content = Text.from_markup(maybe_preview) if item.preview_markup else maybe_preview
preview_widget.update(content)
return

preview_widget.update('')
Expand Down Expand Up @@ -726,7 +729,8 @@ def _update_selection(self) -> None:
else:
text = focused.preview_action(focused)
if text is not None:
preview.update(text)
content = Text.from_markup(text) if focused.preview_markup else text
preview.update(content)
else:
button.remove_class('-active')

Expand Down Expand Up @@ -1126,7 +1130,8 @@ def on_data_table_row_highlighted(self, event: DataTable.RowHighlighted) -> None

maybe_preview = item.preview_action(item)
if maybe_preview is not None:
preview_widget.update(maybe_preview)
content = Text.from_markup(maybe_preview) if item.preview_markup else maybe_preview
preview_widget.update(content)
return

preview_widget.update('')
Expand Down
1 change: 1 addition & 0 deletions archinstall/tui/ui/menu_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class MenuItem:
dependencies_not: list[str] = field(default_factory=list)
display_action: Callable[[Any], str] | None = None
preview_action: Callable[[Self], str | None] | None = None
preview_markup: bool = False
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be set on the actual menu not on the item alongside

preview_location: Literal['bottom'] | None = None,
preview_markup: bool = False,

key: str | None = None

_id: str = ''
Expand Down