Skip to content

#2433 - Dynamic Metrics - Genmapper Filters #2474

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 67 additions & 2 deletions dt-metrics/records/genmap.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,27 @@ jQuery(document).ready(function ($) {

chart.empty().html(`
<div class="grid-x grid-padding-x">
<div class="cell medium-8">
<div class="cell medium-10">
<span>
<select id="select_post_types" style="width: 200px;"></select>
</span>
<span>
<select id="select_post_type_fields" style="width: 200px;"></select>
</span>
<span style="display: inline-block; margin-right: 10px; margin-left: 10px;" class="show-closed-switch">
${window.lodash.escape(translations.show_archived)}
<div class="switch tiny">
<input class="switch-input" id="archivedToggle" type="checkbox" name="archivedToggle">
<label class="switch-paddle" for="archivedToggle">
<span class="show-for-sr">${window.lodash.escape(translations.show_archived)}</span>
</label>
</div>
</span>
<span>
<i class="fi-loop" onclick="window.load_genmap()" style="font-size: 1.5em; padding:.5em;cursor:pointer;"></i>
</span>
</div>
<div class="cell medium-4" >
<div class="cell medium-2" >
<h2 style="float:right;">${window.lodash.escape(translations.title)}</h2>
</div>
</div>
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down
88 changes: 70 additions & 18 deletions dt-metrics/records/genmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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' ),
Expand Down Expand Up @@ -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.
Expand All @@ -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 (
Expand All @@ -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 );
Expand All @@ -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 ) {
Expand All @@ -206,42 +220,80 @@ 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 ) )
{
$next_gen = $gen + 1;

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();

Loading