diff --git a/atst/routes/workspaces.py b/atst/routes/workspaces.py index 64faac94..fcc5f7ae 100644 --- a/atst/routes/workspaces.py +++ b/atst/routes/workspaces.py @@ -12,6 +12,8 @@ from atst.domain.workspaces import Workspaces from atst.domain.projects import Projects from atst.forms.new_project import NewProjectForm from atst.forms.new_member import NewMemberForm +from atst.domain.authz import Authorization +from atst.models.permissions import Permissions bp = Blueprint("workspaces", __name__) @@ -26,7 +28,15 @@ def workspace(): ) except UnauthorizedError: pass - return {"workspace": workspace} + + def user_can(permission): + if workspace: + return Authorization.has_workspace_permission( + g.current_user, workspace, permission + ) + return False + + return {"workspace": workspace, "permissions": Permissions, "user_can": user_can} @bp.route("/workspaces") diff --git a/styles/components/_empty_state.scss b/styles/components/_empty_state.scss index be8675ad..6117484b 100644 --- a/styles/components/_empty_state.scss +++ b/styles/components/_empty_state.scss @@ -14,7 +14,7 @@ @include icon-color($color-gray-light); } - p { + .empty-state__message { @include h2; line-height: 1.2; max-width: 15em; @@ -24,4 +24,13 @@ @include h1; } } + + .empty-state__sub-message { + @include h4; + color: $color-gray; + + @include media($large-screen) { + @include h3; + } + } } diff --git a/templates/components/empty_state.html b/templates/components/empty_state.html index 7dc6f119..b0aaa038 100644 --- a/templates/components/empty_state.html +++ b/templates/components/empty_state.html @@ -1,13 +1,20 @@ {% from "components/icon.html" import Icon %} -{% macro EmptyState(message, actionLabel, actionHref, icon=None) -%} +{% macro EmptyState(message, action_label, action_href, icon=None, sub_message=None) -%}
-

{{ message }}

+

{{ message }}

{% if icon %} {{ Icon(icon) }} {% endif %} - {{ actionLabel }} + {% if sub_message %} +

{{ sub_message }}

