Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TUI] Add validation to create folders #276

Merged
merged 14 commits into from
Jan 12, 2024
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
14 changes: 9 additions & 5 deletions datashuttle/tui/configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from datashuttle import DataShuttle
from datashuttle.tui.screens import modal_dialogs
from datashuttle.tui.utils import utils
from datashuttle.tui.utils import tui_utils


class ConfigsContent(Container):
Expand Down Expand Up @@ -161,7 +161,9 @@ def on_radio_set_changed(self, event: RadioSet.Changed) -> None:
Update the displayed SSH widgets when the `connection_method`
radiobuttons are changed.
"""
display_bool = True if str(event.pressed.label) == "SSH" else False
label = str(event.pressed.label)
assert label in ["SSH", "Local Filesystem"], "Unexpected label."
display_bool = True if label == "SSH" else False
self.switch_ssh_widgets_display(display_bool)

def switch_ssh_widgets_display(self, display_bool):
Expand Down Expand Up @@ -214,7 +216,9 @@ def setup_configs_for_a_new_project_and_switch_to_tab_screen(self):

self.parent_class.mainwindow.push_screen(
modal_dialogs.ShowConfigsDialog(
utils.get_textual_compatible_project_configs(project.cfg),
tui_utils.get_textual_compatible_project_configs(
project.cfg
),
"A DataShuttle project with the below "
"configs has now been created.\n\n Click 'OK' to proceed to "
"the project page, where you will \n be able to create and "
Expand All @@ -238,7 +242,7 @@ def setup_configs_for_an_existing_project(self):
try:
self.project.make_config_file(**cfg_kwargs)

configs_to_show = utils.get_textual_compatible_project_configs(
configs_to_show = tui_utils.get_textual_compatible_project_configs(
self.project.cfg
)

Expand All @@ -262,7 +266,7 @@ def fill_widgets_with_project_configs(self):
"ssh" widgets are hidden / displayed based on the current setting,
in `self.switch_ssh_widgets_display()`.
"""
cfg_to_load = utils.get_textual_compatible_project_configs(
cfg_to_load = tui_utils.get_textual_compatible_project_configs(
self.project.cfg
)

Expand Down
87 changes: 86 additions & 1 deletion datashuttle/tui/css/tui_menu.tcss
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
align: center top;
margin: 3 2 0 0;
content-align: center middle;
height: auto;
}

#project_select_top_container > Button {
Expand Down Expand Up @@ -146,7 +147,6 @@ ShowConfigsDialog:light > #display_configs_top_container {

#configs_local_path_label {
align: center middle;
padding: 0 0 0 0;
}

#configs_container > Input {
Expand Down Expand Up @@ -199,3 +199,88 @@ config label and button align center */
height: auto;
align: center middle;
}


/* TemplateSettingsScreen --------------------------------------------------------------- */

TemplateSettingsScreen {
align: center middle;
}

#template_top_container {
height: 25;
width: 80;
background: $primary-background;
border: tall $panel-lighten-3;
}

#template_inner_horizontal_container{
height: 3;
}

#template_inner_container {
height: auto;
overflow: auto hidden;
}

#template_message_label {
width: auto;
margin: 1 0 0 2;
}

#template_settings_radioset {
layout: horizontal;
border: none;
background: transparent;
align: center middle;
width: 50%;
margin: 1 0 0 0;
}

#template_settings_input {
align: center middle;
width: 50%;
}

#template_sessions_close_button{
dock: right;
layer: top;
}

#template_other_widgets_container{
align: center top;
content-align: center top;
}

#template_message_label:disabled {
color: $panel-lighten-3;
link-color: $panel-lighten-3;
}

#template_settings_radioset:disabled {
color: $panel-lighten-3;
}

#template_settings_input:disabled {
color: $panel-lighten-3;
}

/* TemplateSettingsScreen Light Mode */

#template_top_container:light {
border: tall $panel-darken-3;
background: $boost;
}

#template_settings_radioset:light:disabled {
color: $panel-darken-2;
}

#template_message_label:light:disabled {
color: $panel-darken-2;
link-color: $panel-darken-2;
}

