Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
92 changes: 92 additions & 0 deletions src/fourc_webviewer/fourc_webserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ def init_general_sections_state_and_server_vars(self):

# loop through input file sections
self.state.general_sections = {}
self.state.add_section = ""
for section_name, section_data in self._server_vars[
"fourc_yaml_content"
].sections.items():
Expand Down Expand Up @@ -942,6 +943,97 @@ def change_export_fourc_yaml_path(self, export_fourc_yaml_path, **kwargs):
#################################################
# SELECTION CHANGES #################################
################################################
@controller.set("click_delete_section_button")
def click_delete_section_button(self, **kwargs):
"""Deletes the currently selected section; if it was the last
subsection, delete the main too."""
if self.state.selected_section_name in self.state.json_schema.get(
"required", []
):
return

cur_main = self.state.selected_main_section_name
cur_section = self.state.selected_section_name
if not cur_main or not cur_section:
return

general_sections = copy.deepcopy(self.state.general_sections) or {}
sections_names = copy.deepcopy(self.state.section_names) or {}

# delete the subsection's data
del general_sections[cur_main][cur_section]
self.state.general_sections = general_sections

# rebuild subsections list (new list ref -> reactive)
subs_before = sections_names[cur_main]["subsections"]
new_subs = [s for s in subs_before if s != cur_section]
sections_names[cur_main] = {**sections_names[cur_main], "subsections": new_subs}

if cur_section == cur_main:
# last one -> delete the main group immediately
sections_names.pop(cur_main, None)
general_sections.pop(cur_main, None)
self.state.section_names = sections_names
self.state.general_sections = general_sections

# choose a new valid selection
new_main = next(iter(sections_names.keys()), "")
self.state.selected_main_section_name = new_main
self.state.selected_section_name = (
sections_names[new_main]["subsections"][0]
if new_main and sections_names[new_main]["subsections"]
else ""
)
return

self.state.section_names = sections_names
self.state.selected_main_section_name = cur_main
self.state.selected_section_name = new_subs[0] if new_subs else ""

@change("add_section")
def change_add_section(self, **kwargs):
"""Reaction to section selection."""
add_section = self.state.add_section
main_section_name = add_section.split("/")[0] or ""

if add_section not in self.state.json_schema.get("properties", {}):
return

general_sections = copy.deepcopy(self.state.general_sections) or {}
section_names = copy.deepcopy(self.state.section_names) or {}

# Ensure main buckets exist
if main_section_name not in section_names:
section_names[main_section_name] = {
"subsections": [main_section_name],
"content_mode": self.state.all_content_modes["general_section"],
}
if main_section_name not in general_sections:
general_sections[main_section_name] = {main_section_name: {}}

# Store data under main -> sub
if add_section not in general_sections[main_section_name]:
general_sections[main_section_name][add_section] = {}

# Replace subsections list with a NEW list object
subs = section_names[main_section_name]["subsections"]
if add_section not in subs:
subs = subs + [add_section] # new list ref
section_names[main_section_name] = {
**section_names[main_section_name], # keep content_mode
"subsections": subs, # new list ref
}

# Commit (new references -> reactive)
self.state.general_sections = general_sections
self.state.section_names = section_names

# Set a valid selection so VSelect updates
self.state.selected_main_section_name = main_section_name
self.state.selected_section_name = add_section

self.state.add_section = ""

@change("selected_main_section_name")
def change_selected_main_section_name(self, selected_main_section_name, **kwargs):
"""Reaction to change of state.selected_main_section_name."""
Expand Down
59 changes: 47 additions & 12 deletions src/fourc_webviewer/gui_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,9 @@ def _sections_dropdown():
items=("Object.keys(section_names)",),
)
vuetify.VSelect(
v_if=("section_names[selected_main_section_name]['subsections'].length>1"),
v_if=(
"selected_main_section_name!=selected_section_name || section_names[selected_main_section_name]['subsections'].length>1",
),
v_model=("selected_section_name",),
items=("section_names[selected_main_section_name]['subsections']",),
)
Expand Down Expand Up @@ -576,6 +578,39 @@ def _functions_panel(server):
)


def _top_row(server):
"""Top row layout (edit mode switch and add section)."""
# EDIT MODE switch
with html.Div(classes="d-flex align-center flex-nowrap w-100", style="gap: 12px;"):
vuetify.VSwitch(
v_model=("edit_mode", "all_edit_modes['view_mode']"),
label=("edit_mode", "VIEW"),
true_value=("all_edit_modes['edit_mode']",),
false_value=("all_edit_modes['view_mode']",),
color="primary",
inset=True,
classes="ma-0",
)
# add sections on the right
with html.Div(
classes="d-inline-flex align-center ml-auto",
style="gap: 8px;",
v_if="edit_mode == all_edit_modes['edit_mode']",
):
html.Span("Add Section:", classes="text-h6 font-weight-medium mr-3")
vuetify.VAutocomplete(
v_model=("add_section",),
items=(
"Object.keys(json_schema['properties']).filter(key => !new Set(['MATERIALS', 'TITLE', 'CLONING MATERIAL MAP', 'RESULT DESCRIPTION']).has(key) && !(['DESIGN', 'TOPOLOGY', 'ELEMENTS', 'NODE', 'FUNCT', 'GEOMETRY'].some(n => key.includes(n))))",
),
dense=True,
solo=True,
filterable=True,
classes="ma-0 flex-grow-0",
style="width: 200px;",
)


def _prop_value_table():
"""Table (property - value) layout (for general sections)."""
with vuetify.VTable(
Expand Down Expand Up @@ -1246,24 +1281,24 @@ def create_gui(server, render_window):
with layout.drawer as drawer:
drawer.width = 800
with html.Div(v_if=("vtu_path != ''",)):
# EDIT MODE switch
vuetify.VSwitch(
v_model=("edit_mode", "all_edit_modes['view_mode']"),
label=("edit_mode", "VIEW"),
true_value=("all_edit_modes['edit_mode']",),
false_value=("all_edit_modes['view_mode']",),
color="primary",
inset=True,
classes="ml-5",
)

# Further elements with conditional rendering (see above)
_top_row(server)
_sections_dropdown()
_prop_value_table()
_materials_panel()
_functions_panel(server)
_design_conditions_panel()
_result_description_panel()
vuetify.VBtn(
text="DELETE SECTION",
classes="mx-auto d-block mt-10",
outlined=True,
color="red",
v_if=(
"!json_schema['required'].includes(selected_section_name) && Object.keys(general_sections).includes(selected_main_section_name)",
),
click=server.controller.click_delete_section_button,
)
with html.Div(classes="flex-column justify-start"):
vuetify.VCard(
title="No input file content available",
Expand Down