Skip to content

CFM-291_filter_groups_by_member #196

Merged
Changes from all commits
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
6 changes: 5 additions & 1 deletion app/src/Lib/Traits/IndexQueryTrait.php
@@ -159,7 +159,11 @@ public function getIndexQuery(bool $pickerMode = false, array $requestParams = [
$this->viewBuilder()
->getVar('vv_tz'));

// Pass any additional field filter confiration in the view
// Extra View Variables
foreach ($table->getViewVars() as $key => $variable) {
$this->set($key, $variable);
}
// Pass any additional field filter configuration in the view
$this->set('vv_searchable_attributes_extras', $table->getSearchFiltersExtras());
if(!empty($searchableAttributes)) {
$this->set('vv_searchable_attributes', $searchableAttributes);
32 changes: 30 additions & 2 deletions app/src/Lib/Traits/SearchFilterTrait.php
@@ -52,6 +52,12 @@ trait SearchFilterTrait {
*/
private array $searchFiltersExtras = [];

/**
* List of view Vars
* @var array
*/
private array $viewVars = [];

/**
* Optional filter configuration that dictates display state and allows for related models
*
@@ -135,7 +141,7 @@ public function addJoins(Query $query, string $attribute, ServerRequest $request
* @since COmanage Registry v5.0.0
*/
public function constructDateComparisonClause(QueryExpression $exp, string $attributeWithModelPrefix, array $dates): QueryExpression {
// Both are empty, just return
// Both are empty, return
if (empty($dates[0]) && empty($dates[1])) {
return $exp;
}
@@ -243,9 +249,22 @@ public function getSearchableAttributes(string $controller, string $vv_tz=null):
}

$filterType = $f['type'] ?? 'string';
// Custom boolean use cases
if(\in_array($f['type'], ['isNull', 'isNotNull'])) {
$filterType = 'boolean';
}
// Picker configuration
if(isset($f['picker'])) {
$autocompleteArgs = [
'type' => 'default',
'fieldName' => $field,
'personType' => $f['picker']['type'],
'htmlId' => $field, // This is the input ID
'viewConfigParameters' => $f['picker']['configuration']
];
$this->viewVars['vv_autocomplete_arguments'] = $autocompleteArgs;
}

$this->searchFilters[$field] = [
'type' => $filterType,
'label' => $f['label'] ?? StringUtilities::columnKey($fieldName, $field, $vv_tz, true),
@@ -256,7 +275,7 @@ public function getSearchableAttributes(string $controller, string $vv_tz=null):
}

foreach ($this->filterMetadataFields() as $column => $type) {
// If the column is an array then we are accessing the Metadata fields. Skip
// If the column is an array, then we are accessing the Metadata fields. Skip
if(is_array($type)) {
continue;
}
@@ -323,4 +342,13 @@ public function getSearchFiltersExtras(): array
return $this->searchFiltersExtras;
}

/**
* Get View Vars
*
* @since COmanage Registry v5.0.0
*/
public function getViewVars(): array
{
return $this->viewVars;
}
}
26 changes: 26 additions & 0 deletions app/src/Model/Table/GroupsTable.php
@@ -145,6 +145,16 @@ public function initialize(array $config): void {
'groupTypes' => [
'type' => 'enum',
'class' => 'GroupTypeEnum'
],
// Required for peoplePicker
'cosettings' => [
'type' => 'auxiliary',
'model' => 'CoSettings'
],
// Required for peoplePicker
'types' => [
'type' => 'auxiliary',
'model' => 'Types'
]
]);

@@ -154,6 +164,22 @@ public function initialize(array $config): void {
'model' => 'Identifiers',
'active' => true,
'order' => 4
],
'person_id' => [
'type' => 'integer',
'model' => 'GroupMembers',
'active' => true,
'order' => 5,
'picker' => [
'type' => 'person',
'configuration' => [
// For the Groups Filtering block we want to
// pick/GET from the entire CO pool of people
'action' => 'GET',
// The co configuration will fall throught the default configuration
'for' => 'co'
]
]
]
]);

34 changes: 34 additions & 0 deletions app/src/View/Helper/FieldHelper.php
@@ -168,6 +168,40 @@ public function calculateLabelAndDescription(string $fieldName): array
return [$label, $desc];
}

/**
* Calculate the list of classes for the li element
*
* @return string
*/
public function calculateLiClasses(): string
{
$fieldName = $this->getView()->get('fieldName');
$vv_field_arguments = $this->getView()->get('vv_field_arguments');

// Class calculation by field Type
$classes = match ($this->getFieldType($fieldName)) {
'date',
'datetime',
'timestamp' => 'fields-datepicker ',
default => ''
};

// Class calculation by field name
$classes .= match ($fieldName) {
'source_record' => 'source-record ',
'retry_interval',
'login' => 'subfield ',
default => ''
};

// Class calculation by type of Info Div
if(isset($vv_field_arguments['autocomplete'])) {
$classes .= 'fields-people-autocomplete ';
}

return $classes;
}

