Skip to content

Commit

Permalink
fix(employees): restore locked employee filter
Browse files Browse the repository at this point in the history
This commit fixes the "locked" employee feature on the employee
configuration page for payroll which was lost during the migration to
bh-checkbox-tree.  To do this, I added a new feature to bh-checkbox-tree
to allow disabling nodes based on their id, similar to how the
checked-ids functionality works.

In this case, disabled ids will retain the state they came in with,
being ignore in the "setNodeValue()"  function.  Therefore, whatever the
node came in with, it will leave with.  Additionally, the icon disables
the checkbox, makes the font italics, and puts a little lock icon in
front of the text value.

Thanks to @lomamech for pointing this out.
  • Loading branch information
jniles committed Dec 7, 2020
1 parent 45a1859 commit 968a887
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 11 deletions.
16 changes: 16 additions & 0 deletions client/src/css/structure.css
Original file line number Diff line number Diff line change
Expand Up @@ -1044,3 +1044,19 @@ a[disabled] {
.lot-width {
width: 30%;
}

/* lock certain items of the checkbox tree when disabled */
[data-bh-checkbox-tree] input[type="checkbox"][disabled],
[data-bh-checkbox-tree] input[type="checkbox"][disabled] + span {
cursor: not-allowed;
font-style: italic;
}

[data-bh-checkbox-tree] input[type="checkbox"][disabled] + span:before {
display: inline-block;
font: normal normal normal 14px/1 FontAwesome;
font-size: inherit;
content : "\f023";
padding-right: 5px;
text-rendering: auto;
}
6 changes: 3 additions & 3 deletions client/src/js/components/bhCheckboxTree/bhCheckboxTree.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<div ng-repeat="node in $ctrl.root.children track by $ctrl.tree.id(node)">
<div class="checkbox">
<label data-label="{{node._label}}">
<input type="checkbox" ng-model="node._checked" ng-change="$ctrl.setNodeValue(node, node._checked)" />
<input type="checkbox" ng-model="node._checked" ng-change="$ctrl.setNodeValue(node, node._checked)" ng-disabled="node._disabled" />
<span ng-class="{ 'text-bold' : node.children.length }" translate>{{node._label}}</span>
</label>
</div>
Expand All @@ -18,7 +18,7 @@
<li ng-repeat="child in node.children track by $ctrl.tree.id(child)">
<div class="checkbox">
<label data-label="{{child._label}}">
<input type="checkbox" ng-model="child._checked" ng-change="$ctrl.setNodeValue(child, child._checked)" />
<input type="checkbox" ng-model="child._checked" ng-change="$ctrl.setNodeValue(child, child._checked)" ng-disabled="child._disabled" />
<span translate>{{child._label}}</span>
</label>
</div>
Expand All @@ -27,7 +27,7 @@
<li ng-repeat="grandchild in child.children track by $ctrl.tree.id(grandchild)">
<div class="checkbox">
<label data-label="{{grandchild._label}}">
<input type="checkbox" ng-model="grandchild._checked" ng-change="$ctrl.setNodeValue(grandchild, grandchild._checked)" />
<input type="checkbox" ng-model="grandchild._checked" ng-change="$ctrl.setNodeValue(grandchild, grandchild._checked)" ng-disabled="grandchild._disabled" />
<span translate>{{grandchild._label}}</span>
</label>
</div>
Expand Down
52 changes: 47 additions & 5 deletions client/src/js/components/bhCheckboxTree/bhCheckboxTree.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ angular.module('bhima.components')
bindings : {
data : '<',
checkedIds : '<?',
disabledIds : '<?',
onChange : '&',
idKey : '@?',
labelKey : '@?',
Expand All @@ -27,6 +28,8 @@ function bhCheckboxTreeController(Tree) {
$ctrl.labelKey = $ctrl.labelKey || DEFAULT_LABEL_KEY;
$ctrl.parentKey = $ctrl.parentKey || DEFAULT_PARENT_KEY;

$ctrl.disabledIds = $ctrl.disabledIds || [];

if ($ctrl.data) {
buildTree($ctrl.data);
}
Expand All @@ -37,11 +40,36 @@ function bhCheckboxTreeController(Tree) {
buildTree(changes.data.currentValue);
}

if (changes.disabledIds && changes.disabledIds.currentValue) {
processDisabledIds();
getCheckedNodes();
}

if (changes.checkedIds && changes.checkedIds.currentValue) {
processCheckedIds();
getCheckedNodes();
}
};

function processDisabledIds() {
// ensure that disabled ids are an array
if (!Array.isArray($ctrl.disabledIds) || $ctrl.data.length === 0) {
return;
}

// ensure that the mask is a cloned array
const mask = [...$ctrl.disabledIds];

// loop through and set the disabled property on the checkbox
mask
.filter(id => id !== $ctrl.tree.id($ctrl.root))
.forEach(id => {
const node = $ctrl.tree.find(id);
if (!node) { return; }
node._disabled = true;
});
}

function processCheckedIds() {
// ensure that checked ids are an array
if (!Array.isArray($ctrl.checkedIds) || $ctrl.data.length === 0) {
Expand All @@ -58,6 +86,7 @@ function bhCheckboxTreeController(Tree) {
.forEach(id => {
const node = $ctrl.tree.find(id);
if (!node) { return; }
if (node._disabled) { return; }
node._checked = true;
});
}
Expand All @@ -69,6 +98,7 @@ function bhCheckboxTreeController(Tree) {
data.forEach(node => {
node._label = node[$ctrl.labelKey];
node._checked = false;
node._disabled = false;

// work on flat arrays by faking a tree
if ($ctrl.isFlatTree) { node[$ctrl.parentKey] = 0; }
Expand All @@ -94,10 +124,15 @@ function bhCheckboxTreeController(Tree) {
*/
function getCheckedNodes() {
const checked = [];

$ctrl.tree.walk(node => { if (node._checked) { checked.push($ctrl.tree.id(node)); } });

// since disabled nodes cannot be checked, remove them from the count
// this allows the toggle on the root node to function correctly.
const numCheckableNodes = ($ctrl.data.length - $ctrl.disabledIds.length);

// toggle the root node if all child nodes are checked
$ctrl.root._checked = checked.length === $ctrl.data.length;
$ctrl.root._checked = checked.length === numCheckableNodes;

// fire the callback.
$ctrl.onChange({ data : checked });
Expand All @@ -122,16 +157,20 @@ function bhCheckboxTreeController(Tree) {
$ctrl.setNodeValue = setNodeValue;
function setNodeValue(node, isChecked) {

const isRootNode = $ctrl.tree.isRootNode(node);

// set the value of the node to isChecked
node._checked = isChecked;
if (!node._disabled || isRootNode) {
node._checked = isChecked;
}

// recursively update all child nodes.
if (isParentNode(node)) {
node.children.forEach(child => setNodeValue(child, isChecked));
}

// make sure the parent is toggled if all children are toggled
if (!$ctrl.tree.isRootNode(node)) {
if (!isRootNode) {
updateParentNodeCheckedState(node.parent);
}

Expand All @@ -155,9 +194,12 @@ function bhCheckboxTreeController(Tree) {
// in the getCheckedNodes() function.
if ($ctrl.tree.isRootNode(node)) { return; }

// check if every child node is checked
// check if a child node is checked
const isChecked = node.children.some(child => child._checked);
node._checked = isChecked;

if (!node._disabled) {
node._checked = isChecked;
}

// recurse up to root
updateParentNodeCheckedState(node.parent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
is-flat-tree="true"
data="EmployeeConfigModalCtrl.employees"
checked-ids="EmployeeConfigModalCtrl.checkedUuids"
disabled-ids="EmployeeConfigModalCtrl.disabledUuids"
id-key="uuid"
label-key="display_name"
on-change="EmployeeConfigModalCtrl.onChangeRoleSelection(data)">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,10 @@ function EmployeeConfigModalController($state, Config, Notify, AppCache, bhConst
const cache = AppCache('EmployeeModal');

if (params.isCreateState || params.id) {
vm.stateParams = params;
cache.stateParams = params;
} else {
vm.stateParams = cache.stateParams;
}

vm.stateParams = cache.stateParams;
vm.isCreateState = vm.stateParams.isCreateState;

vm.onChangeRoleSelection = onChangeRoleSelection;
Expand All @@ -44,8 +42,13 @@ function EmployeeConfigModalController($state, Config, Notify, AppCache, bhConst
return Config.getEmployeeConfiguration(vm.stateParams.id);
})
.then((employeeConfig) => {

vm.checkedUuids = employeeConfig.map(row => row.employee_uuid);

vm.disabledUuids = vm.employees
.filter(row => row.locked)
.map(row => row.uuid);

// clone the original values as the new values.
vm.checked = [...vm.checkedUuids];
})
Expand Down

0 comments on commit 968a887

Please sign in to comment.