diff --git a/custom/scripts/validate_and_rebuild.py b/custom/scripts/validate_and_rebuild.py index 4726622d..12d004d3 100755 --- a/custom/scripts/validate_and_rebuild.py +++ b/custom/scripts/validate_and_rebuild.py @@ -293,44 +293,91 @@ class EntityValidator: """Prüfe Layout-Dateien auf häufige Fehler.""" print_header("5. LAYOUT-STRUKTUR VALIDIERUNG") - layouts_path = self.metadata_path / "clientDefs" - if not layouts_path.exists(): - print_warning("Keine clientDefs gefunden") - return True - + layouts_base = self.custom_path / "layouts" layout_errors = [] + layout_warnings = [] checked_layouts = 0 - for client_def_file in layouts_path.glob("*.json"): - try: - with open(client_def_file, 'r', encoding='utf-8') as f: - client_def = json.load(f) - - # Prüfe auf häufige Layout-Fehler in bottomPanels - bottom_panels = client_def.get('bottomPanelsDetail', {}) - for panel_key, panel_def in bottom_panels.items(): - checked_layouts += 1 + # 1. Prüfe bottomPanelsDetail.json Dateien (KRITISCH: Muss Objekt sein, kein Array!) + if layouts_base.exists(): + for bottom_panel_file in layouts_base.rglob("bottomPanelsDetail.json"): + try: + with open(bottom_panel_file, 'r', encoding='utf-8') as f: + content = json.load(f) - # Prüfe auf unnötige false-Elemente - if isinstance(panel_def, dict): - for key, value in panel_def.items(): - if value is False and key not in ['disabled', 'sticked']: - layout_errors.append( - f"{client_def_file.stem}: bottomPanelsDetail.{panel_key}.{key} " - f"sollte nicht 'false' sein" - ) - except Exception: - pass # JSON-Fehler bereits gemeldet + checked_layouts += 1 + entity_name = bottom_panel_file.parent.name + + # KRITISCHER CHECK: bottomPanelsDetail.json MUSS Objekt sein (nicht Array)! + if isinstance(content, list): + layout_errors.append( + f"{entity_name}/bottomPanelsDetail.json: FEHLER - Ist Array statt Objekt! " + f"EspoCRM 7.x erfordert Objekt-Format mit Keys wie 'contacts', '_tabBreak_0', etc." + ) + elif isinstance(content, dict): + # Prüfe auf false-Werte in falschen Kontexten + for key, value in content.items(): + if isinstance(value, dict): + for subkey, subvalue in value.items(): + if subvalue is False and subkey not in ['disabled', 'sticked']: + layout_warnings.append( + f"{entity_name}/bottomPanelsDetail.json: {key}.{subkey} " + f"sollte nicht 'false' sein" + ) + except Exception: + pass # JSON-Fehler bereits in validate_json_syntax gemeldet + # 2. Prüfe detail.json Dateien auf deprecated false-Platzhalter + if layouts_base.exists(): + for detail_file in layouts_base.rglob("detail.json"): + try: + with open(detail_file, 'r', encoding='utf-8') as f: + content = json.load(f) + + entity_name = detail_file.parent.name + + # Prüfe ob content ein Array von Panels ist + if isinstance(content, list): + for panel_idx, panel in enumerate(content): + if not isinstance(panel, dict): + continue + + rows = panel.get('rows', []) + for row_idx, row in enumerate(rows): + if not isinstance(row, list): + continue + + for cell_idx, cell in enumerate(row): + # KRITISCH: false als Platzhalter ist deprecated in EspoCRM 7.x! + if cell is False: + layout_errors.append( + f"{entity_name}/detail.json: Panel {panel_idx}, Row {row_idx}, " + f"Cell {cell_idx} verwendet 'false' als Platzhalter. " + f"In EspoCRM 7.x muss '{{}}' (leeres Objekt) verwendet werden!" + ) + except Exception: + pass # JSON-Fehler bereits gemeldet + + # Ergebnisse ausgeben if layout_errors: - print_warning(f"{len(layout_errors)} Layout-Strukturprobleme:") - for err in layout_errors[:5]: - print(f" {Colors.YELLOW}•{Colors.END} {err}") - if len(layout_errors) > 5: - print(f" {Colors.YELLOW}...{Colors.END} und {len(layout_errors) - 5} weitere") - self.warnings.extend(layout_errors) - else: - print_success(f"{checked_layouts} Layout-Definitionen geprüft") + print_error(f"{len(layout_errors)} KRITISCHE Layout-Fehler gefunden:") + for err in layout_errors: + print(f" {Colors.RED}✗{Colors.END} {err}") + self.errors.extend(layout_errors) + return False + + if layout_warnings: + print_warning(f"{len(layout_warnings)} Layout-Warnungen:") + for warn in layout_warnings[:5]: + print(f" {Colors.YELLOW}⚠{Colors.END} {warn}") + if len(layout_warnings) > 5: + print(f" {Colors.YELLOW}...{Colors.END} und {len(layout_warnings) - 5} weitere") + self.warnings.extend(layout_warnings) + + if not layout_errors and not layout_warnings: + print_success(f"{checked_layouts} Layout-Dateien geprüft, keine Fehler") + elif not layout_errors: + print_success(f"{checked_layouts} Layout-Dateien geprüft, keine kritischen Fehler") return True