Get the new context-sensitive new menu working
This commit is contained in:
parent
40a6892a49
commit
d09f2f6e22
13 changed files with 461 additions and 193 deletions
|
@ -679,34 +679,27 @@ def get_user_or_org_by_customer_id(customer_id):
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_matching_user_entities(entity_prefix, user):
|
def get_matching_entities(entity_prefix):
|
||||||
matching_user_orgs = ((User.username ** (entity_prefix + '%')) & (User.robot == False))
|
matching_user_orgs = ((User.username ** (entity_prefix + '%')) & (User.robot == False))
|
||||||
|
matching_robots = ((User.username ** ('%+%' + entity_prefix + '%')) & (User.robot == True))
|
||||||
if user is not None:
|
|
||||||
matching_robots = ((User.username ** (user.username + '+%' + entity_prefix + '%')) &
|
|
||||||
(User.robot == True))
|
|
||||||
else:
|
|
||||||
matching_robots = False
|
|
||||||
|
|
||||||
query = (User.select()
|
query = (User.select()
|
||||||
.where(matching_user_orgs | matching_robots)
|
.where(matching_user_orgs | matching_robots))
|
||||||
.limit(10))
|
|
||||||
|
|
||||||
return query
|
return query
|
||||||
|
|
||||||
def get_matching_user_teams(team_prefix, user):
|
def get_matching_user_teams(team_prefix, user, limit=10):
|
||||||
query = (Team.select()
|
query = (Team.select()
|
||||||
.join(User)
|
.join(User)
|
||||||
.switch(Team)
|
.switch(Team)
|
||||||
.join(TeamMember)
|
.join(TeamMember)
|
||||||
.where(TeamMember.user == user, Team.name ** (team_prefix + '%'))
|
.where(TeamMember.user == user, Team.name ** (team_prefix + '%'))
|
||||||
.distinct(Team.id)
|
.distinct(Team.id)
|
||||||
.limit(10))
|
.limit(limit))
|
||||||
|
|
||||||
return query
|
return query
|
||||||
|
|
||||||
|
def get_matching_admined_teams(team_prefix, user, limit=10):
|
||||||
def get_matching_admined_teams(team_prefix, user):
|
|
||||||
admined_orgs = (get_user_organizations(user.username)
|
admined_orgs = (get_user_organizations(user.username)
|
||||||
.switch(Team)
|
.switch(Team)
|
||||||
.join(TeamRole)
|
.join(TeamRole)
|
||||||
|
@ -718,7 +711,7 @@ def get_matching_admined_teams(team_prefix, user):
|
||||||
.join(TeamMember)
|
.join(TeamMember)
|
||||||
.where(Team.name ** (team_prefix + '%'), Team.organization << (admined_orgs))
|
.where(Team.name ** (team_prefix + '%'), Team.organization << (admined_orgs))
|
||||||
.distinct(Team.id)
|
.distinct(Team.id)
|
||||||
.limit(10))
|
.limit(limit))
|
||||||
|
|
||||||
return query
|
return query
|
||||||
|
|
||||||
|
@ -968,7 +961,7 @@ def _get_public_repo_visibility():
|
||||||
return _public_repo_visibility_cache
|
return _public_repo_visibility_cache
|
||||||
|
|
||||||
|
|
||||||
def get_matching_repositories(repo_term, username=None):
|
def get_matching_repositories(repo_term, username=None, limit=10):
|
||||||
namespace_term = repo_term
|
namespace_term = repo_term
|
||||||
name_term = repo_term
|
name_term = repo_term
|
||||||
|
|
||||||
|
@ -986,7 +979,7 @@ def get_matching_repositories(repo_term, username=None):
|
||||||
search_clauses = (Repository.name ** ('%' + name_term + '%') &
|
search_clauses = (Repository.name ** ('%' + name_term + '%') &
|
||||||
Namespace.username ** ('%' + namespace_term + '%'))
|
Namespace.username ** ('%' + namespace_term + '%'))
|
||||||
|
|
||||||
return visible.where(search_clauses).limit(10)
|
return visible.where(search_clauses).limit(limit)
|
||||||
|
|
||||||
def get_repository_pull_counts(repositories):
|
def get_repository_pull_counts(repositories):
|
||||||
repo_pull = LogEntryKind.get(name = 'pull_repo')
|
repo_pull = LogEntryKind.get(name = 'pull_repo')
|
||||||
|
|
|
@ -9,6 +9,7 @@ from auth import scopes
|
||||||
from app import avatar, get_app_url
|
from app import avatar, get_app_url
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
from stringscore import liquidmetal
|
from stringscore import liquidmetal
|
||||||
|
from util.names import parse_robot_username
|
||||||
|
|
||||||
import math
|
import math
|
||||||
|
|
||||||
|
@ -130,8 +131,13 @@ class ConductSearch(ApiResource):
|
||||||
avatar_data = avatar.get_data_for_org(entity)
|
avatar_data = avatar.get_data_for_org(entity)
|
||||||
href = '/organization/' + entity.username
|
href = '/organization/' + entity.username
|
||||||
elif entity.robot:
|
elif entity.robot:
|
||||||
|
parts = parse_robot_username(entity.username)
|
||||||
|
if parts[0] == username:
|
||||||
|
href = '/user/' + username + '?tab=robots&showRobot=' + entity.username
|
||||||
|
else:
|
||||||
|
href = '/organization/' + parts[0] + '?tab=robots&showRobot=' + entity.username
|
||||||
|
|
||||||
kind = 'robot'
|
kind = 'robot'
|
||||||
href = '/user?tab=robots'
|
|
||||||
avatar_data = None
|
avatar_data = None
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -148,7 +154,7 @@ class ConductSearch(ApiResource):
|
||||||
# Find the matching teams where the user is a member.
|
# Find the matching teams where the user is a member.
|
||||||
encountered_teams = set()
|
encountered_teams = set()
|
||||||
|
|
||||||
matching_teams = model.get_matching_user_teams(query, get_authenticated_user())
|
matching_teams = model.get_matching_user_teams(query, get_authenticated_user(), limit=5)
|
||||||
for team in matching_teams:
|
for team in matching_teams:
|
||||||
if team.id in encountered_teams:
|
if team.id in encountered_teams:
|
||||||
continue
|
continue
|
||||||
|
@ -165,7 +171,7 @@ class ConductSearch(ApiResource):
|
||||||
})
|
})
|
||||||
|
|
||||||
# Find matching teams in orgs admined by the user.
|
# Find matching teams in orgs admined by the user.
|
||||||
matching_teams = model.get_matching_admined_teams(query, get_authenticated_user())
|
matching_teams = model.get_matching_admined_teams(query, get_authenticated_user(), limit=5)
|
||||||
for team in matching_teams:
|
for team in matching_teams:
|
||||||
if team.id in encountered_teams:
|
if team.id in encountered_teams:
|
||||||
continue
|
continue
|
||||||
|
@ -183,7 +189,7 @@ class ConductSearch(ApiResource):
|
||||||
|
|
||||||
|
|
||||||
# Find the matching repositories.
|
# Find the matching repositories.
|
||||||
matching_repos = model.get_matching_repositories(query, username)
|
matching_repos = model.get_matching_repositories(query, username, limit=5)
|
||||||
matching_repo_counts = {t[0]: t[1] for t in model.get_repository_pull_counts(matching_repos)}
|
matching_repo_counts = {t[0]: t[1] for t in model.get_repository_pull_counts(matching_repos)}
|
||||||
|
|
||||||
for repo in matching_repos:
|
for repo in matching_repos:
|
||||||
|
@ -197,10 +203,23 @@ class ConductSearch(ApiResource):
|
||||||
'href': '/repository/' + repo.namespace_user.username + '/' + repo.name
|
'href': '/repository/' + repo.namespace_user.username + '/' + repo.name
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
# Find the matching users, robots and organizations.
|
# Find the matching users, robots and organizations.
|
||||||
matching_entities = model.get_matching_user_entities(query, get_authenticated_user())
|
matching_entities = model.get_matching_entities(query)
|
||||||
|
entity_count = 0
|
||||||
for entity in matching_entities:
|
for entity in matching_entities:
|
||||||
|
# If the entity is a robot, filter it to only match those that are under the current
|
||||||
|
# user or can be administered by the organization.
|
||||||
|
if entity.robot:
|
||||||
|
orgname = parse_robot_username(entity.username)[0]
|
||||||
|
if not AdministerOrganizationPermission(orgname).can() and not orgname == username:
|
||||||
|
continue
|
||||||
|
|
||||||
results.append(entity_view(entity))
|
results.append(entity_view(entity))
|
||||||
|
entity_count = entity_count + 1
|
||||||
|
if entity_count >= 5:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
for result in results:
|
for result in results:
|
||||||
result['score'] = result['score'] * liquidmetal.score(result['name'], query)
|
result['score'] = result['score'] * liquidmetal.score(result['name'], query)
|
||||||
|
|
|
@ -27,7 +27,7 @@ nav.navbar-default .navbar-nav>li>a.active {
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-bar-element .header-bar-content {
|
.header-bar-element .header-bar-content {
|
||||||
z-index: 4;
|
z-index: 5;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
left: 0px;
|
left: 0px;
|
||||||
|
@ -40,7 +40,7 @@ nav.navbar-default .navbar-nav>li>a.active {
|
||||||
left: 0px;
|
left: 0px;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
top: -50px;
|
top: -50px;
|
||||||
z-index: 3;
|
z-index: 4;
|
||||||
height: 83px;
|
height: 83px;
|
||||||
transition: top 0.7s cubic-bezier(.23,.88,.72,.98);
|
transition: top 0.7s cubic-bezier(.23,.88,.72,.98);
|
||||||
background: white;
|
background: white;
|
||||||
|
@ -88,7 +88,7 @@ nav.navbar-default .navbar-nav>li>a.active {
|
||||||
left: 0px;
|
left: 0px;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
top: -130px;
|
top: -130px;
|
||||||
z-index: 2;
|
z-index: 3;
|
||||||
transition: top 0.7s cubic-bezier(.23,.88,.72,.98), height 0.5s ease-in-out;
|
transition: top 0.7s cubic-bezier(.23,.88,.72,.98), height 0.5s ease-in-out;
|
||||||
|
|
||||||
background: white;
|
background: white;
|
||||||
|
@ -173,4 +173,51 @@ nav.navbar-default .navbar-nav>li>a.active {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-left: 6px;
|
margin-left: 6px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header-bar-element .avatar {
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-tools {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-tools .user-tool {
|
||||||
|
font-size: 24px;
|
||||||
|
margin-top: 14px;
|
||||||
|
color: #428bca;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-tools.with-menu {
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-tools .caret {
|
||||||
|
position: absolute;
|
||||||
|
top: 3px;
|
||||||
|
left: 23px
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-tools .notifications-bubble {
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
left: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-tools i.user-tool:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-tools .new-menu {
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-bar-element .context-dropdown i.fa {
|
||||||
|
width: 16px;
|
||||||
|
text-align: center;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,10 @@
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.team-view .team-view-header button i.fa {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.team-view .team-view-header > h3 {
|
.team-view .team-view-header > h3 {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -742,17 +742,6 @@ i.toggle-icon:hover {
|
||||||
100% { transform: scale(1); }
|
100% { transform: scale(1); }
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-tools .user-tool {
|
|
||||||
font-size: 24px;
|
|
||||||
margin-top: 14px;
|
|
||||||
color: #428bca;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-tools i.user-tool:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-box a {
|
.status-box a {
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
color: black;
|
color: black;
|
||||||
|
|
|
@ -1,141 +1,3 @@
|
||||||
<div class="header-bar-element">
|
<span class="header-bar-parent">
|
||||||
<div class="header-bar-content" ng-class="searchVisible ? 'search-visible' : ''">
|
<span quay-include="{'Config.isNewLayout()': 'directives/new-header-bar.html', '!Config.isNewLayout()': 'directives/old-header-bar.html'}"></span>
|
||||||
<!-- Quay -->
|
</span>
|
||||||
<div class="navbar-header">
|
|
||||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse" style="padding: 0px; padding-left: 4px; padding-right: 4px;">
|
|
||||||
≡
|
|
||||||
</button>
|
|
||||||
<a class="navbar-brand" href="/" target="{{ appLinkTarget() }}">
|
|
||||||
<span id="quay-logo" ng-style="{'background-image': 'url(' + getEnterpriseLogo() + ')'}"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Collapsable stuff -->
|
|
||||||
<div class="collapse navbar-collapse navbar-ex1-collapse">
|
|
||||||
<ul class="nav navbar-nav navbar-links">
|
|
||||||
<li><a ng-href="/tour/" target="{{ appLinkTarget() }}" quay-section="tour">Tour</a></li>
|
|
||||||
<li><a ng-href="/repository/" target="{{ appLinkTarget() }}" quay-section="repository">Repositories</a></li>
|
|
||||||
<li><a href="http://docs.quay.io/" target="_blank">Docs</a></li>
|
|
||||||
<li><a ng-href="/tutorial/" target="{{ appLinkTarget() }}" quay-section="tutorial">Tutorial</a></li>
|
|
||||||
<li quay-require="['BILLING']"><a ng-href="/plans/" target="{{ appLinkTarget() }}" quay-section="plans">Pricing</a></li>
|
|
||||||
<li><a ng-href="{{ user.organizations.length ? '/organizations/' : '/tour/organizations/' }}" target="{{ appLinkTarget() }}" quay-section="organization">Organizations</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<!-- Phone -->
|
|
||||||
<ul class="nav navbar-nav navbar-right visible-xs" ng-switch on="user.anonymous">
|
|
||||||
<li ng-switch-when="false">
|
|
||||||
<a href="/user/" class="user-view" target="{{ appLinkTarget() }}">
|
|
||||||
<span class="avatar" size="32" data="user.avatar"></span>
|
|
||||||
{{ user.username }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li ng-switch-default>
|
|
||||||
<a class="user-view" href="/signin/" target="{{ appLinkTarget() }}">Sign in</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<!-- Normal -->
|
|
||||||
<ul class="nav navbar-nav navbar-right hidden-xs" ng-switch on="user.anonymous">
|
|
||||||
<li>
|
|
||||||
<span class="navbar-left user-tools">
|
|
||||||
<i class="fa fa-search fa-lg user-tool" ng-click="toggleSearch()"></i>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<span class="navbar-left user-tools" ng-show="!user.anonymous">
|
|
||||||
<a href="/new/"><i class="fa fa-plus user-tool" bs-tooltip="tooltip.title" data-placement="bottom" data-title="Create new repository" data-container="body"></i></a>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="dropdown" ng-switch-when="false">
|
|
||||||
<a href="javascript:void(0)" class="dropdown-toggle user-dropdown user-view" data-toggle="dropdown">
|
|
||||||
<span class="avatar" size="32" data="user.avatar"></span>
|
|
||||||
{{ user.username }}
|
|
||||||
<span class="notifications-bubble"></span>
|
|
||||||
<b class="caret"></b>
|
|
||||||
</a>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<li>
|
|
||||||
<a href="/user/{{ user.username }}?tab=settings" target="{{ appLinkTarget() }}" ng-if="isNewLayout">
|
|
||||||
Account Settings
|
|
||||||
</a>
|
|
||||||
<a href="/user/" target="{{ appLinkTarget() }}" ng-if="!isNewLayout">
|
|
||||||
Account Settings
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li ng-if="notificationService.notifications.length">
|
|
||||||
<a href="javascript:void(0)" data-template="/static/directives/notification-bar.html"
|
|
||||||
data-animation="am-slide-right" bs-aside="aside" data-container="body">
|
|
||||||
Notifications
|
|
||||||
<span class="notifications-bubble"></span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li><a ng-href="/organizations/" target="{{ appLinkTarget() }}">Organizations</a></li>
|
|
||||||
<li ng-if="user.super_user"><a href="/superuser/"><strong>Super User Admin Panel</strong></a></li>
|
|
||||||
<li><a href="javascript:void(0)" ng-click="signout()">Sign out</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li ng-switch-default>
|
|
||||||
<a class="user-view" href="/signin/" target="{{ appLinkTarget() }}">Sign in</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div><!-- /.navbar-collapse -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="search-box" ng-class="getSearchBoxClasses(searchVisible, searchResultState)">
|
|
||||||
<div class="search-label">Search For</div>
|
|
||||||
<div class="search-box-wrapper">
|
|
||||||
<input id="search-box-input" type="text" placeholder="(Enter Search Terms)"
|
|
||||||
ng-model-options="{'debounce': 250}" ng-model="currentSearchQuery"
|
|
||||||
ng-keydown="handleSearchKeyDown($event)">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="search-results"
|
|
||||||
ng-class="searchVisible && searchResultState ? searchResultState.state : ''"
|
|
||||||
ng-class="{'height': (searchResultState.results.length * 40) + 28}">
|
|
||||||
<div class="cor-loader" ng-if="searchResultState.state == 'loading'"></div>
|
|
||||||
<div ng-if="searchResultState.state == 'no-results'">No matching results found</div>
|
|
||||||
<ul ng-if="searchResultState.state == 'results'">
|
|
||||||
<li ng-repeat="result in searchResultState.results" ng-mouseover="setCurrentResult($index)"
|
|
||||||
ng-class="searchResultState.current == $index ? 'current' : ''"
|
|
||||||
ng-click="showResult(result)">
|
|
||||||
<span class="kind">{{ result.kind }}</span>
|
|
||||||
<span class="score">{{ result.score }}</span>
|
|
||||||
<span ng-switch on="result.kind">
|
|
||||||
<!-- Team -->
|
|
||||||
<span ng-switch-when="team">
|
|
||||||
<strong>
|
|
||||||
<span class="avatar" data="result.avatar" size="16"></span>
|
|
||||||
<span class="result-name">{{ result.name }}</span>
|
|
||||||
</strong>
|
|
||||||
<span class="clarification">
|
|
||||||
under organization
|
|
||||||
<span class="avatar" data="result.organization.avatar" size="16"></span>
|
|
||||||
<span class="result-name">{{ result.organization.name }}</span>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
<span ng-switch-when="user">
|
|
||||||
<span class="avatar" data="result.avatar" size="16"></span>
|
|
||||||
<span class="result-name">{{ result.name }}</span>
|
|
||||||
</span>
|
|
||||||
<span ng-switch-when="organization">
|
|
||||||
<span class="avatar" data="result.avatar" size="16"></span>
|
|
||||||
<span class="result-name">{{ result.name }}</span>
|
|
||||||
</span>
|
|
||||||
<span href="/user/{{ result.name }}" ng-switch-when="robot">
|
|
||||||
<i class="fa fa-wrench"></i>
|
|
||||||
<span class="result-name">{{ result.name }}</span>
|
|
||||||
</span>
|
|
||||||
<span ng-switch-when="repository">
|
|
||||||
<span class="avatar" data="result.namespace.avatar" size="16"></span>
|
|
||||||
<span class="result-name">{{ result.namespace.name }}/{{ result.name }}</span>
|
|
||||||
<div class="description" ng-if="result.description">
|
|
||||||
{{ result.description }}
|
|
||||||
</div>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
189
static/directives/new-header-bar.html
Normal file
189
static/directives/new-header-bar.html
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
<div class="header-bar-element">
|
||||||
|
<div class="header-bar-content" ng-class="searchVisible ? 'search-visible' : ''">
|
||||||
|
<!-- Quay -->
|
||||||
|
<div class="navbar-header">
|
||||||
|
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse" style="padding: 0px; padding-left: 4px; padding-right: 4px;">
|
||||||
|
≡
|
||||||
|
</button>
|
||||||
|
<a class="navbar-brand" href="/" target="{{ appLinkTarget() }}">
|
||||||
|
<span id="quay-logo" ng-style="{'background-image': 'url(' + getEnterpriseLogo() + ')'}"></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Collapsable stuff -->
|
||||||
|
<div class="collapse navbar-collapse navbar-ex1-collapse">
|
||||||
|
<ul class="nav navbar-nav navbar-links">
|
||||||
|
<li><a ng-href="/tour/" target="{{ appLinkTarget() }}" quay-section="tour">Tour</a></li>
|
||||||
|
<li><a ng-href="/repository/" target="{{ appLinkTarget() }}" quay-section="repository">Repositories</a></li>
|
||||||
|
<li><a href="http://docs.quay.io/" target="_blank">Docs</a></li>
|
||||||
|
<li><a ng-href="/tutorial/" target="{{ appLinkTarget() }}" quay-section="tutorial">Tutorial</a></li>
|
||||||
|
<li quay-require="['BILLING']"><a ng-href="/plans/" target="{{ appLinkTarget() }}" quay-section="plans">Pricing</a></li>
|
||||||
|
<li><a ng-href="{{ user.organizations.length ? '/organizations/' : '/tour/organizations/' }}" target="{{ appLinkTarget() }}" quay-section="organization">Organizations</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!-- Phone -->
|
||||||
|
<ul class="nav navbar-nav navbar-right visible-xs" ng-switch on="user.anonymous">
|
||||||
|
<li ng-switch-when="false">
|
||||||
|
<a href="/user/" class="user-view" target="{{ appLinkTarget() }}">
|
||||||
|
<span class="avatar" size="32" data="user.avatar"></span>
|
||||||
|
{{ user.username }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li ng-switch-default>
|
||||||
|
<a class="user-view" href="/signin/" target="{{ appLinkTarget() }}">Sign in</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!-- Normal -->
|
||||||
|
<ul class="nav navbar-nav navbar-right hidden-xs" ng-switch on="user.anonymous">
|
||||||
|
<li>
|
||||||
|
<span class="navbar-left user-tools">
|
||||||
|
<i class="fa fa-search fa-lg user-tool" ng-click="toggleSearch()"
|
||||||
|
data-placement="bottom" data-title="Search" bs-tooltip></i>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span class="navbar-left user-tools with-menu" ng-show="!user.anonymous">
|
||||||
|
<span class="dropdown">
|
||||||
|
<a href="javascript:void(0)" class="dropdown-toggle new-menu" data-toggle="dropdown">
|
||||||
|
<i class="fa fa-plus user-tool"
|
||||||
|
data-placement="bottom" data-title="Create New..." bs-tooltip></i>
|
||||||
|
<b class="caret"></b>
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu context-dropdown">
|
||||||
|
<li>
|
||||||
|
<a href="/organizations/new">
|
||||||
|
<span class="avatar" size="16" data="{'name': '+', color: '#ccc'}"></span>
|
||||||
|
New Organization
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/new{{ getNamespace(currentPageContext) ? '?namespace=' + getNamespace(currentPageContext) : '' }}">
|
||||||
|
<i class="fa fa-hdd-o"></i> New Repository
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li role="presentation" class="divider" ng-if="getNamespace(currentPageContext)"></li>
|
||||||
|
<li role="presentation" class="dropdown-header"
|
||||||
|
ng-if="getNamespace(currentPageContext)">
|
||||||
|
Namespace {{ getNamespace(currentPageContext) }}
|
||||||
|
</li>
|
||||||
|
<li ng-if="isOrganization(getNamespace(currentPageContext)) && canAdmin(getNamespace(currentPageContext))">
|
||||||
|
<a href="javascript:void(0)" ng-click="createTeam(currentPageContext)">
|
||||||
|
<i class="fa fa-group"></i> New Team
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li ng-if="canAdmin(getNamespace(currentPageContext))">
|
||||||
|
<a href="javascript:void(0)" ng-click="createRobot(currentPageContext)">
|
||||||
|
<i class="fa fa-wrench"></i> New Robot Account
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li role="presentation" class="divider" ng-if="currentPageContext.repository"></li>
|
||||||
|
<li role="presentation" class="dropdown-header"
|
||||||
|
ng-if="currentPageContext.repository">
|
||||||
|
Repository {{ currentPageContext.repository.namespace }}/{{ currentPageContext.repository.name }}
|
||||||
|
</li>
|
||||||
|
<li ng-if="currentPageContext.repository">
|
||||||
|
<a href="javascript:void(0)">
|
||||||
|
<i class="fa fa-tasks"></i> New Dockerfile Build
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<span class="navbar-left user-tools" ng-show="!user.anonymous">
|
||||||
|
<a href="javascript:void(0)" data-template="/static/directives/notification-bar.html"
|
||||||
|
data-container="body" data-animation="am-slide-right" bs-aside>
|
||||||
|
<i class="fa fa-bell user-tool"
|
||||||
|
data-placement="bottom" data-title="Notifications" bs-tooltip></i>
|
||||||
|
</a>
|
||||||
|
<span class="notifications-bubble"></span>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dropdown" ng-switch-when="false">
|
||||||
|
<a href="javascript:void(0)" class="dropdown-toggle user-dropdown user-view" data-toggle="dropdown">
|
||||||
|
<span class="avatar" size="32" data="user.avatar"></span>
|
||||||
|
{{ user.username }}
|
||||||
|
<b class="caret"></b>
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li>
|
||||||
|
<a href="/user/{{ user.username }}?tab=settings" target="{{ appLinkTarget() }}" ng-if="isNewLayout">
|
||||||
|
Account Settings
|
||||||
|
</a>
|
||||||
|
<a href="/user/" target="{{ appLinkTarget() }}" ng-if="!isNewLayout">
|
||||||
|
Account Settings
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li><a ng-href="/organizations/" target="{{ appLinkTarget() }}">Organizations</a></li>
|
||||||
|
<li ng-if="user.super_user"><a href="/superuser/"><strong>Super User Admin Panel</strong></a></li>
|
||||||
|
<li><a href="javascript:void(0)" ng-click="signout()">Sign out</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li ng-switch-default>
|
||||||
|
<a class="user-view" href="/signin/" target="{{ appLinkTarget() }}">Sign in</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div><!-- /.navbar-collapse -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="search-box" ng-class="getSearchBoxClasses(searchVisible, searchResultState)">
|
||||||
|
<div class="search-label">Search For</div>
|
||||||
|
<div class="search-box-wrapper">
|
||||||
|
<input id="search-box-input" type="text" placeholder="(Enter Search Terms)"
|
||||||
|
ng-model-options="{'debounce': 250}" ng-model="currentSearchQuery"
|
||||||
|
ng-keydown="handleSearchKeyDown($event)">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="search-results"
|
||||||
|
ng-class="searchVisible && searchResultState ? searchResultState.state : ''"
|
||||||
|
ng-class="{'height': (searchResultState.results.length * 40) + 28}">
|
||||||
|
<div class="cor-loader" ng-if="searchResultState.state == 'loading'"></div>
|
||||||
|
<div ng-if="searchResultState.state == 'no-results'">No matching results found</div>
|
||||||
|
<ul ng-if="searchResultState.state == 'results'">
|
||||||
|
<li ng-repeat="result in searchResultState.results" ng-mouseover="setCurrentResult($index)"
|
||||||
|
ng-class="searchResultState.current == $index ? 'current' : ''"
|
||||||
|
ng-click="showResult(result)">
|
||||||
|
<span class="kind">{{ result.kind }}</span>
|
||||||
|
<span class="score">{{ result.score }}</span>
|
||||||
|
<span ng-switch on="result.kind">
|
||||||
|
<!-- Team -->
|
||||||
|
<span ng-switch-when="team">
|
||||||
|
<strong>
|
||||||
|
<span class="avatar" data="result.avatar" size="16"></span>
|
||||||
|
<span class="result-name">{{ result.name }}</span>
|
||||||
|
</strong>
|
||||||
|
<span class="clarification">
|
||||||
|
under organization
|
||||||
|
<span class="avatar" data="result.organization.avatar" size="16"></span>
|
||||||
|
<span class="result-name">{{ result.organization.name }}</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span ng-switch-when="user">
|
||||||
|
<span class="avatar" data="result.avatar" size="16"></span>
|
||||||
|
<span class="result-name">{{ result.name }}</span>
|
||||||
|
</span>
|
||||||
|
<span ng-switch-when="organization">
|
||||||
|
<span class="avatar" data="result.avatar" size="16"></span>
|
||||||
|
<span class="result-name">{{ result.name }}</span>
|
||||||
|
</span>
|
||||||
|
<span href="/user/{{ result.name }}" ng-switch-when="robot">
|
||||||
|
<i class="fa fa-wrench"></i>
|
||||||
|
<span class="result-name">{{ result.name }}</span>
|
||||||
|
</span>
|
||||||
|
<span ng-switch-when="repository">
|
||||||
|
<span class="avatar" data="result.namespace.avatar" size="16"></span>
|
||||||
|
<span class="result-name">{{ result.namespace.name }}/{{ result.name }}</span>
|
||||||
|
<div class="description" ng-if="result.description">
|
||||||
|
{{ result.description }}
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
78
static/directives/old-header-bar.html
Normal file
78
static/directives/old-header-bar.html
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
<!-- Quay -->
|
||||||
|
<div class="navbar-header">
|
||||||
|
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse" style="padding: 0px; padding-left: 4px; padding-right: 4px;">
|
||||||
|
≡
|
||||||
|
</button>
|
||||||
|
<a class="navbar-brand" href="/" target="{{ appLinkTarget() }}">
|
||||||
|
<span id="quay-logo" ng-style="{'background-image': 'url(' + getEnterpriseLogo() + ')'}"></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Collapsable stuff -->
|
||||||
|
<div class="collapse navbar-collapse navbar-ex1-collapse">
|
||||||
|
<ul class="nav navbar-nav navbar-links">
|
||||||
|
<li><a ng-href="/tour/" target="{{ appLinkTarget() }}" quay-section="tour">Tour</a></li>
|
||||||
|
<li><a ng-href="/repository/" target="{{ appLinkTarget() }}" quay-section="repository">Repositories</a></li>
|
||||||
|
<li><a href="http://docs.quay.io/" target="_blank">Docs</a></li>
|
||||||
|
<li><a ng-href="/tutorial/" target="{{ appLinkTarget() }}" quay-section="tutorial">Tutorial</a></li>
|
||||||
|
<li quay-require="['BILLING']"><a ng-href="/plans/" target="{{ appLinkTarget() }}" quay-section="plans">Pricing</a></li>
|
||||||
|
<li><a ng-href="{{ user.organizations.length ? '/organizations/' : '/tour/organizations/' }}" target="{{ appLinkTarget() }}" quay-section="organization">Organizations</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!-- Phone -->
|
||||||
|
<ul class="nav navbar-nav navbar-right visible-xs" ng-switch on="user.anonymous">
|
||||||
|
<li ng-switch-when="false">
|
||||||
|
<a href="/user/" class="user-view" target="{{ appLinkTarget() }}">
|
||||||
|
<span class="avatar" size="32" data="user.avatar"></span>
|
||||||
|
{{ user.username }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li ng-switch-default>
|
||||||
|
<a class="user-view" href="/signin/" target="{{ appLinkTarget() }}">Sign in</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!-- Normal -->
|
||||||
|
<ul class="nav navbar-nav navbar-right hidden-xs" ng-switch on="user.anonymous">
|
||||||
|
<li>
|
||||||
|
<form class="navbar-form navbar-left" role="search">
|
||||||
|
<div class="form-group">
|
||||||
|
<span class="repo-search"></span>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<span class="navbar-left user-tools" ng-show="!user.anonymous">
|
||||||
|
<a href="/new/"><i class="fa fa-upload user-tool" bs-tooltip="tooltip.title" data-placement="bottom" data-title="Create new repository" data-container="body"></i></a>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dropdown" ng-switch-when="false">
|
||||||
|
<a href="javascript:void(0)" class="dropdown-toggle user-dropdown user-view" data-toggle="dropdown">
|
||||||
|
<span class="avatar" size="32" data="user.avatar"></span>
|
||||||
|
{{ user.username }}
|
||||||
|
<span class="notifications-bubble"></span>
|
||||||
|
<b class="caret"></b>
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li>
|
||||||
|
<a href="/user/" target="{{ appLinkTarget() }}">
|
||||||
|
Account Settings
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li ng-if="notificationService.notifications.length">
|
||||||
|
<a href="javascript:void(0)" data-template="/static/directives/notification-bar.html"
|
||||||
|
data-animation="am-slide-right" bs-aside="aside" data-container="body">
|
||||||
|
Notifications
|
||||||
|
<span class="notifications-bubble"></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li><a ng-href="/organizations/" target="{{ appLinkTarget() }}">Organizations</a></li>
|
||||||
|
<li ng-if="user.super_user"><a href="/superuser/"><strong>Super User Admin Panel</strong></a></li>
|
||||||
|
<li><a href="javascript:void(0)" ng-click="signout()">Sign out</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li ng-switch-default>
|
||||||
|
<a class="user-view" href="/signin/" target="{{ appLinkTarget() }}">Sign in</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div><!-- /.navbar-collapse -->
|
|
@ -12,7 +12,7 @@ angular.module('quay').directive('headerBar', function () {
|
||||||
restrict: 'C',
|
restrict: 'C',
|
||||||
scope: {
|
scope: {
|
||||||
},
|
},
|
||||||
controller: function($scope, $element, $location, $timeout, UserService, PlanService, ApiService, NotificationService, Config) {
|
controller: function($rootScope, $scope, $element, $location, $timeout, UserService, PlanService, ApiService, NotificationService, Config, CreateService) {
|
||||||
$scope.notificationService = NotificationService;
|
$scope.notificationService = NotificationService;
|
||||||
$scope.searchVisible = false;
|
$scope.searchVisible = false;
|
||||||
$scope.currentSearchQuery = null;
|
$scope.currentSearchQuery = null;
|
||||||
|
@ -23,6 +23,19 @@ angular.module('quay').directive('headerBar', function () {
|
||||||
|
|
||||||
$scope.isNewLayout = Config.isNewLayout();
|
$scope.isNewLayout = Config.isNewLayout();
|
||||||
|
|
||||||
|
$scope.currentPageContext = {};
|
||||||
|
|
||||||
|
$rootScope.$watch('currentPage.scope.viewuser', function(u) {
|
||||||
|
$scope.currentPageContext['viewuser'] = u;
|
||||||
|
});
|
||||||
|
|
||||||
|
$rootScope.$watch('currentPage.scope.organization', function(o) {
|
||||||
|
$scope.currentPageContext['organization'] = o;
|
||||||
|
});
|
||||||
|
|
||||||
|
$rootScope.$watch('currentPage.scope.repository', function(r) {
|
||||||
|
$scope.currentPageContext['repository'] = r;
|
||||||
|
});
|
||||||
|
|
||||||
var conductSearch = function(query) {
|
var conductSearch = function(query) {
|
||||||
if (!query) { $scope.searchResultState = null; return; }
|
if (!query) { $scope.searchResultState = null; return; }
|
||||||
|
@ -43,6 +56,8 @@ angular.module('quay').directive('headerBar', function () {
|
||||||
'results': resp.results,
|
'results': resp.results,
|
||||||
'current': -1
|
'current': -1
|
||||||
};
|
};
|
||||||
|
}, function(resp) {
|
||||||
|
$scope.searchResultState = null;
|
||||||
}, /* background */ true);
|
}, /* background */ true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -133,6 +148,77 @@ angular.module('quay').directive('headerBar', function () {
|
||||||
if (!$scope.searchResultState) { return; }
|
if (!$scope.searchResultState) { return; }
|
||||||
$scope.searchResultState['current'] = result;
|
$scope.searchResultState['current'] = result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.getNamespace = function(context) {
|
||||||
|
if (!context) { return null; }
|
||||||
|
|
||||||
|
if (context.repository && context.repository.namespace) {
|
||||||
|
return context.repository.namespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.organization && context.organization.name) {
|
||||||
|
return context.organization.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.viewuser && context.viewuser.username) {
|
||||||
|
return context.viewuser.username;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.canAdmin = function(namespace) {
|
||||||
|
if (!namespace) { return false; }
|
||||||
|
return UserService.isNamespaceAdmin(namespace);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.isOrganization = function(namespace) {
|
||||||
|
if (!namespace) { return false; }
|
||||||
|
return UserService.isOrganization(namespace);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.createRobot = function(context) {
|
||||||
|
var namespace = $scope.getNamespace(context);
|
||||||
|
if (!namespace || !UserService.isNamespaceAdmin(namespace)) { return; }
|
||||||
|
|
||||||
|
var isorg = UserService.isOrganization(namespace);
|
||||||
|
bootbox.prompt('Enter the name of the new robot account', function(robotname) {
|
||||||
|
if (!robotname) { return; }
|
||||||
|
|
||||||
|
var regex = new RegExp(ROBOT_PATTERN);
|
||||||
|
if (!regex.test(robotname)) {
|
||||||
|
bootbox.alert('Invalid robot account name');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateService.createRobotAccount(ApiService, isorg, namespace, robotname, function(created) {
|
||||||
|
if (isorg) {
|
||||||
|
$location.url('/organization/' + namespace + '?tab=robots');
|
||||||
|
} else {
|
||||||
|
$location.url('/user/' + namespace + '?tab=robots');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.createTeam = function(context) {
|
||||||
|
var namespace = $scope.getNamespace(context);
|
||||||
|
if (!namespace || !UserService.isNamespaceAdmin(namespace)) { return; }
|
||||||
|
|
||||||
|
bootbox.prompt('Enter the name of the new team', function(teamname) {
|
||||||
|
if (!teamname) { return; }
|
||||||
|
|
||||||
|
var regex = new RegExp(TEAM_PATTERN);
|
||||||
|
if (!regex.test(teamname)) {
|
||||||
|
bootbox.alert('Invalid team name');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateService.createOrganizationTeam(ApiService, namespace, teamname, function(created) {
|
||||||
|
$location.url('/organization/' + namespace + '/teams/' + teamname);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return directiveDefinitionObject;
|
return directiveDefinitionObject;
|
||||||
|
|
|
@ -47,7 +47,7 @@ angular.module('quay').directive('teamsManager', function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
var loadOrderedTeams = function() {
|
var loadOrderedTeams = function() {
|
||||||
if (!$scope.organization) { return; }
|
if (!$scope.organization || !$scope.organization.ordered_teams) { return; }
|
||||||
|
|
||||||
$scope.orderedTeams = [];
|
$scope.orderedTeams = [];
|
||||||
$scope.organization.ordered_teams.map(function(name) {
|
$scope.organization.ordered_teams.map(function(name) {
|
||||||
|
|
|
@ -63,6 +63,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.repositoryResource = ApiService.getRepoAsResource(params).get(function(repo) {
|
$scope.repositoryResource = ApiService.getRepoAsResource(params).get(function(repo) {
|
||||||
|
$scope.repository = repo;
|
||||||
$scope.viewScope.repository = repo;
|
$scope.viewScope.repository = repo;
|
||||||
|
|
||||||
// Load the remainder of the data async, so we don't block the initial view from
|
// Load the remainder of the data async, so we don't block the initial view from
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
var loadUser = function() {
|
var loadUser = function() {
|
||||||
$scope.userResource = ApiService.getUserInformationAsResource({'username': username}).get(function(user) {
|
$scope.userResource = ApiService.getUserInformationAsResource({'username': username}).get(function(user) {
|
||||||
$scope.user = user;
|
$scope.viewuser = user;
|
||||||
|
|
||||||
// Load the repositories.
|
// Load the repositories.
|
||||||
$timeout(function() {
|
$timeout(function() {
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
<div class="cor-title">
|
<div class="cor-title">
|
||||||
<span class="cor-title-link"></span>
|
<span class="cor-title-link"></span>
|
||||||
<span class="cor-title-content">
|
<span class="cor-title-content">
|
||||||
<span class="avatar" size="32" data="user.avatar"></span>
|
<span class="avatar" size="32" data="viewuser.avatar"></span>
|
||||||
<span class="user-name">{{ user.username }}</span>
|
<span class="user-name">{{ viewuser.username }}</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="co-main-content-panel user-repo-list" ng-if="!user.is_me">
|
<div class="co-main-content-panel user-repo-list" ng-if="!viewuser.is_me">
|
||||||
<div class="repo-list-grid"
|
<div class="repo-list-grid"
|
||||||
repositories-resource="repositoriesResource"
|
repositories-resource="repositoriesResource"
|
||||||
starred="false"
|
starred="false"
|
||||||
|
@ -18,8 +18,8 @@
|
||||||
hide-title="true"></div>
|
hide-title="true"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="cor-tab-panel" ng-if="user.is_me">
|
<div class="cor-tab-panel" ng-if="viewuser.is_me">
|
||||||
<div class="cor-tabs" quay-show="user.is_me">
|
<div class="cor-tabs" quay-show="viewuser.is_me">
|
||||||
<span class="cor-tab" tab-active="true" tab-title="Repositories" tab-target="#repos">
|
<span class="cor-tab" tab-active="true" tab-title="Repositories" tab-target="#repos">
|
||||||
<i class="fa fa-hdd-o"></i>
|
<i class="fa fa-hdd-o"></i>
|
||||||
</span>
|
</span>
|
||||||
|
@ -60,29 +60,29 @@
|
||||||
|
|
||||||
<!-- Robot Accounts -->
|
<!-- Robot Accounts -->
|
||||||
<div id="robots" class="tab-pane">
|
<div id="robots" class="tab-pane">
|
||||||
<div class="robots-manager" user="user"></div>
|
<div class="robots-manager" user="viewuser"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- External Logins -->
|
<!-- External Logins -->
|
||||||
<div id="external" class="tab-pane">
|
<div id="external" class="tab-pane">
|
||||||
<div class="external-logins-manager" user="user"></div>
|
<div class="external-logins-manager" user="viewuser"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Applications -->
|
<!-- Applications -->
|
||||||
<div id="applications" class="tab-pane">
|
<div id="applications" class="tab-pane">
|
||||||
<div class="authorized-apps-manager" user="user" is-enabled="showAppsCounter"></div>
|
<div class="authorized-apps-manager" user="viewuser" is-enabled="showAppsCounter"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Plan and Usage -->
|
<!-- Plan and Usage -->
|
||||||
<div id="usage" class="tab-pane" quay-require="['BILLING']">
|
<div id="usage" class="tab-pane" quay-require="['BILLING']">
|
||||||
<h3>Plan Usage and Billing</h3>
|
<h3>Plan Usage and Billing</h3>
|
||||||
<div class="plan-manager" user="user"></div>
|
<div class="plan-manager" user="viewuser"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Billing Invoices -->
|
<!-- Billing Invoices -->
|
||||||
<div id="invoices" class="tab-pane" quay-require="['BILLING']">
|
<div id="invoices" class="tab-pane" quay-require="['BILLING']">
|
||||||
<h3>Billing Invoices</h3>
|
<h3>Billing Invoices</h3>
|
||||||
<div class="billing-invoices" user="user"
|
<div class="billing-invoices" user="viewuser"
|
||||||
makevisible="showInvoicesCounter"></div>
|
makevisible="showInvoicesCounter"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@
|
||||||
<table class="col-md-6">
|
<table class="col-md-6">
|
||||||
<tr>
|
<tr>
|
||||||
<td>Current E-mail Address:</td>
|
<td>Current E-mail Address:</td>
|
||||||
<td>{{ user.email }}</td>
|
<td>{{ viewuser.email }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>New E-mail Address:</td>
|
<td>New E-mail Address:</td>
|
||||||
|
@ -124,7 +124,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="btn btn-primary"
|
<button class="btn btn-primary"
|
||||||
ng-disabled="changeEmailForm.$invalid || changeEmail.email == user.email"
|
ng-disabled="changeEmailForm.$invalid || changeEmail.email == viewuser.email"
|
||||||
type="submit">
|
type="submit">
|
||||||
Change E-mail Address
|
Change E-mail Address
|
||||||
</button>
|
</button>
|
||||||
|
@ -193,7 +193,7 @@
|
||||||
<div class="co-panel" quay-show="Config.AUTHENTICATION_TYPE == 'Database'">
|
<div class="co-panel" quay-show="Config.AUTHENTICATION_TYPE == 'Database'">
|
||||||
<div class="co-panel-heading"><i class="fa fa-group"></i> Convert to organization</div>
|
<div class="co-panel-heading"><i class="fa fa-group"></i> Convert to organization</div>
|
||||||
<div class="panel-body" style="padding-top: 5px;">
|
<div class="panel-body" style="padding-top: 5px;">
|
||||||
<div class="convert-user-to-org" user="user"></div>
|
<div class="convert-user-to-org" user="viewuser"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div> <!-- /Convert -->
|
</div> <!-- /Convert -->
|
||||||
|
|
Reference in a new issue