diff --git a/src/python/impactx/dashboard/Input/__init__.py b/src/python/impactx/dashboard/Input/__init__.py index cb130e683..e480f4b16 100644 --- a/src/python/impactx/dashboard/Input/__init__.py +++ b/src/python/impactx/dashboard/Input/__init__.py @@ -1,5 +1,5 @@ -from .components import CardComponents, InputComponents, NavigationComponents -from .defaults import DashboardDefaults, UIDefaults +from .components import CardBase, CardComponents, InputComponents, NavigationComponents +from .defaults import DashboardDefaults from .generalFunctions import generalFunctions __all__ = [ @@ -8,5 +8,5 @@ "generalFunctions", "InputComponents", "NavigationComponents", - "UIDefaults", + "CardBase", ] diff --git a/src/python/impactx/dashboard/Input/components.py b/src/python/impactx/dashboard/Input/components.py index 5c13685a9..e9c332289 100644 --- a/src/python/impactx/dashboard/Input/components.py +++ b/src/python/impactx/dashboard/Input/components.py @@ -1,7 +1,7 @@ from typing import Optional from .. import html, setup_server, vuetify -from .defaults import TooltipDefaults +from .defaults import TooltipDefaults, UIDefaults from .generalFunctions import generalFunctions server, state, ctrl = setup_server() @@ -10,6 +10,41 @@ state.documentation_url = "" +def clean_name(section_name): + return section_name.lower().replace(" ", "_") + + +class CardBase(UIDefaults): + HEADER_NAME = "Base Section" + + def card(self): + """ + Creates UI content for a section. + """ + + self.init_dialog(self.HEADER_NAME, self.card_content) + self.card_content() + + def card_content(self): + raise NotImplementedError("Card must contain card_content.") + + @staticmethod + def init_dialog(section_name: str, content_callback) -> None: + """ + Renders the expansion dialog UI for the input sections card. + Only runs once, when the section's card is built. + """ + + section_name_cleaned = clean_name(section_name) + expand_state_name = f"expand_{section_name_cleaned}" + + setattr(state, expand_state_name, False) + + with vuetify.VDialog(v_model=(expand_state_name,), width="fit-content"): + with vuetify.VCard(): + content_callback() + + class CardComponents: """ Class contains staticmethods to build @@ -24,7 +59,7 @@ def input_header(section_name: str, additional_components=None) -> None: :param section_name: The name for the input section. """ - documentation_name = section_name.lower().replace(" ", "_") + section_name_cleaned = clean_name(section_name) def render_components(position: str): if additional_components and position in additional_components: @@ -33,8 +68,9 @@ def render_components(position: str): with vuetify.VCardTitle(section_name): vuetify.VSpacer() render_components("start") - CardComponents.refresh_icon(documentation_name) - CardComponents.documentation_icon(documentation_name) + CardComponents.expand_button(section_name_cleaned) + CardComponents.refresh_icon(section_name_cleaned) + CardComponents.documentation_icon(section_name_cleaned) render_components("end") vuetify.VDivider() @@ -72,6 +108,24 @@ def refresh_icon(section_name: str) -> vuetify.VBtn: ): vuetify.VIcon("mdi-refresh") + @staticmethod + def expand_button(section_name: str) -> vuetify.VBtn: + """ + A button which expands/closes the given card configuration. + + :param section_name: The name for the input section. + """ + + with vuetify.VBtn( + color="primary", + click=f"expand_{section_name} = !expand_{section_name}", + icon=True, + small=True, + ): + vuetify.VIcon( + v_text=(f"expand_{section_name} ? 'mdi-close' : 'mdi-arrow-expand'",) + ) + class InputComponents: """ diff --git a/src/python/impactx/dashboard/Input/csrConfiguration/csrMain.py b/src/python/impactx/dashboard/Input/csrConfiguration/csrMain.py index fb5e1ae2a..25d37649f 100644 --- a/src/python/impactx/dashboard/Input/csrConfiguration/csrMain.py +++ b/src/python/impactx/dashboard/Input/csrConfiguration/csrMain.py @@ -1,20 +1,18 @@ from ... import setup_server, vuetify -from .. import CardComponents, InputComponents, UIDefaults +from .. import CardBase, CardComponents, InputComponents server, state, ctrl = setup_server() -class csrConfiguration(UIDefaults): +class csrConfiguration(CardBase): + HEADER_NAME = "CSR" + def __init__(self): super().__init__() - def card(self): - """ - Creates UI content for CSR. - """ - + def card_content(self): with vuetify.VCard(): - CardComponents.input_header("CSR") + CardComponents.input_header(self.HEADER_NAME) with vuetify.VCardText(**self.CARD_TEXT_OVERFLOW): with vuetify.VRow(**self.ROW_STYLE): with vuetify.VCol(): diff --git a/src/python/impactx/dashboard/Input/distributionParameters/distributionMain.py b/src/python/impactx/dashboard/Input/distributionParameters/distributionMain.py index 437355c99..5290dd620 100644 --- a/src/python/impactx/dashboard/Input/distributionParameters/distributionMain.py +++ b/src/python/impactx/dashboard/Input/distributionParameters/distributionMain.py @@ -14,10 +14,10 @@ from ... import setup_server, vuetify from .. import ( + CardBase, CardComponents, DashboardDefaults, InputComponents, - UIDefaults, generalFunctions, ) from . import DistributionFunctions @@ -167,20 +167,22 @@ def on_distribution_parameter_change(parameter_name, parameter_value, parameter_ # ----------------------------------------------------------------------------- -class DistributionParameters(UIDefaults): +class DistributionParameters(CardBase): """ User-Input section for beam distribution. """ + HEADER_NAME = "Distribution Parameters" + def __init__(self): super().__init__() - def card(self): + def card_content(self): """ Creates UI content for beam distribution. """ with vuetify.VCard(): - CardComponents.input_header("Distribution Parameters") + CardComponents.input_header(self.HEADER_NAME) with vuetify.VCardText(**self.CARD_TEXT_OVERFLOW): with vuetify.VRow(**self.ROW_STYLE): with vuetify.VCol(cols=6): diff --git a/src/python/impactx/dashboard/Input/inputParameters/inputMain.py b/src/python/impactx/dashboard/Input/inputParameters/inputMain.py index b7da30537..f46582c9d 100644 --- a/src/python/impactx/dashboard/Input/inputParameters/inputMain.py +++ b/src/python/impactx/dashboard/Input/inputParameters/inputMain.py @@ -7,17 +7,19 @@ """ from ... import setup_server, vuetify -from .. import CardComponents, InputComponents, UIDefaults +from .. import CardBase, CardComponents, InputComponents from . import InputFunctions server, state, ctrl = setup_server() -class InputParameters(UIDefaults): +class InputParameters(CardBase): """ User-Input section for beam properties. """ + HEADER_NAME = "Input Parameters" + def __init__(self): super().__init__() @@ -26,13 +28,9 @@ def on_kin_energy_unit_change(**kwargs) -> None: if state.kin_energy_on_ui != 0: InputFunctions.update_kin_energy_sim_value() - def card(self): - """ - Creates UI content for beam properties. - """ - + def card_content(self): with vuetify.VCard(): - CardComponents.input_header("Input Parameters") + CardComponents.input_header(self.HEADER_NAME) with vuetify.VCardText(**self.CARD_TEXT_OVERFLOW): with vuetify.VRow(**self.ROW_STYLE): with vuetify.VCol(cols="auto"): diff --git a/src/python/impactx/dashboard/Input/latticeConfiguration/latticeMain.py b/src/python/impactx/dashboard/Input/latticeConfiguration/latticeMain.py index c0c0d37f2..b26a57fad 100644 --- a/src/python/impactx/dashboard/Input/latticeConfiguration/latticeMain.py +++ b/src/python/impactx/dashboard/Input/latticeConfiguration/latticeMain.py @@ -10,10 +10,10 @@ from ... import setup_server, vuetify from .. import ( + CardBase, CardComponents, InputComponents, NavigationComponents, - UIDefaults, generalFunctions, ) from . import LatticeConfigurationHelper @@ -225,74 +225,25 @@ def update_default_value(parameter_name, new_value): # ----------------------------------------------------------------------------- -class LatticeConfiguration(UIDefaults): - """ - User-Input section for configuring lattice elements. - """ +class LatticeConfiguration(CardBase): + HEADER_NAME = "Lattice Configuration" def __init__(self): super().__init__() - def init_dialogs(self): - with vuetify.VDialog( - v_model=("expand_configuration", False), width="fit-content" - ): - with vuetify.VCard(): - self.configuration_list() + def init_settings_dialog(self): with vuetify.VDialog( v_model=("lattice_configuration_dialog_settings", False), width="500px" ): LatticeConfiguration.dialog_settings() - def card(self): - """ - Creates UI content for lattice configuration. - """ - - self.init_dialogs() - self.configuration_list() - - # ----------------------------------------------------------------------------- - # Dialogs - # ----------------------------------------------------------------------------- - - @staticmethod - def dialog_settings(): - """ - Provides controls for lattice element configuration, - allowing dashboard users to define parameter defaults. - """ - dialog_name = "lattice_configuration_dialog_tab_settings" - - NavigationComponents.create_dialog_tabs(dialog_name, 1, ["Defaults"]) - with vuetify.VTabsItems(v_model=(dialog_name, 0)): - with vuetify.VTabItem(): - with vuetify.VCardText(): - with vuetify.VRow(): - with vuetify.VCol(cols=3): - InputComponents.text_field( - label="nslice", - v_model_name="nslice", - change=( - ctrl.nsliceDefaultChange, - "['nslice', $event]", - ), - ) - - # ----------------------------------------------------------------------------- - # lattice_configuration_lsit - # ----------------------------------------------------------------------------- - - def configuration_list(self): - """ - Displays the configuration for lattice elements. - """ + def card_content(self): + self.init_settings_dialog() with vuetify.VCard(): CardComponents.input_header( - "Lattice Configuration", + self.HEADER_NAME, additional_components={ "start": LatticeConfigurationHelper.settings, - "end": LatticeConfigurationHelper.expand_configuration, }, ) with vuetify.VCardText(**self.CARD_TEXT_OVERFLOW): @@ -345,3 +296,30 @@ def configuration_list(self): dense=True, style="width: 100px;", ) + + # ----------------------------------------------------------------------------- + # Dialogs + # ----------------------------------------------------------------------------- + + @staticmethod + def dialog_settings(): + """ + Provides controls for lattice element configuration, + allowing dashboard users to define parameter defaults. + """ + dialog_name = "lattice_configuration_dialog_tab_settings" + + NavigationComponents.create_dialog_tabs(dialog_name, 1, ["Defaults"]) + with vuetify.VTabsItems(v_model=(dialog_name, 0)): + with vuetify.VTabItem(): + with vuetify.VCardText(): + with vuetify.VRow(): + with vuetify.VCol(cols=3): + InputComponents.text_field( + label="nslice", + v_model_name="nslice", + change=( + ctrl.nsliceDefaultChange, + "['nslice', $event]", + ), + ) diff --git a/src/python/impactx/dashboard/Input/space_charge_configuration/spaceChargeMain.py b/src/python/impactx/dashboard/Input/space_charge_configuration/spaceChargeMain.py index 922f87631..cab4c6976 100644 --- a/src/python/impactx/dashboard/Input/space_charge_configuration/spaceChargeMain.py +++ b/src/python/impactx/dashboard/Input/space_charge_configuration/spaceChargeMain.py @@ -1,9 +1,9 @@ from ... import setup_server, vuetify from .. import ( + CardBase, CardComponents, InputComponents, NavigationComponents, - UIDefaults, generalFunctions, ) from . import SpaceChargeFunctions @@ -171,15 +171,13 @@ def multigrid_settings(): ) -class SpaceChargeConfiguration(UIDefaults): +class SpaceChargeConfiguration(CardBase): + HEADER_NAME = "Space Charge" + def __init__(self): super().__init__() - def card(self): - """ - Creates UI content for space charge configuration - """ - + def card_content(self): with vuetify.VDialog( v_model=("space_charge_dialog_settings", False), width="500px" ): @@ -187,7 +185,7 @@ def card(self): with vuetify.VCard(): CardComponents.input_header( - "Space Charge", additional_components={"start": multigrid_settings} + self.HEADER_NAME, additional_components={"start": multigrid_settings} ) with vuetify.VCardText(**self.CARD_TEXT_OVERFLOW): with vuetify.VRow(**self.ROW_STYLE):