Skip to content

Commit 0503760

Browse files
authored
Merge pull request #27 from LaSi5002/feature/add-delete-sections
add and delete sections
2 parents 98cad2d + 04fb071 commit 0503760

File tree

2 files changed

+139
-12
lines changed

2 files changed

+139
-12
lines changed

src/fourc_webviewer/fourc_webserver.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,7 @@ def init_general_sections_state_and_server_vars(self):
439439

440440
# loop through input file sections
441441
self.state.general_sections = {}
442+
self.state.add_section = ""
442443
self.state.add_key = "" # key for the add property row
443444
self.state.add_value = "" # value for the add property row
444445
for section_name, section_data in self._server_vars[
@@ -1058,6 +1059,97 @@ def change_export_fourc_yaml_path(self, export_fourc_yaml_path, **kwargs):
10581059
#################################################
10591060
# SELECTION CHANGES #################################
10601061
################################################
1062+
@controller.set("click_delete_section_button")
1063+
def click_delete_section_button(self, **kwargs):
1064+
"""Deletes the currently selected section; if it was the last
1065+
subsection, delete the main too."""
1066+
if self.state.selected_section_name in self.state.json_schema.get(
1067+
"required", []
1068+
):
1069+
return
1070+
1071+
cur_main = self.state.selected_main_section_name
1072+
cur_section = self.state.selected_section_name
1073+
if not cur_main or not cur_section:
1074+
return
1075+
1076+
general_sections = copy.deepcopy(self.state.general_sections) or {}
1077+
sections_names = copy.deepcopy(self.state.section_names) or {}
1078+
1079+
# delete the subsection's data
1080+
del general_sections[cur_main][cur_section]
1081+
self.state.general_sections = general_sections
1082+
1083+
# rebuild subsections list (new list ref -> reactive)
1084+
subs_before = sections_names[cur_main]["subsections"]
1085+
new_subs = [s for s in subs_before if s != cur_section]
1086+
sections_names[cur_main] = {**sections_names[cur_main], "subsections": new_subs}
1087+
1088+
if cur_section == cur_main:
1089+
# last one -> delete the main group immediately
1090+
sections_names.pop(cur_main, None)
1091+
general_sections.pop(cur_main, None)
1092+
self.state.section_names = sections_names
1093+
self.state.general_sections = general_sections
1094+
1095+
# choose a new valid selection
1096+
new_main = next(iter(sections_names.keys()), "")
1097+
self.state.selected_main_section_name = new_main
1098+
self.state.selected_section_name = (
1099+
sections_names[new_main]["subsections"][0]
1100+
if new_main and sections_names[new_main]["subsections"]
1101+
else ""
1102+
)
1103+
return
1104+
1105+
self.state.section_names = sections_names
1106+
self.state.selected_main_section_name = cur_main
1107+
self.state.selected_section_name = new_subs[0] if new_subs else ""
1108+
1109+
@change("add_section")
1110+
def change_add_section(self, **kwargs):
1111+
"""Reaction to section selection."""
1112+
add_section = self.state.add_section
1113+
main_section_name = add_section.split("/")[0] or ""
1114+
1115+
if add_section not in self.state.json_schema.get("properties", {}):
1116+
return
1117+
1118+
general_sections = copy.deepcopy(self.state.general_sections) or {}
1119+
section_names = copy.deepcopy(self.state.section_names) or {}
1120+
1121+
# Ensure main buckets exist
1122+
if main_section_name not in section_names:
1123+
section_names[main_section_name] = {
1124+
"subsections": [main_section_name],
1125+
"content_mode": self.state.all_content_modes["general_section"],
1126+
}
1127+
if main_section_name not in general_sections:
1128+
general_sections[main_section_name] = {main_section_name: {}}
1129+
1130+
# Store data under main -> sub
1131+
if add_section not in general_sections[main_section_name]:
1132+
general_sections[main_section_name][add_section] = {}
1133+
1134+
# Replace subsections list with a NEW list object
1135+
subs = section_names[main_section_name]["subsections"]
1136+
if add_section not in subs:
1137+
subs = subs + [add_section] # new list ref
1138+
section_names[main_section_name] = {
1139+
**section_names[main_section_name], # keep content_mode
1140+
"subsections": subs, # new list ref
1141+
}
1142+
1143+
# Commit (new references -> reactive)
1144+
self.state.general_sections = general_sections
1145+
self.state.section_names = section_names
1146+
1147+
# Set a valid selection so VSelect updates
1148+
self.state.selected_main_section_name = main_section_name
1149+
self.state.selected_section_name = add_section
1150+
1151+
self.state.add_section = ""
1152+
10611153
@change("selected_main_section_name")
10621154
def change_selected_main_section_name(self, selected_main_section_name, **kwargs):
10631155
"""Reaction to change of state.selected_main_section_name."""

src/fourc_webviewer/gui_utils.py

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,9 @@ def _sections_dropdown():
249249
items=("Object.keys(section_names)",),
250250
)
251251
vuetify.VSelect(
252-
v_if=("section_names[selected_main_section_name]['subsections'].length>1"),
252+
v_if=(
253+
"selected_main_section_name!=selected_section_name || section_names[selected_main_section_name]['subsections'].length>1",
254+
),
253255
v_model=("selected_section_name",),
254256
items=("section_names[selected_main_section_name]['subsections']",),
255257
)
@@ -576,6 +578,39 @@ def _functions_panel(server):
576578
)
577579

