Add "hide empty Specifications" to Bonsai IFCTester (#7190)

* add filter

* apply filter property

* allow name filter

* black .

* add hide-skipped to html

* rename prop

* only hide optional specifications
This commit is contained in:
Christoph Mellüh
2025-10-06 06:49:35 +02:00
committed by GitHub
parent 16fd614886
commit 8e045d772c
5 changed files with 46 additions and 7 deletions
@@ -135,6 +135,7 @@ class IfcTesterNamespace(socketio.AsyncNamespace):
try:
request_id = data.get("id")
ids_string = data.get("ids")
props = tool.Tester.get_tester_props()
if not request_id:
await self.emit("error", {"error": "No request ID provided"}, room=sid)
@@ -176,7 +177,7 @@ class IfcTesterNamespace(socketio.AsyncNamespace):
json_report = json_reporter.to_string()
# HTML report
html_reporter = ifctester.reporter.Html(ids)
html_reporter = ifctester.reporter.Html(ids, hide_skipped=props.hide_skipped_specs)
html_reporter.report()
html_report = html_reporter.to_string()
@@ -267,7 +268,7 @@ class ExecuteIfcTester(bpy.types.Operator):
start = time.time()
if props.generate_html_report:
engine = ifctester.reporter.Html(specs)
engine = ifctester.reporter.Html(specs, props.hide_skipped_specs)
engine.report()
output_path = output.as_posix()
engine.to_file(output_path)
@@ -82,6 +82,7 @@ class IfcTesterProperties(PropertyGroup):
webapp_server_port: IntProperty(name="Webapp Server Port", default=0)
webapp_is_running: BoolProperty(default=False, name="Webapp Is Running", options=set())
websocket_server_port: IntProperty(name="WebSocket Server Port", default=0)
hide_skipped_specs: BoolProperty(default=False, name="Hide skipped Specifications", options=set())
if TYPE_CHECKING:
specs: MultipleFileSelect
+33 -1
View File
@@ -62,7 +62,8 @@ class BIM_PT_tester(Panel):
row.prop(props, "generate_ods_report")
row = self.layout.row()
row.prop(props, "flag")
row = self.layout.row()
row.prop(props, "hide_skipped_specs")
if not tool.Ifc.get() or not props.should_load_from_memory:
row = self.layout.row(align=True)
props.ifc_files.layout_file_select(row, "*.ifc;*.ifczip;*.ifcxml", "IFC File(s)")
@@ -104,6 +105,9 @@ class BIM_PT_tester(Panel):
def draw_editable_ui(self, context: bpy.types.Context) -> None:
props = tool.Tester.get_tester_props()
specification = TesterData.data["specification"]
is_skipped = specification["total_checks"] == 0 and specification["cardinality"] == "optional"
if props.hide_skipped_specs and is_skipped:
return
n_requirements = len(specification["requirements"])
@@ -179,6 +183,34 @@ class BIM_UL_tester_specifications(UIList):
row.label(text=item.name, icon="CHECKMARK" if item.status else "CANCEL")
row.label(text=item.description)
def filter_items(self, context: bpy.types.Context, data: IfcTesterProperties, propname: str):
items = getattr(data, propname)
filter_flags = [self.bitflag_filter_item] * len(items)
props = tool.Tester.get_tester_props()
if props.hide_skipped_specs:
for idx, item in enumerate(items):
report = tool.Tester.report[idx]
if report["total_checks"] != 0:
filter_flags[idx] |= self.bitflag_filter_item
else:
filter_flags[idx] &= ~self.bitflag_filter_item
filter_name = self.filter_name
if filter_name:
name_filtered = bpy.types.UI_UL_list.filter_items_by_name(
filter_name,
self.bitflag_filter_item,
items,
"name",
)
if len(name_filtered) == len(filter_flags):
for idx, flag in enumerate(name_filtered):
if flag == 0:
filter_flags[idx] &= ~self.bitflag_filter_item
return filter_flags, []
class BIM_UL_tester_failed_entities(UIList):
def draw_item(
+5 -3
View File
@@ -55,6 +55,7 @@ class Results(TypedDict):
date: str
filepath: str
filename: str
hide_skipped: bool
specifications: list[ResultsSpecification]
status: bool
total_specifications: int
@@ -236,9 +237,10 @@ class Txt(Console):
class Json(Reporter):
def __init__(self, ids: Ids):
def __init__(self, ids: Ids,hide_skipped = False):
super().__init__(ids)
self.results = Results()
self.results["hide_skipped"] = hide_skipped
def report(self) -> Results:
self.results["title"] = self.ids.info.get("title", "Untitled IDS")
@@ -435,14 +437,14 @@ class Json(Reporter):
class Html(Json):
def __init__(self, ids: Ids):
def __init__(self, ids: Ids, hide_skipped: bool = False):
self.entity_limit = 100
super().__init__(ids)
self.results["hide_skipped"] = hide_skipped
def report(self) -> None:
super().report()
for spec in self.results["specifications"]:
print("checking", spec["cardinality"])
if spec["cardinality"] == "optional" and spec["total_checks"] == 0:
spec["is_skipped"] = True
spec["is_prohibited"] = spec["cardinality"] == "prohibited"
@@ -34,6 +34,9 @@
}
body { font-family: 'Arial', sans-serif; padding: 10px 40px; }
section { padding: 15px; border-radius: 5px; border: 1px solid #eee; margin-bottom: 15px; }
{{#hide_skipped}}
.specification.is-skipped { display: none; }
{{/hide_skipped}}
section>h2 { margin-top: 0px; }
span.time { color: #999; font-style: italic; float: right; }
span.step-time { float: right; color: #555; font-size: 0.8em; font-style: italic; }
@@ -96,7 +99,7 @@
</p>
<hr>
{{#specifications}}
<section style="clear: both; overflow: hidden;">
<section class="specification{{#is_skipped}} is-skipped{{/is_skipped}}" style="clear: both; overflow: hidden;">
<div class="info">
<h2>{{name}}</h2>
{{#description}}