forked from rapidpro/rapidpro
-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Overhaul UI for managing child workspaces
- Loading branch information
1 parent
747759c
commit 2502798
Showing
5 changed files
with
137 additions
and
198 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1677,11 +1677,11 @@ def test_workspace(self): | |
self.admin, | ||
[ | ||
"Nyaruka", | ||
"Workspaces (1)", | ||
"Dashboard", | ||
"Account", | ||
"Resthooks", | ||
"Incidents", | ||
"Workspaces (2)", | ||
"Dashboard", | ||
"Users (4)", | ||
"Invitations (0)", | ||
"Export", | ||
|
@@ -2344,29 +2344,15 @@ def test_signup(self): | |
self.assertFalse(User.objects.filter(email="[email protected]")) | ||
|
||
def test_create_new(self): | ||
children_url = reverse("orgs.org_sub_orgs") | ||
create_url = reverse("orgs.org_create") | ||
|
||
self.login(self.admin) | ||
|
||
# by default orgs don't have this feature | ||
response = self.client.get(children_url) | ||
self.assertContentMenu(children_url, self.admin, []) | ||
|
||
# trying to access the modal directly should redirect | ||
response = self.client.get(create_url) | ||
self.assertRedirect(response, "/org/workspace/") | ||
# nobody can access if new orgs feature not enabled | ||
response = self.requestView(create_url, self.admin) | ||
self.assertRedirect(response, reverse("orgs.org_workspace")) | ||
|
||
self.org.features = [Org.FEATURE_NEW_ORGS] | ||
self.org.save(update_fields=("features",)) | ||
|
||
response = self.client.get(children_url) | ||
self.assertContentMenu(children_url, self.admin, ["New Workspace"]) | ||
|
||
# give org2 the same feature | ||
self.org2.features = [Org.FEATURE_NEW_ORGS] | ||
self.org2.save(update_fields=("features",)) | ||
|
||
# since we can only create new orgs, we don't show type as an option | ||
self.assertRequestDisallowed(create_url, [None, self.user, self.editor, self.agent]) | ||
self.assertCreateFetch(create_url, [self.admin], form_fields=["name", "timezone"]) | ||
|
@@ -2398,24 +2384,18 @@ def test_create_new(self): | |
self.assertEqual(str(new_org.id), response.headers["X-Temba-Org"]) | ||
|
||
def test_create_child(self): | ||
children_url = reverse("orgs.org_sub_orgs") | ||
list_url = reverse("orgs.org_list") | ||
create_url = reverse("orgs.org_create") | ||
|
||
self.login(self.admin) | ||
|
||
# by default orgs don't have the new_orgs or child_orgs feature | ||
response = self.client.get(children_url) | ||
self.assertContentMenu(children_url, self.admin, []) | ||
|
||
# trying to access the modal directly should redirect | ||
response = self.client.get(create_url) | ||
self.assertRedirect(response, "/org/workspace/") | ||
# nobody can access if child orgs feature not enabled | ||
response = self.requestView(create_url, self.admin) | ||
self.assertRedirect(response, reverse("orgs.org_workspace")) | ||
|
||
self.org.features = [Org.FEATURE_CHILD_ORGS] | ||
self.org.save(update_fields=("features",)) | ||
|
||
response = self.client.get(children_url) | ||
self.assertContentMenu(children_url, self.admin, ["New Workspace"]) | ||
response = self.client.get(list_url) | ||
self.assertContentMenu(list_url, self.admin, ["New"]) | ||
|
||
# give org2 the same feature | ||
self.org2.features = [Org.FEATURE_CHILD_ORGS] | ||
|
@@ -2447,7 +2427,7 @@ def test_create_child(self): | |
self.assertEqual(OrgRole.ADMINISTRATOR, child_org.get_user_role(self.admin)) | ||
|
||
# should have been redirected to child management page | ||
self.assertRedirect(response, "/org/sub_orgs/") | ||
self.assertRedirect(response, "/org/") | ||
|
||
def test_create_child_or_new(self): | ||
create_url = reverse("orgs.org_create") | ||
|
@@ -2491,33 +2471,19 @@ def test_create_child_spa(self): | |
|
||
response = self.client.post(create_url, {"name": "Child Org", "timezone": "Africa/Nairobi"}, HTTP_TEMBA_SPA=1) | ||
|
||
self.assertRedirect(response, reverse("orgs.org_sub_orgs")) | ||
|
||
def test_child_management(self): | ||
sub_orgs_url = reverse("orgs.org_sub_orgs") | ||
menu_url = reverse("orgs.org_menu") + "settings/" | ||
self.assertRedirect(response, reverse("orgs.org_list")) | ||
|
||
self.login(self.admin) | ||
|
||
response = self.client.get(menu_url) | ||
self.assertNotContains(response, "Workspaces") | ||
self.assertNotContains(response, sub_orgs_url) | ||
def test_list(self): | ||
list_url = reverse("orgs.org_list") | ||
|
||
# enable child orgs and create some child orgs | ||
self.org.features = [Org.FEATURE_CHILD_ORGS, Org.FEATURE_USERS] | ||
self.org.save(update_fields=("features",)) | ||
child1 = self.org.create_new(self.admin, "Child Org 1", self.org.timezone, as_child=True) | ||
child2 = self.org.create_new(self.admin, "Child Org 2", self.org.timezone, as_child=True) | ||
|
||
# now we see the Workspaces menu item | ||
self.login(self.admin, choose_org=self.org) | ||
|
||
response = self.client.get(menu_url) | ||
self.assertContains(response, "Workspaces") | ||
self.assertContains(response, sub_orgs_url) | ||
|
||
response = self.assertListFetch( | ||
sub_orgs_url, [self.admin], context_objects=[child1, child2], choose_org=self.org | ||
list_url, [self.admin], context_objects=[self.org, child1, child2], choose_org=self.org | ||
) | ||
|
||
child1_edit_url = reverse("orgs.org_edit_sub_org") + f"?org={child1.id}" | ||
|
@@ -2528,11 +2494,11 @@ def test_child_management(self): | |
child1_edit_url, | ||
{"name": "New Child Name", "timezone": "Africa/Nairobi", "date_format": "Y", "language": "es"}, | ||
) | ||
self.assertEqual(sub_orgs_url, response.url) | ||
self.assertEqual(list_url, response.url) | ||
|
||
child1.refresh_from_db() | ||
self.assertEqual("New Child Name", child1.name) | ||
self.assertEqual("/org/sub_orgs/", response.url) | ||
self.assertEqual("/org/", response.url) | ||
|
||
# edit our sub org's details in a spa view | ||
response = self.client.post( | ||
|
@@ -2541,7 +2507,7 @@ def test_child_management(self): | |
HTTP_TEMBA_SPA=1, | ||
) | ||
|
||
self.assertEqual(reverse("orgs.org_sub_orgs"), response.url) | ||
self.assertEqual(list_url, response.url) | ||
|
||
child1.refresh_from_db() | ||
self.assertEqual("Spa Child Name", child1.name) | ||
|
@@ -2692,9 +2658,9 @@ def test_delete_child(self): | |
response = self.client.get(delete_url) | ||
self.assertContains(response, "You are about to delete the workspace <b>Child Workspace</b>") | ||
|
||
# go through with it, redirects to main workspace page | ||
# go through with it, redirects to workspaces list page | ||
response = self.client.post(delete_url) | ||
self.assertEqual(reverse("orgs.org_sub_orgs"), response["Temba-Success"]) | ||
self.assertEqual(reverse("orgs.org_list"), response["Temba-Success"]) | ||
|
||
child.refresh_from_db() | ||
self.assertFalse(child.is_active) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
{% extends "smartmin/list.html" %} | ||
{% load i18n temba smartmin humanize %} | ||
|
||
{% block content %} | ||
{% block pre-table %} | ||
<temba-modax header="{{ _("Update Workspace") |escapejs }}" id="update-child"> | ||
</temba-modax> | ||
<temba-modax header="{{ _("Delete Workspace") |escapejs }}" id="delete-child"> | ||
</temba-modax> | ||
{% endblock pre-table %} | ||
<form method="get" action="{{ request.path }}" id="search-form"> | ||
<temba-textinput placeholder="{% trans "Search" %}" name="search" value="{{ search }}" class="w-full"> | ||
</temba-textinput> | ||
<input type="submit" class="hide"> | ||
</form> | ||
<div class="mt-4 shadow rounded-lg rounded-bl-none rounded-br-none bg-white">{% include "includes/short_pagination.html" %}</div> | ||
<div class="flex-grow overflow-y-auto shadow"> | ||
<table class="list lined scrolled"> | ||
<thead> | ||
<tr> | ||
<th>{% trans "Name" %}</th> | ||
<th style="text-align:right">{% trans "Users" %}</th> | ||
<th style="text-align:right">{% trans "Contacts" %}</th> | ||
<th style="text-align:right">{% trans "Created On" %}</th> | ||
<th></th> | ||
</tr> | ||
<tbody> | ||
{% for obj in object_list %} | ||
<tr onclick="{% if obj.id != user_org.id %}showUpdateChildModal({{ obj.id }}){% endif %}" | ||
class="{% if obj.id != user_org.id %}hover-linked update{% endif %}"> | ||
<td>{{ obj.name }}</td> | ||
<td style="text-align:right">{{ obj.users.all|length }}</td> | ||
<td style="text-align:right">{{ obj.get_contact_count|intcomma }}</td> | ||
<td style="text-align:right">{{ obj.created_on|day }}</td> | ||
<td class="w-2"> | ||
{% if obj.id != user_org.id %} | ||
<div style="visibility:hidden" | ||
onclick="event.stopPropagation(); showDeleteChildModal({{ obj.id }});" | ||
class="pl-2 pt-1 delete-link linked text-gray-400"> | ||
<temba-icon name="delete_small"> | ||
</temba-icon> | ||
</div> | ||
{% endif %} | ||
</td> | ||
</tr> | ||
{% endfor %} | ||
</tbody> | ||
</thead> | ||
</table> | ||
</div> | ||
{% endblock content %} | ||
{% block extra-script %} | ||
{{ block.super }} | ||
<script> | ||
function showUpdateChildModal(id) { | ||
var modax = document.querySelector('#update-child'); | ||
modax.endpoint = `/org/edit_sub_org/?org=${id}`; | ||
modax.open = true; | ||
} | ||
|
||
function showDeleteChildModal(id) { | ||
var modax = document.querySelector('#delete-child'); | ||
modax.endpoint = `/org/delete_child/${id}/`; | ||
modax.open = true; | ||
} | ||
</script> | ||
{% endblock extra-script %} | ||
{% block extra-style %} | ||
{{ block.super }} | ||
<style type="text/css"> | ||
tr:hover .delete-link { | ||
visibility: visible !important; | ||
} | ||
</style> | ||
{% endblock extra-style %} |
Oops, something went wrong.