#template_settings_input:light:disabled {
color: $panel-darken-2;
}
35 changes: 35 additions & 0 deletions datashuttle/tui/css/tui_tab.tcss
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,38 @@ TabScreen > TabbedContent {
width: auto;
padding: 0 0 1 0;
}

CreateFoldersTab > Horizontal > Button{
width: 30%;
}

CreateFoldersTab > Horizontal{
align-horizontal: left;
}

#tabscreen_create_tab > Input.-valid {
border: tall $success 60%;
}
#tabscreen_create_tab > Input.-valid:focus {
border: tall $success;
}

#tabscreen_create_tab > Input.-invalid {
border: tall $error 60%;
}

#tabscreen_create_tab > Input.-invalid:focus {
border: tall $error
}

#template_settings_validation_on_checkbox.-on > .toggle--button{
color: $success;
}

#template_settings_validation_on_checkbox.-on > .toggle--label{
color: $success;
}

#template_settings_validation_on_checkbox > .toggle--button{
color: $error;
}
89 changes: 76 additions & 13 deletions datashuttle/tui/custom_widgets.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
from __future__ import annotations

from typing import TYPE_CHECKING, Dict

if TYPE_CHECKING:
from textual import events

from dataclasses import dataclass

from textual.message import Message
from textual.reactive import reactive
from textual.widgets import Checkbox, Static
from textual.widgets import Checkbox, Input, Static

from datashuttle.configs.canonical_configs import get_datatypes

Expand All @@ -12,38 +22,91 @@ class DatatypeCheckboxes(Static):
Attributes
----------

type_out:
datatype_out:
List of datatypes selected by the user to be passed to `make_folders`
(e.g. "behav" that will be passed to `make-folders`.)

type_config:
List of datatypes supported by NeuroBlueprint
"""

type_out = reactive("all")
datatype_out = reactive("all")

def __init__(self):
def __init__(self, project):
super(DatatypeCheckboxes, self).__init__()

self.type_config = get_datatypes()
self.project = project
self.datatype_config = get_datatypes()
self.persistent_settings = self.project._load_persistent_settings()

def compose(self):
for type in self.type_config:
checkboxes_on = self.persistent_settings["tui"]["checkboxes_on"]

for datatype in self.datatype_config:
assert datatype in checkboxes_on.keys(), (
"Need to update tui" "persistent settings."
)

yield Checkbox(
type.title(), id=f"tabscreen_{type}_checkbox", value=True
datatype.title(),
id=f"tabscreen_{datatype}_checkbox",
value=checkboxes_on[datatype],
)

def on_mount(self):
"""
Update datatype out based on the current checkbox
ticks which are determined during `compose().`
"""
datatype_dict = self.get_datatype_dict()
self.set_datatype_out(datatype_dict)

def on_checkbox_changed(self):
"""
When a checkbox is clicked, update the `type_out` attribute
When a checkbox is clicked, update the `datatype_out` attribute
with the datatypes to pass to `make_folders` datatype argument.
"""
type_dict = {
type: self.query_one(f"#tabscreen_{type}_checkbox").value
for type in self.type_config
datatype_dict = self.get_datatype_dict()

# This is slightly wasteful as update entire dict instead
# of changed entry, but is negligible.
self.persistent_settings["tui"]["checkboxes_on"] = datatype_dict

self.project._save_persistent_settings(self.persistent_settings)

self.set_datatype_out(datatype_dict)

def get_datatype_dict(self) -> Dict:
""""""
datatype_dict = {
datatype: self.query_one(f"#tabscreen_{datatype}_checkbox").value
for datatype in self.datatype_config
}
self.type_out = [

return datatype_dict

def set_datatype_out(self, datatype_dict: dict) -> None:
""""""
self.datatype_out = [
datatype
for datatype, is_on in zip(type_dict.keys(), type_dict.values())
for datatype, is_on in zip(
datatype_dict.keys(), datatype_dict.values()
)
if is_on
]


class ClickableInput(Input):
"""
An input widget which emits a `ClickableInput.Clicked`
signal when clicked, containing the input name
`input` and mouse button index `button`.
"""

@dataclass
class Clicked(Message):
input: ClickableInput
button: int

def _on_click(self, click: events.Click) -> None:
self.post_message(self.Clicked(self, click.button))
Loading
Loading