+ {% endif %} + + {% if action_href and action_label %} + {{ action_label }} + {% endif %} +
{%- endmacro %} diff --git a/templates/navigation/workspace_navigation.html b/templates/navigation/workspace_navigation.html index a3de6043..5ef3ec8c 100644 --- a/templates/navigation/workspace_navigation.html +++ b/templates/navigation/workspace_navigation.html @@ -6,7 +6,7 @@ "Projects", href=url_for("workspaces.workspace_projects", workspace_id=workspace.id), active=request.url_rule.rule.startswith('/workspaces//projects'), - subnav=[ + subnav=None if not user_can(permissions.ADD_APPLICATION_IN_WORKSPACE) else [ { "label": "Add New Project", "href": url_for('workspaces.new_project', workspace_id=workspace.id), @@ -20,7 +20,7 @@ "Members", href=url_for("workspaces.workspace_members", workspace_id=workspace.id), active=request.url_rule.rule.startswith('/workspaces//members'), - subnav=[ + subnav=None if not user_can(permissions.ASSIGN_AND_UNASSIGN_ATAT_ROLE) else [ { "label": "Add New Member", "href": url_for("workspaces.new_member", workspace_id=workspace.id), diff --git a/templates/requests.html b/templates/requests.html index 85190baf..31f2c7d1 100644 --- a/templates/requests.html +++ b/templates/requests.html @@ -29,8 +29,8 @@ {{ EmptyState( 'There are currently no active requests for you to see.', - actionLabel='Create a new JEDI Cloud Request', - actionHref=url_for('requests.requests_form_new', screen=1), + action_label='Create a new JEDI Cloud Request', + action_href=url_for('requests.requests_form_new', screen=1), icon='document' ) }} diff --git a/templates/workspace_members.html b/templates/workspace_members.html index 6fb852cb..d1e43515 100644 --- a/templates/workspace_members.html +++ b/templates/workspace_members.html @@ -6,10 +6,13 @@ {% if not workspace.members %} + {% set user_can_invite = user_can(permissions.ASSIGN_AND_UNASSIGN_ATAT_ROLE) %} + {{ EmptyState( 'There are currently no members in this Workspace.', - actionLabel='Invite a new Member', - actionHref='/members/new', + action_label='Invite a new Member' if user_can_invite else None, + action_href='/members/new' if user_can_invite else None, + sub_message=None if user_can_invite else 'Please contact your JEDI workspace administrator to invite new members.', icon='avatar' ) }} diff --git a/templates/workspace_projects.html b/templates/workspace_projects.html index d2af0e17..0ad2d6ef 100644 --- a/templates/workspace_projects.html +++ b/templates/workspace_projects.html @@ -1,36 +1,54 @@ {% from "components/icon.html" import Icon %} {% from "components/alert.html" import Alert %} +{% from "components/empty_state.html" import EmptyState %} {% extends "base_workspace.html" %} + {% block workspace_content %} -{% for project in workspace.projects %} -
-
-

{{ project.name }} ({{ project.environments|length }} environments)

- - {{ Icon('edit') }} - edit - -
- -
-{% endfor %} + {% set can_create_projects = user_can(permissions.ADD_APPLICATION_IN_WORKSPACE) %} + + {{ EmptyState( + 'This workspace doesn’t have any projects yet.', + action_label='Add a New Project' if can_create_projects else None, + action_href=url_for('workspaces.new_project', workspace_id=workspace.id) if can_create_projects else None, + icon='cloud', + sub_message=None if can_create_projects else 'Please contact your JEDI workspace administrator to set up a new project.' + ) }} + +{% else %} + + {% for project in workspace.projects %} +
+
+

{{ project.name }} ({{ project.environments|length }} environments)

+ + {{ Icon('edit') }} + edit + +
+ +
+ {% endfor %} + +{% endif %} {% endblock %} diff --git a/tests/routes/test_workspaces.py b/tests/routes/test_workspaces.py new file mode 100644 index 00000000..202a8127 --- /dev/null +++ b/tests/routes/test_workspaces.py @@ -0,0 +1,53 @@ +from tests.factories import UserFactory, WorkspaceFactory +from atst.domain.workspaces import Workspaces +from atst.models.workspace_user import WorkspaceUser + + +def test_user_with_permission_has_add_project_link(client, user_session): + user = UserFactory.create() + workspace = WorkspaceFactory.create() + Workspaces._create_workspace_role(user, workspace, "owner") + + user_session(user) + response = client.get("/workspaces/{}/projects".format(workspace.id)) + assert ( + 'href="/workspaces/{}/projects/new"'.format(workspace.id).encode() + in response.data + ) + + +def test_user_without_permission_has_no_add_project_link(client, user_session): + user = UserFactory.create() + workspace = WorkspaceFactory.create() + Workspaces._create_workspace_role(user, workspace, "developer") + user_session(user) + response = client.get("/workspaces/{}/projects".format(workspace.id)) + assert ( + 'href="/workspaces/{}/projects/new"'.format(workspace.id).encode() + not in response.data + ) + + +def test_user_with_permission_has_add_member_link(client, user_session): + user = UserFactory.create() + workspace = WorkspaceFactory.create() + Workspaces._create_workspace_role(user, workspace, "owner") + + user_session(user) + response = client.get("/workspaces/{}/members".format(workspace.id)) + assert ( + 'href="/workspaces/{}/members/new"'.format(workspace.id).encode() + in response.data + ) + + +def test_user_without_permission_has_no_add_member_link(client, user_session): + user = UserFactory.create() + workspace = WorkspaceFactory.create() + Workspaces._create_workspace_role(user, workspace, "developer") + user_session(user) + response = client.get("/workspaces/{}/members".format(workspace.id)) + assert ( + 'href="/workspaces/{}/members/new"'.format(workspace.id).encode() + not in response.data + )