/**
* Emit a date/time form control.
* This is a wrapper function for $this->control()
18 changes: 18 additions & 0 deletions app/src/View/Helper/FilterHelper.php
@@ -30,6 +30,7 @@
namespace App\View\Helper;

use Cake\Collection\Collection;
use Cake\ORM\TableRegistry;
use Cake\Utility\{Inflector, Hash};
use Cake\View\Helper;

@@ -157,4 +158,21 @@ public function getHiddenFields(): array
->filter(fn($value, $key) => !\in_array($key, $searchable_parameters, true) && $key != 'page')
->toArray();
}

/**
* Construct Full Name from Person ID
*
* @param int $personId
*
* @return string
*/
public function getFullName(int $personId): string
{
if(empty($personId)) {
return '';
}
$ModelTable = TableRegistry::getTableLocator()->get('Names');
$person = $ModelTable->primaryName($personId);
return "{$person->given} {$person->family}";
}
}
26 changes: 25 additions & 1 deletion app/templates/element/filter/filter.php
@@ -27,8 +27,23 @@

declare(strict_types = 1);

use Cake\Utility\Inflector;
?>

<script type="text/javascript">
$(function() {
// Remove the friendly representation of the person_id input element before submiting
const filterForm = document.getElementById("top-filters-form");
filterForm.addEventListener('formdata', (event) => {
if(event.formData.has('person_id')) {
const personId = $(filterForm).find('#person_id')[0].getAttribute('datapersonid')
event.formData.set('person_id', personId)
}
});
});
</script>

<?php
use Cake\Utility\Inflector;

// $this->name = Models
$modelsName = $this->name;
@@ -68,8 +83,17 @@
<?php
foreach($field_generic_columns as $key => $options) {
$elementArguments = compact('options', 'key');
// Set in SearchfilterTrait.php
if($vv_autocomplete_arguments['fieldName'] === $key) {
// Picker is a custom type.
// This is why we calculate it here, and we
// only use it to pick the correct element
$options['type'] = 'picker';
}

print match($options['type']) {
'date' => $this->element('filter/dateSingle', $elementArguments),
'picker' => $this->element('filter/peoplePicker', $elementArguments),
default => $this->element('filter/default', $elementArguments),
};
}
65 changes: 65 additions & 0 deletions app/templates/element/filter/peoplePicker.php
@@ -0,0 +1,65 @@
<?php
/**
* COmanage Registry People Picker
*
* 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)
*/


/*
* Parameters:
* $columns : array, required
* $key : string, required
* $options : array, required
*/

declare(strict_types = 1);

use Cake\Utility\{Inflector};

// $columns = the passed parameter $indexColumns as found in columns.inc; provides overrides for labels and sorting.
$columns = $vv_indexColumns;

$wrapperCssClass = 'filter-active';
if(empty($options['active'])) {
$wrapperCssClass = 'filter-inactive';
}

$label = Inflector::humanize(
Inflector::underscore(
$options['label'] ?? $columns[$key]['label']
)
);

// Get the Field configuration
$formParams = $this->Filter->calculateFieldParams($key, $label);
if(!empty($formParams['value']) && $key == 'person_id') {
$formParams['fullName'] = $this->Filter->getFullName((int)$formParams['value']);
}
$vv_autocomplete_arguments['formParams'] = $formParams;

?>

<div class="filter-standard <?= $wrapperCssClass ?>">
<?= $this->element('peopleAutocomplete', $vv_autocomplete_arguments) ?>
</div>
6 changes: 5 additions & 1 deletion app/templates/element/filter/topButtons.php
@@ -41,10 +41,12 @@
$populated_vvar = lcfirst(Inflector::pluralize(Inflector::camelize($key)));
$button_label = 'Range';
if(isset($$populated_vvar) && isset($$populated_vvar[$params])) {
// Get label name from AutoViewPopulated vars
$button_label = $$populated_vvar[$params];
} elseif(!is_array($params)) {
$button_label = $params;
if(isset($vv_searchable_attributes_extras)) {
// Extras use case
if(!empty($vv_searchable_attributes_extras)) {
$flattenedSearchableAttributesExtras = Hash::flatten($vv_searchable_attributes_extras);
$filteredFlattenedSearchableAttributesExtras = array_filter(
$flattenedSearchableAttributesExtras,
@@ -54,6 +56,8 @@
if(!empty($filteredFlattenedSearchableAttributesExtras)) {
$button_label = array_pop($filteredFlattenedSearchableAttributesExtras);
}
} elseif ($key == 'person_id') {
$button_label = $this->Filter->getFullName((int)$params);
}
}

24 changes: 1 addition & 23 deletions app/templates/element/form/listItem.php
@@ -38,28 +38,6 @@
$fieldName = $arguments['fieldName'];
$this->set('vv_field_arguments', $arguments);

// Class calculation by field Type
$classes = match ($this->Field->getFieldType($fieldName)) {
'date',
'datetime',
'timestamp' => 'fields-datepicker ',
default => ''
};

// Class calculation by field name
$classes .= match ($fieldName) {
'source_record' => 'source-record ',
'retry_interval',
'login' => 'subfield ',
default => ''
};

// Class calculation by type of Info Div
if(isset($arguments['autocomplete'])) {
$classes .= 'fields-people-autocomplete ';
}


// If an attribute is frozen, inject a special link to unfreeze it, since
// the attribute is read-only and the admin can't simply uncheck the setting
if($fieldName == 'frozen' && $this->Field->getEntity()->frozen) {
@@ -101,6 +79,6 @@

?>

<li class="<?= trim($classes) ?>">
<li class="<?= trim($this->Field->calculateLiClasses()) ?>">
<?= $this->element('form/fieldDiv')?>
</li>
2 changes: 1 addition & 1 deletion app/templates/element/javascript.php
@@ -175,7 +175,7 @@
$('#top-filters-submit').addClass("tss-rebalance");
} else {
$('#top-filters-submit').removeClass("tss-rebalance");
}
}
}
});