diff --git a/dt-metrics/records/genmap.js b/dt-metrics/records/genmap.js index 9a1ea0999..b455c0f98 100644 --- a/dt-metrics/records/genmap.js +++ b/dt-metrics/records/genmap.js @@ -16,18 +16,27 @@ jQuery(document).ready(function ($) { chart.empty().html(`
-
+
+ + ${window.lodash.escape(translations.show_archived)} +
+ + +
+
-
+

${window.lodash.escape(translations.title)}

@@ -70,6 +79,7 @@ jQuery(document).ready(function ($) { .data('p2p_direction'), post_type: selected_post_type, gen_depth_limit: 100, + show_archived: jQuery('#archivedToggle').prop('checked'), }; // Dynamically update URL parameters. @@ -120,6 +130,39 @@ jQuery(document).ready(function ($) { nodeContent: 'content', direction: 'l2r', nodeTemplate: nodeTemplate, + initCompleted: function (chart) { + const post_types = window.dtMetricsProject.post_types; + + // Identify archived items, in order to update corresponding node color. + if ( + post_types && + post_types[selected_post_type] && + post_types[selected_post_type]?.status_field?.archived_key + ) { + const archived_items = identify_items_by_field_value( + response, + 'status', + post_types[selected_post_type]['status_field'][ + 'archived_key' + ], + {}, + ); + + // Tweak node colouring of identified items; which have been archived. + if (archived_items) { + for (const [id, item] of Object.entries(archived_items)) { + const node = $(chart).find(`#${id}.node`); + if (node) { + const color = '#808080'; + $(node).css('background-color', color); + $(node).find('.title').css('background-color', color); + $(node).find('.content').css('background-color', color); + $(node).find('.content').css('border', '0px'); + } + } + } + } + }, }); let container_height = window.innerHeight - 200; // because it is rotated @@ -206,6 +249,28 @@ jQuery(document).ready(function ($) { jQuery(document).on('click', '#gen_tree_add_child_but', function (e) { handle_add_child(); }); + + jQuery(document).on('click', '#archivedToggle', function (e) { + window.load_genmap(); + }); + } + + function identify_items_by_field_value(data, field, value, items) { + if (data?.[field] === value) { + items[data['id']] = { + id: data['id'], + name: data['name'], + status: data['status'], + }; + } + + if (data?.['children']) { + data['children'].forEach(function (item) { + items = identify_items_by_field_value(item, field, value, items); + }); + } + + return items; } function identify_infinite_loops(data, loops) { diff --git a/dt-metrics/records/genmap.php b/dt-metrics/records/genmap.php index 451df082b..21e8c89c6 100644 --- a/dt-metrics/records/genmap.php +++ b/dt-metrics/records/genmap.php @@ -57,9 +57,18 @@ public function tree( WP_REST_Request $request ) { return new WP_Error( __METHOD__, 'Missing parameters! [Required: p2p_type, p2p_direction, post_type ]', [ 'status' => 400 ] ); } - $query = $this->get_query( $params['post_type'], $params['p2p_type'], $params['p2p_direction'] ); + $post_type = $params['post_type']; + $post_settings = DT_Posts::get_post_settings( $post_type ); - return $this->get_genmap( $query, $params['gen_depth_limit'] ?? 100, $params['focus_id'] ?? 0 ); + $filters = [ + 'post_type' => $post_type, + 'show_archived' => $params['show_archived'] ?? false, + 'status_key' => $post_settings['status_field']['status_key'] ?? '', + 'archived_key' => $post_settings['status_field']['archived_key'] ?? '' + ]; + $query = $this->get_query( $post_type, $params['p2p_type'], $params['p2p_direction'], $filters ); + + return $this->get_genmap( $query, $params['gen_depth_limit'] ?? 100, $params['focus_id'] ?? 0, $filters ); } public function scripts() { @@ -84,6 +93,7 @@ public function scripts() { 'data' => [], 'translations' => [ 'title' => __( 'Generation Map', 'disciple_tools' ), + 'show_archived' => __( 'Show Archived', 'disciple_tools' ), 'highlight_active' => __( 'Highlight Active', 'disciple_tools' ), 'highlight_churches' => __( 'Highlight Churches', 'disciple_tools' ), 'members' => __( 'Members', 'disciple_tools' ), @@ -131,7 +141,7 @@ public function scripts() { wp_enqueue_style( 'orgchart_css', $css_uri, [], filemtime( $css_dir ) ); } - public function get_query( $post_type, $p2p_type, $p2p_direction ) { + public function get_query( $post_type, $p2p_type, $p2p_direction, $filters = [] ) { global $wpdb; // p2p direction will govern overall query sql shape. @@ -147,11 +157,14 @@ public function get_query( $post_type, $p2p_type, $p2p_direction ) { $select_parent_id = 'p2p_from'; } + // Determine archived meta values. + $status_key = $filters['status_key'] ?? ''; $query = $wpdb->get_results( $wpdb->prepare( " SELECT a.ID as id, 0 as parent_id, - a.post_title as name + a.post_title as name, + ( SELECT p_status.meta_value FROM $wpdb->postmeta as p_status WHERE ( p_status.post_id = a.ID ) AND ( p_status.meta_key = %s ) ) as status FROM $wpdb->posts as a WHERE a.post_type = %s AND a.ID %1s IN ( @@ -170,15 +183,16 @@ public function get_query( $post_type, $p2p_type, $p2p_direction ) { SELECT p.%1s as id, p.%1s as parent_id, - (SELECT sub.post_title FROM $wpdb->posts as sub WHERE sub.ID = p.%1s ) as name + (SELECT sub.post_title FROM $wpdb->posts as sub WHERE sub.ID = p.%1s ) as name, + ( SELECT u_status.meta_value FROM $wpdb->postmeta as u_status WHERE ( u_status.post_id = p.%1s ) AND ( u_status.meta_key = %s ) ) as status FROM $wpdb->p2p as p WHERE p.p2p_type = %s; - ", $post_type, $not_from, $p2p_type, $not_to, $p2p_type, $select_id, $select_parent_id, $select_id, $p2p_type ), ARRAY_A ); + ", $status_key, $post_type, $not_from, $p2p_type, $not_to, $p2p_type, $select_id, $select_parent_id, $select_id, $select_id, $status_key, $p2p_type ), ARRAY_A ); return $query; } - public function get_genmap( $query, $depth_limit, $focus_id ) { + public function get_genmap( $query, $depth_limit, $focus_id, $filters = [] ) { if ( is_wp_error( $query ) ){ return $this->_circular_structure_error( $query ); @@ -188,7 +202,7 @@ public function get_genmap( $query, $depth_limit, $focus_id ) { } $menu_data = $this->prepare_menu_array( $query ); - return $this->build_array( $focus_id ?? 0, $menu_data, 0, $depth_limit ); + return $this->build_array( $focus_id ?? 0, $menu_data, 0, $depth_limit, $filters ); } public function prepare_menu_array( $query ) { @@ -206,7 +220,7 @@ public function prepare_menu_array( $query ) { return $menu_data; } - public function build_array( $parent_id, $menu_data, $gen, $depth_limit ) { + public function build_array( $parent_id, $menu_data, $gen, $depth_limit, $filters = [] ) { $children = []; if ( isset( $menu_data['parents'][$parent_id] ) && ( $gen < $depth_limit ) ) { @@ -214,34 +228,72 @@ public function build_array( $parent_id, $menu_data, $gen, $depth_limit ) { foreach ( $menu_data['parents'][$parent_id] as $item_id ) { - $children[] = $this->build_array( $item_id, $menu_data, $next_gen, $depth_limit ); + $children[] = $this->build_array( $item_id, $menu_data, $next_gen, $depth_limit, $filters ); } } + $array = [ 'id' => $parent_id, 'name' => $menu_data['items'][ $parent_id ]['name'] ?? 'SYSTEM', - 'content' => 'Gen ' . $gen, - 'children' => $children, - 'has_infinite_loop' => $this->has_infinite_loop( $parent_id, $children ) + 'status' => $menu_data['items'][ $parent_id ]['status'] ?? '', + 'content' => 'Gen ' . $gen ]; + // Determine if archived records are to be excluded. + if ( !$filters['show_archived'] ) { + + // Recursively exclude associated children. + $children = $this->exclude_archived_children( $children, $filters['archived_key'] ); + + // Only capture node, if active children are still detected; otherwise return empty array. + if ( !empty( $children ) ) { + $array['children'] = $children; + $array['has_infinite_loop'] = $this->has_infinite_loop( $parent_id, $children ); + } else { + $array['children'] = []; + $array['has_infinite_loop'] = false; + } + } else { + $array['children'] = $children; + $array['has_infinite_loop'] = $this->has_infinite_loop( $parent_id, $children ); + } + return $array; } public function has_infinite_loop( $parent_id, $children ): bool { foreach ( $children ?? [] as $child ) { - if ( $parent_id === $child['id'] ) { - return true; - } - if ( !empty( $child['children'] ) ) { - if ( $this->has_infinite_loop( $parent_id, $child['children'] ) ) { + if ( isset( $child['id'], $child['children'] ) ) { + if ( $parent_id === $child['id'] ){ return true; } + if ( !empty( $child['children'] ) ){ + if ( $this->has_infinite_loop( $parent_id, $child['children'] ) ){ + return true; + } + } } } return false; } + + public function exclude_archived_children( $children, $archived_key ): array { + $updated_children = []; + foreach ( $children ?? [] as $child ) { + if ( isset( $child['status'] ) && $child['status'] == $archived_key ) { + $child['children'] = $this->exclude_archived_children( $child['children'], $archived_key ); + + if ( !empty( $child['children'] ) ) { + $updated_children[] = $child; + } + } else { + $updated_children[] = $child; + } + } + + return $updated_children; + } } new DT_Metrics_Groups_Genmap();