class JS_Tree_Debug_Node extends Component { on_create() { this.is_expanded = (this.args.expand_depth ?? 1) > 0; // Track relationship loading states: { rel_name: 'pending'|'loading'|'loaded'|'error' } this.state.rel_states = {}; // Store loaded relationship data: { rel_name: data } this.state.rel_data = {}; // Store error messages: { rel_name: error_message } this.state.rel_errors = {}; } on_ready() { // Relationships are never auto-loaded - they only load when explicitly expanded } toggle() { this.is_expanded = !this.is_expanded; this.$sid('children').toggle(this.is_expanded); this.$sid('toggle').toggleClass('js-tree-debug-collapsed', !this.is_expanded); this.$sid('preview_collapsed').toggle(!this.is_expanded); // Note: Relationships are NOT auto-loaded here - they have their own toggle handler } /** * Toggle a relationship node and load its data if not already loaded */ toggle_relationship(rel_name) { const $container = this.$sid('rel_' + rel_name); const $toggle = $container.find('.js-tree-debug-toggle').first(); const $children = $container.find('.js-tree-debug-rel-children').first(); const $preview = $container.find('.js-tree-debug-preview-collapsed').first(); const is_expanded = !$toggle.hasClass('js-tree-debug-collapsed'); if (is_expanded) { // Collapse $toggle.addClass('js-tree-debug-collapsed'); $children.hide(); $preview.show(); } else { // Expand $toggle.removeClass('js-tree-debug-collapsed'); $children.show(); $preview.hide(); // Load if not already loaded if (!this.state.rel_states[rel_name] || this.state.rel_states[rel_name] === 'pending') { this._load_relationship(rel_name); } } } /** * Load a relationship and update the UI */ async _load_relationship(rel_name) { // Validate the relationship function exists const obj = this.args.data; if (!obj || typeof obj[rel_name] !== 'function') { return; } this.state.rel_states[rel_name] = 'loading'; this._update_relationship_ui(rel_name); try { const result = await obj[rel_name](); this.state.rel_states[rel_name] = 'loaded'; this.state.rel_data[rel_name] = result; this._update_relationship_ui(rel_name); } catch (e) { this.state.rel_states[rel_name] = 'error'; this.state.rel_errors[rel_name] = e.message || 'Error loading relationship'; this._update_relationship_ui(rel_name); } } /** * Update the UI for a relationship after loading */ _update_relationship_ui(rel_name) { const $container = this.$sid('rel_' + rel_name); const $children = $container.find('.js-tree-debug-rel-children').first(); const $preview = $container.find('.js-tree-debug-preview-collapsed').first(); const state = this.state.rel_states[rel_name]; const data = this.state.rel_data[rel_name]; const error = this.state.rel_errors[rel_name]; // Update preview text if (state === 'loading') { $preview.html('loading...'); } else if (state === 'error') { $preview.html('error'); } else if (state === 'loaded') { const type = JS_Tree_Debug_Node.get_type(data); $preview.text(JS_Tree_Debug_Node.get_preview(data, type) || JS_Tree_Debug_Node.format_value(data, type)); } // Update children content $children.empty(); if (state === 'loading') { $children.html('