Skip to content

Commit

Permalink
Merge pull request #3125 from SEED-platform/feat-3044/filter-labels-s…
Browse files Browse the repository at this point in the history
…erverside

Feat 3044/filter labels serverside
  • Loading branch information
Ryo committed Feb 18, 2022
2 parents 9f594af + 88784cd commit 9524cb3
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 85 deletions.
110 changes: 39 additions & 71 deletions seed/static/seed/js/controllers/inventory_list_beta_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ angular.module('BE.seed.controller.inventory_list_beta', [])
'cycles',
'profiles',
'current_profile',
'labels',
'all_columns',
'derived_columns_payload',
'urls',
Expand Down Expand Up @@ -52,7 +51,6 @@ angular.module('BE.seed.controller.inventory_list_beta', [])
cycles,
profiles,
current_profile,
labels,
all_columns,
derived_columns_payload,
urls,
Expand Down Expand Up @@ -136,6 +134,7 @@ angular.module('BE.seed.controller.inventory_list_beta', [])
// this only happens ONCE (after the ui-grid's saveState.restore has completed)
if ($scope.restore_status === RESTORE_SETTINGS_DONE) {
updateColumnFilterSort();
get_labels();
$scope.load_inventory(1)
.then(function () {
$scope.restore_status = RESTORE_COMPLETE;
Expand Down Expand Up @@ -182,7 +181,6 @@ angular.module('BE.seed.controller.inventory_list_beta', [])
}
}
};
$scope.build_labels();

// Builds the html to display labels associated with this row entity
$scope.display_labels = function (entity) {
Expand Down Expand Up @@ -239,12 +237,6 @@ angular.module('BE.seed.controller.inventory_list_beta', [])
var localStorageKey = 'grid.' + $scope.inventory_type;
var localStorageLabelKey = 'grid.' + $scope.inventory_type + '.labels';

// Reapply valid previously-applied labels
var ids = inventory_service.loadSelectedLabels(localStorageLabelKey);
$scope.selected_labels = _.filter($scope.labels, function (label) {
return _.includes(ids, label.id);
});

$scope.clear_labels = function () {
$scope.selected_labels = [];
};
Expand Down Expand Up @@ -334,57 +326,9 @@ angular.module('BE.seed.controller.inventory_list_beta', [])
});
};

function updateApplicableLabels (current_labels) {
var inventoryIds;
if ($scope.inventory_type === 'properties') {
inventoryIds = _.map($scope.data, 'property_view_id').sort();
} else {
inventoryIds = _.map($scope.data, 'taxlot_view_id').sort();
}
$scope.labels = _.filter(current_labels, function (label) {
return _.some(label.is_applied, function (id) {
return _.includes(inventoryIds, id);
});
});
// Ensure that no previously-applied labels remain
// Filter on $scope.labels to refresh is_applied
$scope.selected_labels = _.filter($scope.labels, function (label) {
return _.find($scope.selected_labels, ['id', label.id]);
});
$scope.build_labels();
};

var filterUsingLabels = function () {
// Only submit the `id` of the label to the API.
var ids;
if ($scope.labelLogic === 'and') {
ids = _.intersection.apply(null, _.map($scope.selected_labels, 'is_applied'));
} else if (_.includes(['or', 'exclude'], $scope.labelLogic)) {
ids = _.union.apply(null, _.map($scope.selected_labels, 'is_applied'));
}

inventory_service.saveSelectedLabels(localStorageLabelKey, _.map($scope.selected_labels, 'id'));

if ($scope.selected_labels.length) {
_.forEach($scope.gridApi.grid.rows, function (row) {
var view_id;
if ($scope.inventory_type === 'properties') {
view_id = row.entity.property_view_id;
} else {
view_id = row.entity.taxlot_view_id;
}
if ($scope.labelLogic === 'exclude') {
if ((_.includes(ids, view_id) && row.treeLevel === 0) || !_.has(row, 'treeLevel')) $scope.gridApi.core.setRowInvisible(row);
else $scope.gridApi.core.clearRowInvisible(row);
} else {
if ((!_.includes(ids, view_id) && row.treeLevel === 0) || !_.has(row, 'treeLevel')) $scope.gridApi.core.setRowInvisible(row);
else $scope.gridApi.core.clearRowInvisible(row);
}
});
} else {
_.forEach($scope.gridApi.grid.rows, $scope.gridApi.core.clearRowInvisible);
}
_.delay($scope.updateHeight, 150);
$scope.load_inventory(1);
};

$scope.labelLogic = localStorage.getItem('labelLogic');
Expand All @@ -395,8 +339,6 @@ angular.module('BE.seed.controller.inventory_list_beta', [])
filterUsingLabels();
};

$scope.$watchCollection('selected_labels', filterUsingLabels);

