From 425fba99da583568628a09b733d92638a6a53aa1 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Sun, 10 Feb 2019 14:36:33 -0500 Subject: [PATCH 1/5] Fix flashed message after creating portfolio member --- atst/routes/portfolios/members.py | 7 +------ tests/routes/portfolios/test_members.py | 1 + 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/atst/routes/portfolios/members.py b/atst/routes/portfolios/members.py index e549cdf2..182fe74f 100644 --- a/atst/routes/portfolios/members.py +++ b/atst/routes/portfolios/members.py @@ -26,10 +26,6 @@ from atst.utils.flash import formatted_flash as flash @portfolios_bp.route("/portfolios//members") def portfolio_members(portfolio_id): portfolio = Portfolios.get_with_members(g.current_user, portfolio_id) - new_member_name = http_request.args.get("newMemberName") - new_member = next( - filter(lambda m: m.user_name == new_member_name, portfolio.members), None - ) members_list = [ { "name": k.user_name, @@ -50,7 +46,6 @@ def portfolio_members(portfolio_id): role_choices=PORTFOLIO_ROLE_DEFINITIONS, status_choices=MEMBER_STATUS_CHOICES, members=members_list, - new_member=new_member, ) @@ -76,7 +71,7 @@ def create_member(portfolio_id): ) invite_service.invite() - flash("new_portfolio_member", new_member=new_member, portfolio=portfolio) + flash("new_portfolio_member", new_member=member, portfolio=portfolio) return redirect( url_for("portfolios.portfolio_members", portfolio_id=portfolio.id) diff --git a/tests/routes/portfolios/test_members.py b/tests/routes/portfolios/test_members.py index c8d97b61..58078f35 100644 --- a/tests/routes/portfolios/test_members.py +++ b/tests/routes/portfolios/test_members.py @@ -92,6 +92,7 @@ def test_create_member(client, user_session): ) assert response.status_code == 200 + assert user.full_name in response.data.decode() assert user.has_portfolios assert user.invitations assert len(queue.get_queue()) == queue_length + 1 From 5846207269a7c552e41697ed3370cb2d82659415 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Sun, 10 Feb 2019 15:02:17 -0500 Subject: [PATCH 2/5] Add page for viewing application team --- atst/routes/portfolios/members.py | 44 +++++++--- js/components/members_list.js | 10 ++- templates/portfolios/applications/index.html | 2 +- .../portfolios/applications/members.html | 81 +++++++++++++++++++ translations.yaml | 3 + 5 files changed, 124 insertions(+), 16 deletions(-) create mode 100644 templates/portfolios/applications/members.html diff --git a/atst/routes/portfolios/members.py b/atst/routes/portfolios/members.py index 182fe74f..b61510e6 100644 --- a/atst/routes/portfolios/members.py +++ b/atst/routes/portfolios/members.py @@ -23,22 +23,25 @@ from atst.models.permissions import Permissions from atst.utils.flash import formatted_flash as flash +def serialize_portfolio_role(portfolio_role): + return { + "name": portfolio_role.user_name, + "status": portfolio_role.display_status, + "id": portfolio_role.user_id, + "role": portfolio_role.role_displayname, + "num_env": portfolio_role.num_environment_roles, + "edit_link": url_for( + "portfolios.view_member", + portfolio_id=portfolio_role.portfolio_id, + member_id=portfolio_role.user_id, + ), + } + + @portfolios_bp.route("/portfolios//members") def portfolio_members(portfolio_id): portfolio = Portfolios.get_with_members(g.current_user, portfolio_id) - members_list = [ - { - "name": k.user_name, - "status": k.display_status, - "id": k.user_id, - "role": k.role_displayname, - "num_env": k.num_environment_roles, - "edit_link": url_for( - "portfolios.view_member", portfolio_id=portfolio.id, member_id=k.user_id - ), - } - for k in portfolio.members - ] + members_list = [serialize_portfolio_role(k) for k in portfolio.members] return render_template( "portfolios/members/index.html", @@ -49,6 +52,21 @@ def portfolio_members(portfolio_id): ) +@portfolios_bp.route("/portfolios//applications//members") +def application_members(portfolio_id, application_id): + portfolio = Portfolios.get_with_members(g.current_user, portfolio_id) + application = Applications.get(g.current_user, portfolio, application_id) + # TODO: this should show only members that have env roles in this application + members_list = [serialize_portfolio_role(k) for k in portfolio.members] + + return render_template( + "portfolios/applications/members.html", + portfolio=portfolio, + application=application, + members=members_list, + ) + + @portfolios_bp.route("/portfolios//members/new") def new_member(portfolio_id): portfolio = Portfolios.get(g.current_user, portfolio_id) diff --git a/js/components/members_list.js b/js/components/members_list.js index a48d2eb5..e8d7b37e 100644 --- a/js/components/members_list.js +++ b/js/components/members_list.js @@ -61,8 +61,14 @@ export default { props: { members: Array, - role_choices: Array, - status_choices: Array, + role_choices: { + type: Array, + default: () => [], + }, + status_choices: { + type: Array, + default: () => [], + }, }, data: function() { diff --git a/templates/portfolios/applications/index.html b/templates/portfolios/applications/index.html index e89ff12c..5f5c324c 100644 --- a/templates/portfolios/applications/index.html +++ b/templates/portfolios/applications/index.html @@ -47,7 +47,7 @@
{% endif %} - + {{ "portfolios.applications.team_text" | translate }} {{ application.num_users }} diff --git a/templates/portfolios/applications/members.html b/templates/portfolios/applications/members.html new file mode 100644 index 00000000..7b5d56c1 --- /dev/null +++ b/templates/portfolios/applications/members.html @@ -0,0 +1,81 @@ +{% extends "portfolios/applications/base.html" %} + +{% from "components/empty_state.html" import EmptyState %} +{% from "components/icon.html" import Icon %} + +{% set secondary_breadcrumb = 'portfolios.applications.team_management.title' | translate({ "application_name": application.name }) %} + +{% block application_content %} + +
{{ 'portfolios.applications.team_management.subheading' | translate }}
+ +{% if not portfolio.members %} + + {% set user_can_invite = user_can(permissions.ASSIGN_AND_UNASSIGN_ATAT_ROLE) %} + + {{ EmptyState( + 'There are currently no members in this Portfolio.', + 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 Cloud portfolio administrator to invite new members.', + icon='avatar' + ) }} + + +{% else %} + +{% include "fragments/flash.html" %} + + +
+ + + + + + + + + + + + + + + + +
+ !{ col.displayName } + + {{ Icon("caret_down") }} + + + {{ Icon("caret_up") }} + +
+ + + + + No Environment Access +
+
+ {{ EmptyState( + 'No members found.', + action_label=None, + action_href=None, + sub_message='Please try a different search.', + icon=None + ) }} +
+
+
+ +{% endif %} + + +{% endblock %} + diff --git a/translations.yaml b/translations.yaml index 256d78fd..f9a00d8c 100644 --- a/translations.yaml +++ b/translations.yaml @@ -493,6 +493,9 @@ portfolios: environments_description: Each environment created within an application is logically separated from one another for easier management and security. update_button_text: Save Changes create_button_text: Create Application + team_management: + title: '{application_name} Team Management' + subheading: Team Management testing: example_string: Hello World example_with_variables: 'Hello, {name}!' From 257184fab5f025009450b7ff8f7d9e748a2a8268 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Sun, 10 Feb 2019 15:37:29 -0500 Subject: [PATCH 3/5] Update member list table styles --- js/components/members_list.js | 2 +- styles/components/_portfolio_layout.scss | 30 +++++++++++++++++++ styles/elements/_tables.scss | 4 +++ .../portfolios/applications/members.html | 13 ++++++-- templates/portfolios/members/index.html | 11 ++++++- 5 files changed, 56 insertions(+), 4 deletions(-) diff --git a/js/components/members_list.js b/js/components/members_list.js index e8d7b37e..7c862a31 100644 --- a/js/components/members_list.js +++ b/js/components/members_list.js @@ -93,7 +93,7 @@ export default { displayName: 'Environments', attr: 'num_env', sortFunc: numericSort, - class: 'table-cell--align-right', + class: 'table-cell--align-center', }, { displayName: 'Status', diff --git a/styles/components/_portfolio_layout.scss b/styles/components/_portfolio_layout.scss index bad7fbca..6157fef7 100644 --- a/styles/components/_portfolio_layout.scss +++ b/styles/components/_portfolio_layout.scss @@ -103,6 +103,36 @@ .portfolio-content { margin: 6 * $gap $gap 0 $gap; + .member-list { + .panel { + padding: $gap / 2 0; + box-shadow: 0 6px 18px 0 rgba(144,164,183,0.3); + border-top: none; + border-bottom: none; + } + + table { + box-shadow: 0 6px 18px 0 rgba(144,164,183,0.3); + thead { + th:first-child { + padding-left: 3 * $gap; + } + } + + th { + background-color: $color-gray-lightest; + padding: $gap 2 * $gap; + border-top: none; + border-bottom: none; + color: $color-gray; + } + + td { + border-bottom: 1px solid $color-gray-lightest; + } + } + } + .application-content { .subheading { @include subheading; diff --git a/styles/elements/_tables.scss b/styles/elements/_tables.scss index 448e378c..93e9d2a2 100644 --- a/styles/elements/_tables.scss +++ b/styles/elements/_tables.scss @@ -17,6 +17,10 @@ text-align: right; } + &.table-cell--align-center { + text-align: center; + } + &.table-cell--shrink { width: 1%; } diff --git a/templates/portfolios/applications/members.html b/templates/portfolios/applications/members.html index 7b5d56c1..6b05e799 100644 --- a/templates/portfolios/applications/members.html +++ b/templates/portfolios/applications/members.html @@ -29,8 +29,9 @@ -
+
@@ -51,7 +52,7 @@ - + + +
+ @@ -60,6 +61,14 @@
+ + Add A New Member + {{ Icon('plus') }} + +
diff --git a/templates/portfolios/members/index.html b/templates/portfolios/members/index.html index b44ae8a4..c04c408e 100644 --- a/templates/portfolios/members/index.html +++ b/templates/portfolios/members/index.html @@ -25,6 +25,7 @@ @@ -61,7 +62,7 @@
-
+
@@ -91,6 +92,14 @@ + + +
+ + Add A New Member + {{ Icon('plus') }} + +
From 5f49c42c4e8e2c1d53e7d2cf6f45e92d88c2fc02 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Sun, 10 Feb 2019 15:40:52 -0500 Subject: [PATCH 4/5] Tweak some styles on portfolio member management --- styles/components/_search_bar.scss | 3 +++ templates/portfolios/members/index.html | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/styles/components/_search_bar.scss b/styles/components/_search_bar.scss index 28b536c5..8c4de002 100644 --- a/styles/components/_search_bar.scss +++ b/styles/components/_search_bar.scss @@ -6,6 +6,9 @@ padding: $gap; flex-wrap: wrap; + border-top: none; + border-bottom: none; + @media (min-width:1000px) { flex-wrap: nowrap; } diff --git a/templates/portfolios/members/index.html b/templates/portfolios/members/index.html index c04c408e..028045d5 100644 --- a/templates/portfolios/members/index.html +++ b/templates/portfolios/members/index.html @@ -3,6 +3,8 @@ {% from "components/empty_state.html" import EmptyState %} {% from "components/icon.html" import Icon %} +{% set secondary_breadcrumb = 'Portfolio Team Management' %} + {% block portfolio_content %} {% if not portfolio.members %} @@ -83,7 +85,7 @@ - + From 90c907a75b63cf58ef36f5b5e780c3236a99329e Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Sun, 10 Feb 2019 15:49:08 -0500 Subject: [PATCH 5/5] Hide link to team page if user cannot view members --- templates/portfolios/applications/index.html | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/templates/portfolios/applications/index.html b/templates/portfolios/applications/index.html index 5f5c324c..97e09fee 100644 --- a/templates/portfolios/applications/index.html +++ b/templates/portfolios/applications/index.html @@ -47,10 +47,12 @@
{% endif %} - - {{ "portfolios.applications.team_text" | translate }} - {{ application.num_users }} - + {% if user_can(permissions.VIEW_PORTFOLIO_MEMBERS) %} + + {{ "portfolios.applications.team_text" | translate }} + {{ application.num_users }} + + {% endif %}