578580

581+
def _top_row(server):
582+
"""Top row layout (edit mode switch and add section)."""
583+
# EDIT MODE switch
584+
with html.Div(classes="d-flex align-center flex-nowrap w-100", style="gap: 12px;"):
585+
vuetify.VSwitch(
586+
v_model=("edit_mode", "all_edit_modes['view_mode']"),
587+
label=("edit_mode", "VIEW"),
588+
true_value=("all_edit_modes['edit_mode']",),
589+
false_value=("all_edit_modes['view_mode']",),
590+
color="primary",
591+
inset=True,
592+
classes="ma-0",
593+
)
594+
# add sections on the right
595+
with html.Div(
596+
classes="d-inline-flex align-center ml-auto",
597+
style="gap: 8px;",
598+
v_if="edit_mode == all_edit_modes['edit_mode']",
599+
):
600+
html.Span("Add Section:", classes="text-h6 font-weight-medium mr-3")
601+
vuetify.VAutocomplete(
602+
v_model=("add_section",),
603+
items=(
604+
"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))))",
605+
),
606+
dense=True,
607+
solo=True,
608+
filterable=True,
609+
classes="ma-0 flex-grow-0",
610+
style="width: 200px;",
611+
)
612+
613+
579614
def _prop_value_table(server):
580615
"""Table (property - value) layout (for general sections)."""
581616

@@ -1414,24 +1449,24 @@ def create_gui(server, render_window):
14141449
with layout.drawer as drawer:
14151450
drawer.width = 800
14161451
with html.Div(v_if=("vtu_path != ''",)):
1417-
# EDIT MODE switch
1418-
vuetify.VSwitch(
1419-
v_model=("edit_mode", "all_edit_modes['view_mode']"),
1420-
label=("edit_mode", "VIEW"),
1421-
true_value=("all_edit_modes['edit_mode']",),
1422-
false_value=("all_edit_modes['view_mode']",),
1423-
color="primary",
1424-
inset=True,
1425-
classes="ml-5",
1426-
)
1427-
14281452
# Further elements with conditional rendering (see above)
1453+
_top_row(server)
14291454
_sections_dropdown()
14301455
_prop_value_table(server)
14311456
_materials_panel()
14321457
_functions_panel(server)
14331458
_design_conditions_panel()
14341459
_result_description_panel()
1460+
vuetify.VBtn(
1461+
text="DELETE SECTION",
1462+
classes="mx-auto d-block mt-10",
1463+
outlined=True,
1464+
color="red",
1465+
v_if=(
1466+
"!json_schema['required'].includes(selected_section_name) && Object.keys(general_sections).includes(selected_main_section_name)",
1467+
),
1468+
click=server.controller.click_delete_section_button,
1469+
)
14351470
with html.Div(classes="flex-column justify-start"):
14361471
vuetify.VCard(
14371472
title="No input file content available",

0 commit comments

Comments
 (0)