Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
CFM-291_Show_the_count_of_members_on_the_members_tab (#184)
* Show the count of members on the members tab

* remove bootstrpism

* take into account the pagination

* create tab count item element
  • Loading branch information
Ioannis committed Apr 20, 2024
1 parent 2f093ea commit 54d2fdd
Showing 7 changed files with 166 additions and 19 deletions.
29 changes: 18 additions & 11 deletions app/src/Controller/StandardController.php
@@ -35,7 +35,7 @@
use \Cake\Http\Exception\BadRequestException;
use \App\Lib\Enum\ProvisioningContextEnum;
use \App\Lib\Enum\SuspendableStatusEnum;
use \App\Lib\Util\StringUtilities;
use \App\Lib\Util\{StringUtilities, FunctionUtilities};

class StandardController extends AppController {
use \App\Lib\Traits\IndexQueryTrait;
@@ -656,13 +656,8 @@ protected function populateAutoViewVars(object $obj=null) {
case 'select':
$avvmodel = $avv['model'];
$this->$avvmodel = TableRegistry::getTableLocator()->get($avvmodel);
$query = $this->$avvmodel->find($avv['type'] == 'auxiliary' ? 'all' : 'list');

if($avv['type'] == 'auxiliary') {
$query = $this->$avvmodel->find();
} else {
$query = $this->$avvmodel->find('list');
}

if(!empty($avv['find'])) {
if($avv['find'] == 'filterPrimaryLink') {
// We're filtering the requested model, not our current model.
@@ -693,18 +688,30 @@ protected function populateAutoViewVars(object $obj=null) {
// Use the specified finder, if configured
$query = $query->find($avv['find']);
}
} else {
// XXX is this the best logic? maybe some relation to filterPrimaryLink?
} elseif($table->getSchema()->hasColumn('co_id')) {
// XXX is this the best logic? maybe some relation to filterPrimaryLink?
// By default, filter everything on CO ID

$avv['where']['co_id'] = $this->getCOID();
//$query = $query->where([$table->getAlias().'.co_id' => $this->getCOID()]);
}


// Where Rule. The rule will be transfered as is
if(!empty($avv['where'])) {
// Filter on the specified clause (of the form [column=>value])
$query = $query->where($avv['where']);
}

// Where rule that will be evaluated. We use the custom whereEvan key to
// distinguish from the plain where. Also it might contain more than one conditions
if(!empty($avv['whereEval'])) {
foreach ($avv['whereEval'] as $whereClauseColumn => $chainedMethodDescription) {
$calculatedValue = FunctionUtilities::dynamicChainedFunction(
$this,
$chainedMethodDescription
);
$query = $query->where([$whereClauseColumn => $calculatedValue]);
}
}

// Sort the list by display field
if(!empty($avv['model']) && method_exists($this->$avvmodel, "getDisplayField")) {
83 changes: 83 additions & 0 deletions app/src/Lib/Util/FunctionUtilities.php
@@ -0,0 +1,83 @@
<?php
/**
* COmanage Registry Function Utilities
*
* Portions licensed to the University Corporation for Advanced Internet
* Development, Inc. ("UCAID") under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* UCAID licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @link https://www.internet2.edu/comanage COmanage Project
* @package registry
* @since COmanage Registry v5.0.0
* @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/

declare(strict_types = 1);

namespace App\Lib\Util;

use Cake\ORM\TableRegistry;
use \Cake\Utility\Inflector;

class FunctionUtilities {
/**
* Create a chained method call
*
* Example:
* $this->getRequest()->getQuery(name: 'group_id)
* $rootObject: $this,
* $chainedDescriptionExample => [
* // Chain of methods
* 'getRequest',
* 'getQuery' => [
* // parameter name => parameter value, We are taking advantage the named parameters feature
* 'name' =>'group_id'
* ],
* ]
*
* @param mixed $rootObj Object of the intance method we are calling
* @param array $chainedDescription Description from root to final method call.
*
* @return mixed Return the intermediate objects or the final value
* @since COmanage Registry v5.0.0
*/

public static function dynamicChainedFunction(mixed $rootObj, array $chainedDescription): mixed {
if(!empty($chainedDescription)) {
$key = key($chainedDescription);
// This is the case where we pass a function with no parameters
$funcName = null;
$params = null;
// We pass a function with an array of parameters
if( \is_int($key)) {
$funcName = array_shift($chainedDescription);
} elseif (\is_string($key)) {
$funcName = $key;
$params = array_shift($chainedDescription);
}

if(!empty($params)) {
$funcCall = $rootObj->$funcName(...$params);
} else {
$funcCall = $rootObj->$funcName();
}
$value = self::dynamicChainedFunction($funcCall, $chainedDescription);
}

return !\is_object($rootObj) ? $rootObj : $value;
}

}
23 changes: 21 additions & 2 deletions app/src/Model/Table/GroupNestingsTable.php
@@ -77,9 +77,9 @@ public function initialize(array $config): void {
$this->setPrimaryLink('group_id');
$this->setRequiresCO(true);

$this->setEditContains(['Groups', 'TargetGroups']);
$this->setEditContains(['Groups', 'GroupMembers', 'TargetGroups']);

$this->setIndexContains(['Groups', 'TargetGroups']);
$this->setIndexContains(['Groups', 'GroupMembers', 'TargetGroups']);

$this->setPermissions([
// XXX update for couAdmins, group owners, etc
@@ -95,6 +95,25 @@ public function initialize(array $config): void {
'index' => ['platformAdmin', 'coAdmin']
]
]);

$this->setAutoViewVars([
'groupMembers' => [
'type' => 'auxiliary',
'model' => 'GroupMembers',
'whereEval' => [
// Where Clause column name
'GroupMembers.group_id' => [
// Chain of methods that will construct the whereClause condition value
// Method that accepts no parameters
'getRequest',
// Method that accepts only one parameter
// getQuery(name: 'group_id')
'getQuery' => [
'name' =>'group_id'
]
]
]
]]);
}

/**
6 changes: 4 additions & 2 deletions app/src/Model/Table/GroupsTable.php
@@ -123,15 +123,17 @@ public function initialize(array $config): void {
// For an Owners Group, the group it manages owners for
'OwnersForGroup',
// For a regular group, the Owners Group
'OwnersGroup'
'OwnersGroup',
'GroupMembers'
]);

$this->setViewContains([
'Identifiers',
// For an Owners Group, the group it manages owners for
'OwnersForGroup',
// For a regular group, the Owners Group
'OwnersGroup'
'OwnersGroup',
'GroupMembers'
]);

// XXX Also used by SearchBlocks
2 changes: 1 addition & 1 deletion app/templates/Groups/fields.inc
@@ -74,7 +74,7 @@ if($vv_action != 'add') {

print $this->Field->statusControl(
fieldName: 'owners_group_id',
status: $vv_obj->owners_group->name,
status: $vv_obj->owners_group->name ?? '',
link: ['url' => ['controller' => 'groups', 'action' => 'edit', $vv_obj->owners_group_id]]
);
}
25 changes: 22 additions & 3 deletions app/templates/element/subnavigation.php
@@ -301,14 +301,33 @@
<li class="nav-item">
<?php
$linkClass = ($active == 'members') ? 'nav-link active' : 'nav-link';
$title = __d('controller', 'Members', [99]);
$num_group_members = 0;
// Group Members tab
if(isset($group_members)) {
$num_group_members = $this->Paginator->counter('{{count}}');
} elseif(isset($groupMembers)) {
// Group Nesting
$num_group_members = count($groupMembers);
} elseif($vv_obj?->group_members) {
// Group Properties Tab
$num_group_members = count($vv_obj->group_members);
}

$tab_title = "<span class='tab-count'>"
. "<span class='tab-count-item'>{$num_group_members}</span>"
. '</span>'
. "<span class='tab-title'>{$title}</span>";

print $this->Html->link(
__d('controller', 'Members', [99]),
$tab_title,
[ 'controller' => 'group_members',
'action' => 'index',
'?' => $linkFilter
],
['class' => $linkClass]
);
['class' => $linkClass,
'escape' => false]
);
?>
</li>
<li class="nav-item">
17 changes: 17 additions & 0 deletions app/webroot/css/co-base.css
@@ -696,6 +696,9 @@ ul.form-list li.alert-banner .co-alert {
text-transform: uppercase;
padding: 1em 1.5em;
color: var(--cmg-color-link) !important;
display: flex;
flex-direction: row-reverse;
align-items: center;
}
.cm-subnav-links .nav-link {
color: var(--cmg-color-link) !important;
@@ -706,6 +709,20 @@ ul.form-list li.alert-banner .co-alert {
background-color: var(--cmg-color-body-bg);
border-color: var(--cmg-color-bg-006) var(--cmg-color-bg-006) var(--cmg-color-body-bg) var(--cmg-color-bg-006);
}
.tab-count {
display: inline-block;
margin: -4px 0 -4px 0.5em;
padding: 1px 4px;
font-size: 0.9em;
border: 1px solid var(--cmg-color-link);
border-radius: 16px;
}
.tab-count-item {
display: inline-block;
}
.nav-link.active .tab-count {
border-color: var(--cmg-color-body-txt);
}
.cm-subnav-links ul.list-inline {
margin: 0.5em 0 0 0;
font-size: 0.9em;

0 comments on commit 54d2fdd

Please sign in to comment.