Skip to content

CFM-291_Show_the_count_of_members_on_the_members_tab #184

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 18 additions & 11 deletions app/src/Controller/StandardController.php
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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")) {
Expand Down
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
Expand Up @@ -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
Expand All @@ -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'
]
]
]
]]);
}

/**
Expand Down
6 changes: 4 additions & 2 deletions app/src/Model/Table/GroupsTable.php
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion app/templates/Groups/fields.inc
Expand Up @@ -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]]
);
}
Expand Down
15 changes: 12 additions & 3 deletions app/templates/element/subnavigation.php
Expand Up @@ -301,14 +301,23 @@
<li class="nav-item">
<?php
$linkClass = ($active == 'members') ? 'nav-link active' : 'nav-link';
$title = __d('controller', 'Members', [99]);
$num_group_members = $group_members?->count() // GroupMembers tab
?? count($groupMembers // Group Nesting
?? $vv_obj?->group_members // Groups tab
?? []);
$tab_title = "<span class='tab-title'>{$title}</span>"
. "<span class='mx-2 badge rounded-pill bg-outline-primary'>{$num_group_members}</span>";
Copy link

@arlen arlen Apr 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not use Bootstrap utility classes here - they are fiddly and break the simpler styles. Instead just provide the class "tab-count". Then in co-base.css add the following selectors:

.tab-count {
   display: inline-block;
   margin: -4px 0;
   margin-left: 0.5em;
   padding: 1px 4px;
   font-size: 0.9em;
   border: 1px solid var(--cmg-color-link);
   border-radius: 16px;
}
.nav-link.active .tab-count {
   border-color: var(--cmg-color-body-txt);
}


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">
Expand Down