/**
Opens the update building labels modal.
All further actions for labels happen with that modal and its related controller,
Expand All @@ -419,6 +361,7 @@ angular.module('BE.seed.controller.inventory_list_beta', [])
modalInstance.result.then(function () {
//dialog was closed with 'Done' button.
get_labels();
$scope.load_inventory(1);
});
};

Expand Down Expand Up @@ -774,7 +717,6 @@ angular.module('BE.seed.controller.inventory_list_beta', [])
_.merge(data[relatedIndex], aggregations);
}
$scope.data = data;
get_labels();
$scope.updateQueued = true;
};

Expand All @@ -786,12 +728,27 @@ angular.module('BE.seed.controller.inventory_list_beta', [])
fn = inventory_service.get_taxlots;
}

// add label filtering
let include_ids = undefined;
let exclude_ids = undefined;
if ($scope.selected_labels.length) {
if ($scope.labelLogic === 'and') {
let intersection = _.intersection.apply(null, _.map($scope.selected_labels, 'is_applied'));
include_ids = intersection.length ? intersection : [0];
} else if ($scope.labelLogic === 'or') {
include_ids = _.union.apply(null, _.map($scope.selected_labels, 'is_applied'));
} else if ($scope.labelLogic === 'exclude') {
exclude_ids = _.intersection.apply(null, _.map($scope.selected_labels, 'is_applied'));
}
}

return fn(
page,
chunk,
$scope.cycle.selected_cycle,
_.get($scope, 'currentProfile.id'),
undefined,
include_ids,
exclude_ids,
true,
$scope.organization.id,
false,
Expand Down Expand Up @@ -870,6 +827,7 @@ angular.module('BE.seed.controller.inventory_list_beta', [])
evaluateDerivedColumns();
$scope.select_none();
spinner_utility.hide();
loadSavedLabels();
});
};

Expand All @@ -893,15 +851,28 @@ angular.module('BE.seed.controller.inventory_list_beta', [])
$scope.gridApi.core.raise.sortChanged();
};

watchingSelectedLabels = false;
var get_labels = function () {
label_service.get_labels($scope.inventory_type).then(function (current_labels) {
updateApplicableLabels(current_labels);
filterUsingLabels();
$scope.labels = _.filter(current_labels, function (label) {
return !_.isEmpty(label.is_applied);
});

// load saved label filter
let ids = inventory_service.loadSelectedLabels(localStorageLabelKey);
$scope.selected_labels = _.filter($scope.labels, function (label) {
return _.includes(ids, label.id);
});

// watch for changes
if (!watchingSelectedLabels) {
watchingSelectedLabels = true;
$scope.$watchCollection('selected_labels', filterUsingLabels);
}
$scope.build_labels();
});
};

processData();

$scope.open_ubid_modal = function (selectedViewIds) {
$uibModal.open({
templateUrl: urls.static_url + 'seed/partials/ubid_modal.html',
Expand Down Expand Up @@ -1074,11 +1045,11 @@ angular.module('BE.seed.controller.inventory_list_beta', [])
selectedViewIds = [];

if ($scope.inventory_type === 'properties') {
selectedViewIds = inventory_service.get_properties(undefined, undefined, $scope.cycle.selected_cycle, -1, undefined, true, null, true, $scope.column_filters, $scope.column_sorts, true).then(function (inventory_data) {
selectedViewIds = inventory_service.get_properties(undefined, undefined, $scope.cycle.selected_cycle, -1, undefined, undefined, true, null, true, $scope.column_filters, $scope.column_sorts, true).then(function (inventory_data) {
$scope.run_action(inventory_data.results);
});
} else if ($scope.inventory_type === 'taxlots') {
selectedViewIds = inventory_service.get_taxlots(undefined, undefined, $scope.cycle.selected_cycle, -1, undefined, true, null, true, $scope.column_filters, $scope.column_sorts, true).then(function (inventory_data) {
selectedViewIds = inventory_service.get_taxlots(undefined, undefined, $scope.cycle.selected_cycle, -1, undefined, undefined, true, null, true, $scope.column_filters, $scope.column_sorts, true).then(function (inventory_data) {
$scope.run_action(inventory_data.results);
});
}
Expand Down Expand Up @@ -1443,12 +1414,10 @@ angular.module('BE.seed.controller.inventory_list_beta', [])
var removed = _.difference($scope.selectedOrder, parentsSelectedIds);
var added = _.difference(parentsSelectedIds, $scope.selectedOrder);
if (removed.length === 1 && !added.length) {
// console.log('Removed ', removed);
_.remove($scope.selectedOrder, function (item) {
return item === removed[0];
});
} else if (added.length === 1 && !removed.length) {
// console.log('Added ', added);
$scope.selectedOrder.push(added[0]);
}
$scope.update_selected_display();
Expand Down Expand Up @@ -1484,7 +1453,6 @@ angular.module('BE.seed.controller.inventory_list_beta', [])
$scope.total = _.filter($scope.gridApi.core.getVisibleRows($scope.gridApi.grid), {treeLevel: 0}).length;
if ($scope.updateQueued) {
$scope.updateQueued = false;
if ($scope.selected_labels.length) filterUsingLabels();
}
});
}, 150));
Expand Down
7 changes: 0 additions & 7 deletions seed/static/seed/js/seed.js
Original file line number Diff line number Diff line change
Expand Up @@ -1439,13 +1439,6 @@ SEED_app.config(['stateHelperProvider', '$urlRouterProvider', '$locationProvider
if (currentProfile) inventory_service.save_last_profile(currentProfile.id, $stateParams.inventory_type);
return currentProfile;
}],
labels: ['$stateParams', 'label_service', function ($stateParams, label_service) {
return label_service.get_labels($stateParams.inventory_type).then(function (labels) {
return _.filter(labels, function (label) {
return !_.isEmpty(label.is_applied);
});
});
}],
all_columns: ['$stateParams', 'inventory_service', function ($stateParams, inventory_service) {
if ($stateParams.inventory_type === 'properties') {
return inventory_service.get_property_columns();
Expand Down
10 changes: 6 additions & 4 deletions seed/static/seed/js/services/inventory_service.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ angular.module('BE.seed.service.inventory', []).factory('inventory_service', [
return {order_by: sorts};
}

inventory_service.get_properties = function (page, per_page, cycle, profile_id, property_view_ids, save_last_cycle = true, organization_id = null, include_related = true, column_filters = null, column_sorts = null, ids_only = null) {
inventory_service.get_properties = function (page, per_page, cycle, profile_id, include_view_ids, exclude_view_ids, save_last_cycle = true, organization_id = null, include_related = true, column_filters = null, column_sorts = null, ids_only = null) {
organization_id = organization_id == undefined ? user_service.get_organization().id : organization_id;

var params = {
Expand Down Expand Up @@ -82,7 +82,8 @@ angular.module('BE.seed.service.inventory', []).factory('inventory_service', [

return $http.post('/api/v3/properties/filter/', {
// Pass the specific ids if they exist
property_view_ids,
include_view_ids: include_view_ids,
exclude_view_ids: exclude_view_ids,
// Pass the current profile (if one exists) to limit the column data that is returned
profile_id: profile_id
}, {
Expand Down Expand Up @@ -295,7 +296,7 @@ angular.module('BE.seed.service.inventory', []).factory('inventory_service', [
};


inventory_service.get_taxlots = function (page, per_page, cycle, profile_id, inventory_ids, save_last_cycle = true, organization_id = null, include_related = true, column_filters = null, column_sorts = null, ids_only = null) {
inventory_service.get_taxlots = function (page, per_page, cycle, profile_id, include_view_ids, exclude_view_ids, save_last_cycle = true, organization_id = null, include_related = true, column_filters = null, column_sorts = null, ids_only = null) {
organization_id = organization_id == undefined ? user_service.get_organization().id : organization_id;

var params = {
Expand Down Expand Up @@ -323,7 +324,8 @@ angular.module('BE.seed.service.inventory', []).factory('inventory_service', [

return $http.post('/api/v3/taxlots/filter/', {
// Pass the specific ids if they exist
inventory_ids: inventory_ids,
include_view_ids: include_view_ids,
exclude_view_ids: exclude_view_ids,
// Pass the current profile (if one exists) to limit the column data that is returned
profile_id: profile_id
}, {
Expand Down
10 changes: 7 additions & 3 deletions seed/utils/inventory_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,13 @@ def get_filtered_results(request: Request, inventory_type: Literal['property', '

views_list = views_list.annotate(**annotations).filter(filters).order_by(*order_by)

# Return property views limited to the 'property_view_ids' list. Otherwise, if selected is empty, return all
if f'{inventory_type}_view_ids' in request.data and request.data[f'{inventory_type}_view_ids']:
views_list = views_list.filter(id__in=request.data[f'{inventory_type}_view_ids'])
# return property views limited to the 'include_view_ids' list if not empty
if 'include_view_ids' in request.data and request.data['include_view_ids']:
views_list = views_list.filter(id__in=request.data['include_view_ids'])

# exclude property views limited to the 'exclude_view_ids' list if not empty
if 'exclude_view_ids' in request.data and request.data['exclude_view_ids']:
views_list = views_list.exclude(id__in=request.data['exclude_view_ids'])

if ids_only:
id_list = list(views_list.values_list('id', flat=True))
Expand Down

0 comments on commit 9524cb3

Please sign in to comment.