@@ -71,7 +71,9 @@ def _dom_token(value: Any) -> str:
7171 return token .lower () or "unnamed"
7272
7373
74- def _populate_forms_from_dict (panels : dict [str , Any ], config_dict : dict ) -> None :
74+ def _populate_forms_from_dict (
75+ panels : dict [str , Any ], config_dict : dict , open_test_index : int | None = None
76+ ) -> None :
7577 """Populate all form panels from a parsed config dict.
7678
7779 Walks the three panel groups (``global``, ``tests``, ``metadata``)
@@ -85,6 +87,8 @@ def _populate_forms_from_dict(panels: dict[str, Any], config_dict: dict) -> None
8587 config_dict: A parsed experiment configuration dictionary,
8688 typically the output of ``yaml.safe_load()`` or
8789 ``ConfigService.yaml_to_dict()``.
90+ open_test_index: Optional test panel to open while rebuilding
91+ the test editor.
8892 """
8993 # Global sections
9094 for field_name , panel in panels .get ("global" , {}).items ():
@@ -96,7 +100,9 @@ def _populate_forms_from_dict(panels: dict[str, Any], config_dict: dict) -> None
96100 tests = config_dict .get ("tests" )
97101 test_editor = panels .get ("tests" )
98102 if tests and isinstance (tests , list ) and test_editor :
99- test_editor .set_value ([t for t in tests if isinstance (t , dict )])
103+ test_editor .set_value (
104+ [t for t in tests if isinstance (t , dict )], open_index = open_test_index
105+ )
100106
101107 # Metadata
102108 meta = config_dict .get ("metadata" )
@@ -717,7 +723,7 @@ def _auto_navigate_from_topology(
717723 # Populate forms from loaded data, then open the target test panel
718724 panels = _yaml_editor_ref .get ("panels" )
719725 if panels :
720- _populate_forms_from_dict (panels , data )
726+ _populate_forms_from_dict (panels , data , open_test_index = test_index )
721727 test_editor = panels .get ("tests" )
722728 if test_editor and hasattr (test_editor , "open_test" ):
723729 test_editor .open_test (test_index )
@@ -772,43 +778,86 @@ def _auto_navigate_from_topology(
772778 }}
773779 }});
774780
775- // Phase 2: After expansion animation completes, find and highlight the service
776- setTimeout(function() {{
777- var target = document.querySelector({ js_service_selector } );
778- if (!target && { js_service_id } ) {{
779- var allElements = targetExp.querySelectorAll('*:not(script):not(style)');
780- for (var i = 0; i < allElements.length; i++) {{
781- var el = allElements[i];
782- var text = (el.textContent || el.value || '').toLowerCase();
783- if (text.includes({ js_service_id_lower } ) || text.includes({ js_service_name_lower } )) {{
784- target = el.closest('.panther-field-services-entry') ||
785- el.closest('.q-field') ||
786- el.closest('.q-item') ||
787- el;
788- break;
789- }}
781+ function expandNestedSections() {{
782+ targetExp.querySelectorAll('.q-expansion__header').forEach(function(header, idx) {{
783+ if (idx === 0) return;
784+ var expanded = header.getAttribute('aria-expanded');
785+ var item = header.closest('.q-expansion-item');
786+ var isExpanded = expanded === 'true' ||
787+ (item && item.classList.contains('q-expansion-item--expanded'));
788+ if (!isExpanded) {{
789+ header.click();
790+ }}
791+ }});
792+ }}
793+
794+ function highlightTarget(target) {{
795+ target.scrollIntoView({{behavior: 'smooth', block: 'center'}});
796+ target.style.backgroundColor = '#fff3cd';
797+ target.style.boxShadow = '0 0 0 2px #ffc107';
798+ target.style.borderRadius = '4px';
799+ target.style.transition = 'background-color 2s, box-shadow 2s';
800+ setTimeout(function() {{
801+ target.style.backgroundColor = '';
802+ target.style.boxShadow = '';
803+ }}, 4000);
804+ }}
805+
806+ function findFallbackTarget() {{
807+ if (!{ js_service_id } ) return null;
808+ var allElements = targetExp.querySelectorAll('*:not(script):not(style)');
809+ for (var i = 0; i < allElements.length; i++) {{
810+ var el = allElements[i];
811+ var text = (el.textContent || el.value || '').toLowerCase();
812+ if (text.includes({ js_service_id_lower } ) || text.includes({ js_service_name_lower } )) {{
813+ return el.closest('.panther-field-services-entry') ||
814+ el.closest('.q-field') ||
815+ el.closest('.q-item') ||
816+ el;
817+ }}
818+ }}
819+ return null;
820+ }}
821+
822+ // Phase 2: wait for nested sections and service rows to render, then exact-match the clicked service.
823+ var attempts = 0;
824+ var maxAttempts = 20;
825+ var servicePoll = setInterval(function() {{
826+ attempts += 1;
827+ expandNestedSections();
828+
829+ var exactServiceRow = targetExp.querySelector({ js_service_selector } );
830+ if (exactServiceRow) {{
831+ clearInterval(servicePoll);
832+ highlightTarget(exactServiceRow);
833+ console.log("Highlighted exact service field:", { js_service_id } );
834+
835+ var editButton = exactServiceRow.querySelector('.panther-entry-edit-button');
836+ if (editButton) {{
837+ setTimeout(function() {{
838+ editButton.click();
839+ console.log("Opened edit dialog for exact service:", { js_service_id } );
840+ }}, 150);
841+ }} else {{
842+ console.log("Exact service row found, but no edit button was available:", { js_service_id } );
790843 }}
844+ return;
791845 }}
792846
793- if (target) {{
794- target.scrollIntoView({{behavior: 'smooth', block: 'center'}});
795- target.style.backgroundColor = '#fff3cd';
796- target.style.boxShadow = '0 0 0 2px #ffc107';
797- target.style.borderRadius = '4px';
798- target.style.transition = 'background-color 2s, box-shadow 2s';
799- setTimeout(function() {{
800- target.style.backgroundColor = '';
801- target.style.boxShadow = '';
802- }}, 4000);
803- console.log("Highlighted service field:", { js_service_id } );
804- }} else {{
805- // Keep the user at the correct test even if the service row is not rendered.
806- var rect = targetExp.getBoundingClientRect();
807- var scrollTarget = window.scrollY + rect.top - 100;
808- window.scrollTo({{top: scrollTarget, behavior: 'smooth'}});
809- console.log("Could not find service field for:", { js_service_id_lower } );
847+ if (attempts >= maxAttempts) {{
848+ clearInterval(servicePoll);
849+ var fallbackTarget = findFallbackTarget();
850+ if (fallbackTarget) {{
851+ highlightTarget(fallbackTarget);
852+ console.log("Highlighted fallback service field:", { js_service_id } );
853+ }} else {{
854+ var rect = targetExp.getBoundingClientRect();
855+ var scrollTarget = window.scrollY + rect.top - 100;
856+ window.scrollTo({{top: scrollTarget, behavior: 'smooth'}});
857+ console.log("Could not find service field for:", { js_service_id_lower } );
858+ }}
810859 }}
811- }}, 700 );
860+ }}, 250 );
812861 }} else {{
813862 console.warn("Could not find test panel selector:", { js_test_panel_selector } );
814863 var testsContainer = document.querySelector('.panther-test-list');
0 commit comments