Skip to content

Commit

Permalink
Add button to show or hide all labels (#4875)
Browse files Browse the repository at this point in the history
* bulk update labels

* translations

* fix test

---------

Co-authored-by: Ross Perry <[email protected]>
Co-authored-by: Hannah Eslinger <[email protected]>
Co-authored-by: Katherine Fleming <[email protected]>
  • Loading branch information
4 people authored Dec 10, 2024
1 parent b6bf91d commit e98a892
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 24 deletions.
20 changes: 19 additions & 1 deletion seed/static/seed/js/controllers/label_admin_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
angular.module('SEED.controller.label_admin', []).controller('label_admin_controller', [
'$scope',
'$state',
'$log',
'urls',
'organization_payload',
Expand All @@ -15,7 +16,7 @@ angular.module('SEED.controller.label_admin', []).controller('label_admin_contro
'$translate',
'$sce',
// eslint-disable-next-line func-names
function ($scope, $log, urls, organization_payload, labels_payload, auth_payload, label_service, simple_modal_service, notification, $translate, $sce) {
function ($scope, $state, $log, urls, organization_payload, labels_payload, auth_payload, label_service, simple_modal_service, notification, $translate, $sce) {
$scope.org = organization_payload.organization;
$scope.auth = auth_payload.auth;

Expand Down Expand Up @@ -154,6 +155,23 @@ angular.module('SEED.controller.label_admin', []).controller('label_admin_contro
});
}

const check_show_in_list = () => {
$scope.all_showing = $scope.labels.every((label) => label.show_in_list);
$scope.toggle_text = !$scope.all_showing ? 'Show' : 'Hide';
};
check_show_in_list();

$scope.toggle_show_all_labels = () => {
check_show_in_list();
$scope.label_ids = $scope.labels.map((label) => label.id);
const data = { show_in_list: !$scope.all_showing };
bulk_update_labels($scope.label_ids, data);
};

const bulk_update_labels = (label_ids, data) => {
label_service.bulk_update_labels($scope.org.id, label_ids, data).then(() => $state.reload());
};

function getTruncatedName(name) {
if (name && name.length > 20) {
name = `${name.substr(0, 20)}...`;
Expand Down
9 changes: 8 additions & 1 deletion seed/static/seed/js/services/label_service.js
Original file line number Diff line number Diff line change
Expand Up @@ -282,14 +282,21 @@ angular.module('SEED.service.label', []).factory('label_service', [
];

const get_property_view_labels_by_goal = (org_id, goal_id, cycle) => $http.get(
'/api/v3/property_view_labels/list_by_goal/',
{ params: { organization_id: org_id, goal_id, cycle } }
)
.then(map_labels);

const bulk_update_labels = (org_id, label_ids, data) => $http
.put(
'/api/v3/labels/bulk_update/',
{ label_ids, data },
{ params: { organization_id: org_id } }
).then((response) => response);

return {
get_labels,
get_labels_for_org,
bulk_update_labels,
create_label,
create_label_for_org,
update_label,
Expand Down
3 changes: 2 additions & 1 deletion seed/static/seed/partials/label_admin.html
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,11 @@ <h1>{$:: org.name $}</h1>
</form>
</div>

<div style="padding-left: 10px" class="sectionLabel">
<div style="padding: 10px; display: flex; justify-content: space-between" class="sectionLabel">
<p>
<strong><i class="fa-solid fa-tags"></i>&nbsp;&nbsp;{$:: 'Existing Labels' | translate $}</strong>
</p>
<button class="btn btn-default" ng-click="toggle_show_all_labels()">{$ toggle_text + ' All Labels' | translate $}</button>
</div>

<div class="table_list_container">
Expand Down
27 changes: 26 additions & 1 deletion seed/tests/test_labels.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@
Unit tests for seed/views/labels.py
"""

import json

import pytest
from django.db import IntegrityError, transaction
from django.urls import reverse_lazy

from seed.models import ASSESSED_RAW, Property, PropertyView, TaxLot, TaxLotView
from seed.models import StatusLabel as Label
from seed.models.data_quality import DataQualityCheck, Rule
from seed.test_helpers.fake import FakePropertyStateFactory, FakeTaxLotStateFactory
from seed.tests.util import DataMappingBaseTestCase
from seed.tests.util import AccessLevelBaseTestCase, DataMappingBaseTestCase
from seed.utils.organizations import create_organization
from seed.views.v3.label_inventories import LabelInventoryViewSet

Expand Down Expand Up @@ -98,3 +101,25 @@ def test_error_occurs_when_trying_to_apply_a_label_to_taxlotview_from_a_differen
)

self.assertFalse(TaxLotView.objects.get(pk=org_1_taxlotview.id).labels.all().exists())


class TestLabelViewSet(AccessLevelBaseTestCase):
def setUp(self):
super().setUp()

def test_label_bulk_update(self):
labels = Label.objects.all()
show_in_list_count = labels.filter(show_in_list=True).count()
assert show_in_list_count == 0

label_ids = list(labels.values_list("id", flat=True))
url = reverse_lazy("api:v3:labels-bulk-update") + "?organization_id=" + str(self.org.id)
data = {"label_ids": label_ids, "data": {"show_in_list": True}}
self.client.put(url, data=json.dumps(data), content_type="application/json")
show_in_list_count = Label.objects.filter(show_in_list=True).count()
assert show_in_list_count == Label.objects.count()

data["data"]["show_in_list"] = False
self.client.put(url, data=json.dumps(data), content_type="application/json")
show_in_list_count = Label.objects.filter(show_in_list=True).count()
assert show_in_list_count == 0
2 changes: 1 addition & 1 deletion seed/tests/test_labels_api_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def test_labels_inventory_specific_filter_endpoint_provides_ids_for_records_wher
data = response_a.json()
for label in data:
if label.get("name") == "test_label-a":
self.assertListEqual(label.get("is_applied"), [p_view_1.id, p_view_2.id])
self.assertListEqual(sorted(label.get("is_applied")), sorted([p_view_1.id, p_view_2.id]))
elif label.get("name") == "test_label-b":
self.assertCountEqual(label.get("is_applied"), [p_view_2.id])
else:
Expand Down
57 changes: 38 additions & 19 deletions seed/views/v3/labels.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,20 @@
:author 'Piper Merriam <[email protected]>'
"""

from django.db import transaction
from django.http import JsonResponse
from django.utils.decorators import method_decorator
from drf_yasg.utils import swagger_auto_schema
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.parsers import FormParser, JSONParser
from rest_framework.renderers import JSONRenderer

from seed.filters import LabelFilterBackend
from seed.lib.superperms.orgs.decorators import has_perm_class
from seed.models import StatusLabel as Label
from seed.serializers.labels import LabelSerializer
from seed.utils.api_schema import AutoSchemaHelper
from seed.utils.api_schema import AutoSchemaHelper, swagger_auto_schema_org_query_param
from seed.utils.viewsets import SEEDOrgNoPatchOrOrgCreateModelViewSet


Expand Down Expand Up @@ -76,25 +80,22 @@
name="update",
decorator=[
has_perm_class("requires_root_member_access"),
],
)
@method_decorator(
name="update",
decorator=swagger_auto_schema(
manual_parameters=[
AutoSchemaHelper.query_org_id_field(
required=False, description="Optional org id which overrides the users (default) current org id"
)
],
request_body=AutoSchemaHelper.schema_factory(
{
"name": "string",
"color": "string",
},
required=["name"],
description="An object containing meta data for updating a label",
swagger_auto_schema(
manual_parameters=[
AutoSchemaHelper.query_org_id_field(
required=False, description="Optional org id which overrides the users (default) current org id"
)
],
request_body=AutoSchemaHelper.schema_factory(
{
"name": "string",
"color": "string",
},
required=["name"],
description="An object containing meta data for updating a label",
),
),
),
],
)
class LabelViewSet(SEEDOrgNoPatchOrOrgCreateModelViewSet):
"""
Expand Down Expand Up @@ -129,3 +130,21 @@ def get_queryset(self):
def get_serializer(self, *args, **kwargs):
kwargs["super_organization"] = self.get_organization(self.request)
return super().get_serializer(*args, **kwargs)

@swagger_auto_schema_org_query_param
@has_perm_class("requires_root_member_access")
@action(detail=False, methods=["PUT"])
def bulk_update(self, request):
organization_id = self.get_parent_org(self.request)
label_ids = request.data.get("label_ids")
data = request.data.get("data")
if not organization_id or not label_ids or not data:
return JsonResponse({"status": "error", "message": "Missing required arguments"}, status=status.HTTP_400_BAD_REQUETS)

labels = Label.objects.filter(id__in=label_ids, super_organization=organization_id)
try:
with transaction.atomic():
labels.update(**data)
return JsonResponse({})
except Exception as e:
return JsonResponse({"status": "error", "message": str(e)}, status=status.HTTP_400_BAD_REQUETS)

0 comments on commit e98a892

Please sign in to comment.