diff --git a/data/model.py b/data/model.py index 7dbf578a5..94c71e67e 100644 --- a/data/model.py +++ b/data/model.py @@ -348,6 +348,12 @@ def get_organization_team(orgname, teamname): return result[0] +def get_organization_members_with_teams(organization): + joined = TeamMember.select().annotate(Team).annotate(User) + query = joined.where(Team.organization == organization) + return query + + def get_organization_team_members(teamid): joined = User.select().join(TeamMember).join(Team) query = joined.where(Team.id == teamid) diff --git a/endpoints/api.py b/endpoints/api.py index 6fdf887b1..86df85779 100644 --- a/endpoints/api.py +++ b/endpoints/api.py @@ -300,6 +300,31 @@ def get_organization(orgname): abort(403) +@app.route('/api/organization//members', methods=['GET']) +@api_login_required +def get_organization_members(orgname): + permission = AdministerOrganizationPermission(orgname) + if permission.can(): + try: + org = model.get_organization(orgname) + except model.InvalidOrganizationException: + abort(404) + + # Loop to create the members dictionary. Note that the members collection + # will return an entry for *every team* a member is on, so we will have + # duplicate keys (which is why we pre-build the dictionary). + members_dict = {} + members = model.get_organization_members_with_teams(org) + for member in members: + if not member.user.username in members_dict: + members_dict[member.user.username] = {'username': member.user.username, 'teams': []} + + members_dict[member.user.username]['teams'].append(member.team.name) + + return jsonify({'members': members_dict}) + + abort(403) + @app.route('/api/organization//private', methods=['GET']) @api_login_required def get_organization_private_allowed(orgname): diff --git a/static/css/quay.css b/static/css/quay.css index 0e100e7f4..0fead2172 100644 --- a/static/css/quay.css +++ b/static/css/quay.css @@ -1358,6 +1358,49 @@ p.editable:hover i { stroke-width: 1.5px; } +#repository-usage-chart { + display: inline-block; + vertical-align: middle; + width: 200px; + height: 200px; +} + +#repository-usage-chart .count-text { + font-size: 22px; +} + +#repository-usage-chart.limit-at path.arc-0 { + fill: #c09853; +} + +#repository-usage-chart.limit-over path.arc-0 { + fill: #b94a48; +} + +#repository-usage-chart.limit-near path.arc-0 { + fill: #468847; +} + +#repository-usage-chart.limit-over path.arc-1 { + fill: #fcf8e3; +} + +#repository-usage-chart.limit-at path.arc-1 { + fill: #f2dede; +} + +#repository-usage-chart.limit-near path.arc-1 { + fill: #dff0d8; +} + +.plan-manager-element .usage-caption { + display: inline-block; + color: #aaa; + font-size: 26px; + margin-left: 10px; +} + + /* Overrides for the markdown editor. */ .wmd-panel .btn-toolbar { @@ -1471,7 +1514,6 @@ p.editable:hover i { 100% { background-color: rgba(92, 184, 92, 0.36); } } - .org-view .team-title { font-size: 20px; text-transform: capitalize; @@ -1490,22 +1532,49 @@ p.editable:hover i { padding: 6px; } -.org-admin .plans-table thead td { +.org-admin .team-link { + display: inline-block; + text-transform: capitalize; + margin-right: 20px; +} + +.org-admin #members table td { + font-size: 16px; +} + +.org-admin #members table i { + margin-right: 4px; +} + +.org-admin #members .side-controls { + float: right; +} + +.org-admin #members .result-count { + display: inline-block; + margin-right: 10px; +} + +.org-admin #members .filter-input { + display: inline-block; +} + +.plan-manager-element .plans-table thead td { color: #aaa; font-weight: bold; } -.org-admin .plans-table td { +.plan-manager-element .plans-table td { padding: 10px; font-size: 16px; vertical-align: middle; } -.org-admin .plans-table td.controls { +.plan-manager-element .plans-table td.controls { text-align: right; } -.org-admin .plans-table .plan-price { +.plan-manager-element .plans-table .plan-price { font-size: 16px; margin-bottom: 0px; } diff --git a/static/directives/namespace-selector.html b/static/directives/namespace-selector.html index de208f7c7..bc8abc9a2 100644 --- a/static/directives/namespace-selector.html +++ b/static/directives/namespace-selector.html @@ -1,5 +1,8 @@ - {{user.username}} + + + {{user.username}} +
-

Your Repositories

-
-
+ +

Your Repositories

+

Repositories

+ + -
+
-

You don't have any repositories yet!

+

You don't have any repositories yet!

+

This organization does not have any repositories yet!

Click here to learn how to create a repository
diff --git a/static/partials/user-admin.html b/static/partials/user-admin.html index 8408863fb..f3371e001 100644 --- a/static/partials/user-admin.html +++ b/static/partials/user-admin.html @@ -1,80 +1,62 @@ -
-
- -
-
-
-
{{ errorMessage }}
+
+ +
+ +
+ No matching user found +
+ +
+
+
+ + + {{ user.username }} +
+
Your account does not currently have a password. You will need to create a password before you will be able to push or pull repositories.
-
-
-
-
- {{ plan.title }} - - - Subscribed - -
-
-
${{ plan.price / 100 }}
-
{{ plan.privateRepos }} Private Repositories
-
-
- -
-
- - - -
-
-
-
-
-
-
-
-
-
- Plan Usage -
-
-
- {{ subscription.usedPrivateRepos }} of {{ subscribedPlan.privateRepos }} private repositories used -
-
-
-
-
-
-
-
-
+
-
- + + -
-
-
- Change Password + + +
+
+ +
+
-
-
+ + +
+
+ +
+ + - - + + Password changed successfully
+