Merge remote-tracking branch 'origin/orgs'

Conflicts:
	static/partials/repo-admin.html
This commit is contained in:
yackob03 2013-11-08 16:44:49 -05:00
commit d7cae4fbca
72 changed files with 18683 additions and 1028 deletions

View file

@ -0,0 +1,3 @@
<form name="newteamform" ng-submit="createTeam(); hide()" novalidate>
<input id="create-team-box" type="text form-control" placeholder="Team Name" ng-blur="hide()" ng-pattern="/^[a-zA-Z][a-zA-Z0-9]+$/" ng-model="newTeamName" ng-trim="false" ng-minlength="2" required>
</form>

View file

@ -1,7 +1,7 @@
<div class="container ready-indicator" data-status="{{ status }}">
<div class="alert alert-warning">Warning: Quay requires docker version 0.6.2 or higher to work</div>
<h2>User guide</h2>
<h2>User Guide</h2>
<div class="user-guide container">
<h3>Pulling a repository from Quay</h3>

View file

@ -15,8 +15,9 @@
<div class="collapse navbar-collapse navbar-ex1-collapse">
<ul class="nav navbar-nav">
<li><a ng-href="/repository/" target="{{ appLinkTarget() }}">Repositories</a></li>
<li><a ng-href="/guide/" target="{{ appLinkTarget() }}">User Guide</a></li>
<li><a ng-href="/plans/" target="{{ appLinkTarget() }}">Plans &amp; Pricing</a></li>
<li><a ng-href="/guide/" target="{{ appLinkTarget() }}">Guide</a></li>
<li><a ng-href="/plans/" target="{{ appLinkTarget() }}">Pricing</a></li>
<li><a ng-href="/organizations/" target="{{ appLinkTarget() }}">Organizations</a></li>
</ul>
@ -28,7 +29,7 @@
</form>
<span class="navbar-left user-tools" ng-show="!user.anonymous">
<a href="/new/"><i class="fa fa-upload user-tool" title="Create new repository"></i></a>
<a href="/new/"><i class="fa fa-upload user-tool" bs-tooltip="tooltip.title" data-placement="bottom" title="Create new repository"></i></a>
</span>
<li class="dropdown" ng-switch-when="false">
@ -45,6 +46,7 @@
<span class="badge user-notification" ng-show="user.askForPassword">1</span>
</a>
</li>
<li><a ng-href="/organizations/" target="{{ appLinkTarget() }}">Organizations</a></li>
<li><a href="javascript:void(0)" ng-click="signout()">Sign out</a></li>
</ul>
</li>

View file

@ -20,7 +20,9 @@
</div>
<!-- Comment -->
<blockquote ng-show="image.comment" ng-bind-html-unsafe="getMarkedDown(image.comment)"></blockquote>
<blockquote ng-show="image.comment">
<span class="markdown-view" content="image.comment"></span>
</blockquote>
<!-- Information -->
<dl class="dl-normal">

View file

@ -12,22 +12,22 @@
<div ng-show="loadingmyrepos">
<i class="fa fa-spinner fa-spin fa-3x"></i>
</div>
<span class="namespace-selector" user="user" namespace="namespace" ng-show="!loadingmyrepos && user.organizations"></span>
<div ng-show="!loadingmyrepos && myrepos.length > 0">
<h2>Your Top Repositories</h2>
<h2>Top Repositories</h2>
<div class="repo-listing" ng-repeat="repository in myrepos">
<span class="repo-circle no-background" repo="repository"></span>
<a ng-href="/repository/{{ repository.namespace }}/{{ repository.name }}">{{repository.namespace}}/{{repository.name}}</a>
<div class="description" ng-bind-html-unsafe="getCommentFirstLine(repository.description)"></div>
<div class="markdown-view description" content="repository.description" first-line-only="true"></div>
</div>
</div>
<div ng-show="!loadingmyrepos && myrepos.length == 0">
<div class="sub-message">
You don't have any <b>private</b> repositories yet!
<div class="sub-message" style="margin-top: 20px">
<span ng-show="namespace != user.username">You don't have access to any repositories in this organization yet.</span>
<span ng-show="namespace == user.username">You don't have any repositories yet!</span>
<div class="options">
<div class="option"><a href="/guide">Learn how to create a repository</a></div>
<div class="or"><span>or</span></div>
<div class="option"><a href="/repository">Browse the public repositories</a></div>
<a class="btn btn-primary" href="/repository/">Browse all repositories</a>
<a class="btn btn-success" href="/new/" ng-show="canCreateRepo(namespace)">Create a new repository</a>
</div>
</div>
</div>

View file

@ -0,0 +1,102 @@
<div class="loading" ng-show="loading || creating">
<i class="fa fa-spinner fa-spin fa-3x"></i>
</div>
<div class="container create-org" ng-show="!loading && !creating">
<div class="row header-row">
<div class="col-md-8 col-md-offset-1">
<h2>Create Organization</h2>
<div class="steps-container" ng-show="false">
<ul class="steps">
<li class="step" ng-class="!user || user.anonymous ? 'active' : ''">
<i class="fa fa-sign-in"></i>
<span class="title">Login with an account</span>
</li>
<li class="step" ng-class="!user.anonymous && !created ? 'active' : ''">
<i class="fa fa-gear"></i>
<span class="title">Setup your organization</span>
</li>
<li class="step" ng-class="!user.anonymous && created ? 'active' : ''">
<i class="fa fa-group"></i>
<span class="title">Create teams</span>
</li>
</ul>
</div>
</div>
</div>
<!-- Step 1 -->
<div class="row" ng-show="!user || user.anonymous">
<div class="col-md-10 col-md-offset-1 page-description">
In order to create a new organization, <b>you must first be signed in</b> as the
user that <b>will become an admin</b> for the organization. Please sign-in if
you already have an account, or <a href="/">sign up</a> on the landing
page to create a new account.
</div>
<div class="col-sm-6 col-sm-offset-3">
<div class="step-container" >
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">Sign In</h4>
</div>
<div class="panel-body">
<div class="signin-form" redirect-url="'/organizations/new'"></div>
</div>
</div>
</div>
</div>
</div>
<!-- Step 2 -->
<div class="row" ng-show="user && !user.anonymous && !created">
<div class="col-md-1"></div>
<div class="col-md-8">
<div class="step-container">
<h3>Setup the new organization</h3>
<form method="post" name="newOrgForm" id="newOrgForm" ng-submit="createNewOrg()">
<div class="form-group">
<label for="orgName">Organization Name</label>
<input id="orgName" name="orgName" type="text" class="form-control" placeholder="Organization Name"
ng-model="org.name" required autofocus data-trigger="manual" data-content="{{ createError }}"
data-placement="right">
<span class="description">This will also be the namespace for your repositories</span>
</div>
<div class="form-group">
<label for="orgName">Organization Email</label>
<input id="orgEmail" name="orgEmail" type="email" class="form-control" placeholder="Organization Email"
ng-model="org.email" required>
<span class="description">This address must be different from your account's email</span>
</div>
<!-- Plans Table -->
<div class="form-group plan-group">
<strong>Choose your organization's plan</strong>
<div class="plans-table" plans="plans" current-plan="currentPlan"></div>
</div>
<div class="button-bar">
<button class="btn btn-large btn-success" type="submit" ng-disabled="newOrgForm.$invalid || !currentPlan">
Create Organization
</button>
</div>
</form>
</div>
</div>
</div>
<!-- Step 3 -->
<div class="row" ng-show="user && !user.anonymous && created">
<div class="col-md-1"></div>
<div class="col-md-8">
<div class="step-container">
<h3>Organization Created</h3>
<h4><a href="/organization/{{ org.name }}">Manage Teams Now</a></h4>
</div>
</div>
</div>
</div>

View file

@ -28,17 +28,19 @@
<div class="col-md-8">
<div class="section">
<div class="new-header">
<span class="repo-circle no-background" repo="repo"></span>
<span style="color: #444;"> {{user.username}}</span> <span style="color: #ccc">/</span> <span class="name-container"><input id="repoName" name="repoName" type="text" class="form-control" placeholder="Repository Name" ng-model="repo.name" required autofocus data-trigger="manual" data-content="{{ createError }}" data-placement="right"></span>
<span style="color: #444;">
<span class="namespace-selector" user="user" namespace="repo.namespace" require-create="true"></span>
<span style="color: #ccc">/</span>
<span class="name-container">
<input id="repoName" name="repoName" type="text" class="form-control" placeholder="Repository Name" ng-model="repo.name" required autofocus data-trigger="manual" data-content="{{ createError }}" data-placement="right">
</span>
</div>
</div>
<div class="section">
<strong>Description:</strong><br>
<p class="description lead editable" ng-click="editDescription()">
<span class="content" ng-bind-html-unsafe="getMarkedDown(repo.description)"></span>
<i class="fa fa-edit"></i>
</p>
<div class="description markdown-input" content="repo.description" can-write="true"
field-title="'repository description'"></div>
</div>
</div>
</div>
@ -68,13 +70,19 @@
</div>
<!-- Payment -->
<div class="required-plan" ng-show="repo.is_public == '0' && planRequired">
<div class="required-plan" ng-show="repo.is_public == '0' && planRequired && isUserNamespace">
<div class="alert alert-warning">
In order to make this repository private, youll need to upgrade your plan from <b>{{ subscribedPlan.title }}</b> to <b>{{ planRequired.title }}</b>. This will cost $<span>{{ planRequired.price / 100 }}</span>/month.
</div>
<a class="btn btn-primary" ng-click="upgradePlan()" ng-show="!planChanging">Upgrade now</a>
<i class="fa fa-spinner fa-spin fa-3x" ng-show="planChanging"></i>
</div>
<div class="required-plan" ng-show="repo.is_public == '0' && planRequired && !isUserNamespace">
<div class="alert alert-warning">
This organization has reached its private repository limit. Please contact your administrator.
</div>
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,67 @@
<div class="loading" ng-show="loading">
<i class="fa fa-spinner fa-spin fa-3x"></i>
</div>
<div class="loading" ng-show="!loading && !organization">
No matching organization found
</div>
<div class="org-admin container" ng-show="!loading && organization">
<div class="organization-header" organization="organization"></div>
<div class="row">
<!-- Side tabs -->
<div class="col-md-2">
<ul class="nav nav-pills nav-stacked">
<li class="active"><a href="javascript:void(0)" data-toggle="tab" data-target="#plan">Plan and Usage</a></li>
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#members" ng-click="loadMembers()">Members</a></li>
</ul>
</div>
<!-- Content -->
<div class="col-md-10">
<div class="tab-content">
<!-- Plans tab -->
<div id="plan" class="tab-pane active">
<div class="plan-manager" organization="orgname"></div>
</div>
<!-- Members tab -->
<div id="members" class="tab-pane">
<i class="fa fa-spinner fa-spin fa-3x" ng-show="membersLoading"></i>
<div ng-show="!membersLoading">
<div class="side-controls">
<div class="result-count">
Showing {{(membersFound | filter:search | limitTo:50).length}} of {{(membersFound | filter:search).length}} matching members
</div>
<div class="filter-input">
<input id="member-filter" class="form-control" placeholder="Filter Members" type="text" ng-model="search.$">
</div>
</div>
<table class="table table-striped">
<thead>
<th>User</th>
<th>Teams</th>
</thead>
<tr ng-repeat="memberInfo in (membersFound | filter:search | limitTo:50)">
<td>
<i class="fa fa-user"></i>
{{ memberInfo.username }}
</td>
<td>
<span class="team-link" ng-repeat="team in memberInfo.teams">
<i class="fa fa-group"></i>
<a href="/organization/{{ organization.name }}/teams/{{ team }}">{{ team }}</a>
</span>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,86 @@
<div class="loading" ng-show="loading">
<i class="fa fa-spinner fa-spin fa-3x"></i>
</div>
<div class="loading" ng-show="!loading && !organization">
No matching organization found
</div>
<div class="org-view container" ng-show="!loading && organization">
<div class="organization-header" organization="organization">
<div class="header-buttons" ng-show="organization.is_admin">
<button class="btn btn-success" data-trigger="click" bs-popover="'static/partials/create-team-dialog.html'" data-placement="bottom" ng-click="createTeamShown()"><i class="fa fa-group"></i> Create Team</button>
<a class="btn btn-default" href="/organization/{{ organization.name }}/admin"><i class="fa fa-gear"></i> Settings</a>
</div>
</div>
<div class="row hidden-xs">
<div class="col-md-4 col-md-offset-8 col-sm-5 col-sm-offset-7 header-col" ng-show="organization.is_admin">
Team Permissions
<i class="info-icon fa fa-info-circle" data-placement="bottom" data-original-title="" title=""
data-content="Global permissions for the team and its members<br><br><dl><dt>Member</dt><dd>Permissions are assigned on a per repository basis</dd><dt>Creator</dt><dd>A team can create its own repositories</dd><dt>Admin</dt><dd>A team has full control of the organization</dd></dl>"></i>
</div>
</div>
<div class="team-listing" ng-repeat="(name, team) in organization.teams">
<div id="team-{{name}}" class="row">
<div class="col-sm-7 col-md-8">
<div class="team-title">
<i class="fa fa-group"></i>
<span ng-show="team.can_view">
<a href="/organization/{{ organization.name }}/teams/{{ team.name }}">{{ team.name }}</a>
</span>
<span ng-show="!team.can_view">
{{ team.name }}
</span>
</div>
<div class="team-description markdown-view" content="team.description" first-line-only="true"></div>
</div>
<div class="col-sm-5 col-md-4 control-col" ng-show="organization.is_admin">
<span class="role-group" current-role="team.role" role-changed="setRole(role, team.name)" roles="teamRoles"></span>
<button class="btn btn-sm btn-danger" ng-click="askDeleteTeam(team.name)">Delete</button>
</div>
</div>
</div>
</div>
<!-- Modal message dialog -->
<div class="modal fade" id="cannotChangeTeamModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Cannot change team</h4>
</div>
<div class="modal-body">
<span ng-show="!roleError">You do not have permission to change properties on teams.</span>
<span ng-show="roleError">{{ roleError }}</span>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<!-- Modal message dialog -->
<div class="modal fade" id="confirmdeleteModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Delete Team?</h4>
</div>
<div class="modal-body">
Are you sure you would like to delete this team? This <b>cannot be undone</b>.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" ng-click="deleteTeam()">Delete Team</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->

View file

@ -0,0 +1,129 @@
<div class="container org-list">
<div class="loading" ng-show="loading">
<i class="fa fa-spinner fa-spin fa-3x"></i>
</div>
<div class="button-bar-right">
<a href="/organizations/new/" title="Starts the process to create a new organization" bs-tooltip="tooltip.title">
<button class="btn btn-success">
<i class="fa fa-plus"></i>
Create New Organization
</button>
</a>
<a href="/user/?migrate" ng-show="!user.anonymous" title="Starts the process to convert this account into an organization" bs-tooltip="tooltip.title">
<button class="btn btn-primary">
<i class="fa fa-caret-square-o-right"></i>
Convert account
</button>
</a>
</div>
<!-- Organizations -->
<div ng-show="user.organizations.length > 0">
<h2>Organizations</h2>
<div class="organization-listing" ng-repeat="organization in user.organizations">
<img class="gravatar" src="//www.gravatar.com/avatar/{{ organization.gravatar }}?s=32&amp;d=identicon">
<a class="org-title" href="/organization/{{ organization.name }}">{{ organization.name }}</a>
</div>
</div>
<!-- Organization Help/Tour -->
<div class="product-tour" ng-show="!user.organizations || user.organizations.length == 0">
<div class="tour-section row">
<div class="col-md-12">
<div class="tour-section-title">Organizations</div>
<div class="tour-section-description">
Organizations in Quay provide unique features for businesses and other
groups, including team-based sharing and fine-grained permission controls.
</div>
</div>
</div>
<div class="tour-section row">
<div class="col-md-7"><img src="/static/img/org-repo-list.png" title="Repositories - Quay" data-screenshot-url="https://quay.io/repository/" class="img-responsive"></div>
<div class="col-md-5">
<div class="tour-section-title">A central collection of repositories</div>
<div class="tour-section-description">
Your organization is the focal point for all activity that occurs within
your public or private repositories. Your repositories are centrally visible
and managed within the namespace of your organization. You may share
your repositories with as many users and teams as you like, without
any additional cost.
</div>
</div>
</div>
<div class="tour-section row">
<div class="col-md-7 col-md-push-5"><img src="/static/img/org-admin.png" title="buynlarge Admin - Quay" data-screenshot-url="https://quay.io/organization/buynlarge/admin" class="img-responsive"></div>
<div class="col-md-5 col-md-pull-7">
<div class="tour-section-title">Organization settings at a glance</div>
<div class="tour-section-description">
Your organization allows you to view your private repository count
and manage billing settings in a centralized place.
</div>
<div class="tour-section-description">
You can also see all of the users who have access to your organization
and the teams of which they are members. This allows you to audit the
access that has been granted in your organization.
</div>
</div>
</div>
<div class="tour-section row">
<div class="col-md-7"><img src="/static/img/org-teams.png" title="buynlarge - Quay" data-screenshot-url="https://quay.io/organization/buynlarge" class="img-responsive"></div>
<div class="col-md-5">
<div class="tour-section-title">Teams simplify access controls</div>
<div class="tour-section-description">
Teams allow your organization to delegate access to your namespace and
repositories in a controlled fashion. Each team has permissions that
apply across the entire org, and can also be given specific levels of
access to specific repositories. A user is switching roles? No problem,
change their team membership and their access will be adjusted accordingly.
</div>
<div class="tour-section-description">
Owners of your organization, and members of other teams with
administrator privileges, have full permissions to all repositories
in the organization, as well as permissions to view and adjust the
account settings for the organization. Add users to these teams with
caution.
</div>
</div>
</div>
<div class="tour-section row">
<div class="col-md-7 col-md-push-5"><img src="/static/img/org-repo-admin.png" title="buynlarge/orgrepo - Quay" data-screenshot-url="https://quay.io/repository/buynlarge/orgrepo" class="img-responsive"></div>
<div class="col-md-5 col-md-pull-7">
<div class="tour-section-title">Fine-grained control of sharing</div>
<div class="tour-section-description">
Repositories that you create within your organization can be assigned
fine-grained permissions just like any other repository. You can also
add teams that exist in your organization, or individual users from
inside our outside your organization.
</div>
<div class="tour-section-description">
In order to protect your intellectual property, we warn you before
you share your repositories with anyone who is not currently a member
of a team in your organization.
</div>
</div>
</div>
<div class="button-bar-right button-bar-bottom">
<a href="/organizations/new/" title="Starts the process to create a new organization" bs-tooltip="tooltip.title">
<button class="btn btn-success">
<i class="fa fa-plus"></i>
Create New Organization
</button>
</a>
<a href="/user/?migrate" ng-show="!user.anonymous" title="Starts the process to convert this account into an organization" bs-tooltip="tooltip.title">
<button class="btn btn-primary">
<i class="fa fa-caret-square-o-right"></i>
Convert account
</button>
</a>
</div>
</div>
</div>

View file

@ -7,15 +7,39 @@
All plans include <span class="feature">unlimited public repositories</span> and <span class="feature">unlimited sharing</span>. All paid plans have a <span class="feature">14-day free trial</span>.
</div>
<div class="plans-list">
<div class="plan" ng-repeat="plan in plans" ng-class="plan.stripeId">
<div class="plan-title">{{ plan.title }}</div>
<div class="plan-price">${{ plan.price/100 }}</div>
<div class="count"><b>{{ plan.privateRepos }}</b> private repositories</div>
<div class="description">{{ plan.audience }}</div>
<div class="smaller">SSL secured connections</div>
<div class="row plans-list">
<div class="col-xs-0 col-lg-1"></div>
<div class="col-lg-2 col-xs-4 plan-container" ng-repeat="plan in plans.user">
<div class="plan" ng-class="plan.stripeId">
<div class="plan-title">{{ plan.title }}</div>
<div class="plan-price">${{ plan.price/100 }}</div>
<div class="count"><b>{{ plan.privateRepos }}</b> private repositories</div>
<div class="description">{{ plan.audience }}</div>
<div class="smaller">SSL secured connections</div>
<button class="btn btn-primary btn-block" ng-click="buyNow(plan.stripeId)">Sign Up Now</button>
</div>
</div>
</div>
<button class="btn btn-primary btn-block" ng-click="buyNow(plan.stripeId)">Sign Up Now</button>
<div class="callout">
Business Plan Pricing
</div>
<div class="all-plans">
All business plans include all of the personal plan features, plus: <span class="business-feature">organizations</span> and <span class="business-feature">teams</span> with <span class="business-feature">delegated access</span> to the organization. All business plans have a <span class="business-feature">14-day free trial</span>.
</div>
<div class="row plans-list">
<div class="col-xs-0 col-lg-1"></div>
<div class="col-lg-2 col-xs-4 plan-container" ng-repeat="plan in plans.business">
<div class="plan business-plan" ng-class="plan.stripeId">
<div class="plan-title">{{ plan.title }}</div>
<div class="plan-price">${{ plan.price/100 }}</div>
<div class="count"><b>{{ plan.privateRepos }}</b> private repositories</div>
<div class="description">{{ plan.audience }}</div>
<div class="smaller">SSL secured connections</div>
<button class="btn btn-success btn-block" ng-click="createOrg(plan.stripeId)">Sign Up Now</button>
</div>
</div>
</div>

View file

@ -20,44 +20,61 @@
<!-- User Access Permissions -->
<div class="panel panel-default">
<div class="panel-heading">User Access Permissions
<div class="panel-heading">User <span ng-show="repo.is_organization">and Team</span> Access Permissions
<i class="info-icon fa fa-info-circle" data-placement="left" data-content="Allow any number of users to read, write or administer this repository"></i>
<i class="info-icon fa fa-info-circle" data-placement="left" data-content="Allow any number of users or teams to read, write or administer this repository"></i>
</div>
<div class="panel-body">
<table class="permissions">
<thead>
<tr>
<td>User</td>
<td>User<span ng-show="repo.is_organization">/Team</span></td>
<td>Permissions</td>
<td></td>
<td style="width: 95px;"></td>
</tr>
</thead>
<tr ng-repeat="(username, permission) in permissions">
<td class="user">
<!-- Team Permissions -->
<tr ng-repeat="(name, permission) in permissions['team']">
<td class="team entity">
<i class="fa fa-group"></i>
<span><a href="/organization/{{ repo.namespace }}/teams/{{ name }}">{{name}}</a></span>
</td>
<td class="user-permissions">
<span class="role-group" current-role="permission.role" role-changed="setRole(role, name, 'team')" roles="roles"></span>
</td>
<td>
<span class="delete-ui" tabindex="0">
<span class="delete-ui-button" ng-click="deleteRole(name, 'team')"><button class="btn btn-danger">Delete</button></span>
<i class="fa fa-times" bs-tooltip="tooltip.title" data-placement="right" title="Delete Permission"></i>
</span>
</td>
</tr>
<!-- User Permissions -->
<tr ng-repeat="(name, permission) in permissions['user']">
<td class="{{ 'user entity ' + (permission.is_org_member? '' : 'outside') }}">
<i class="fa fa-user"></i>
<span>{{username}}</span>
<span>{{name}}</span>
<i class="fa fa-exclamation-triangle" ng-show="permission.is_org_member === false" data-trigger="hover" bs-popover="{'content': 'This user is not a member of the organization'}"></i>
</td>
<td class="user-permissions">
<div class="btn-group btn-group-sm">
<button type="button" class="btn btn-default" ng-click="setRole(username, 'read')" ng-class="{read: 'active', write: '', admin: ''}[permission.role]">Read only</button>
<button type="button" class="btn btn-default" ng-click="setRole(username, 'write')" ng-class="{read: '', write: 'active', admin: ''}[permission.role]">Write</button>
<button type="button" class="btn btn-default" ng-click="setRole(username, 'admin')" ng-class="{read: '', write: '', admin: 'active'}[permission.role]">Admin</button>
<span class="role-group" current-role="permission.role" role-changed="setRole(role, name, 'user')" roles="roles"></span>
</div>
</td>
<td>
<span class="delete-ui" tabindex="0" title="Delete Permission">
<span class="delete-ui-button" ng-click="deleteRole(username)"><button class="btn btn-danger">Delete</button></span>
<i class="fa fa-times"></i>
<span class="delete-ui-button" ng-click="deleteRole(name, 'user')"><button class="btn btn-danger">Delete</button></span>
<i class="fa fa-times" bs-tooltip="tooltip.title" data-placement="right" title="Delete Permission"></i>
</span>
</td>
</tr>
<tr>
<td colspan="2">
<input id="userSearch" class="form-control" placeholder="Add new user...">
<span class="entity-search" organization="repo.namespace" input-title="'Add a ' + (repo.is_organization ? 'team or ' : '') + 'user...'" entity-selected="addNewPermission"></span>
</td>
</tr>
</table>
@ -93,9 +110,9 @@
</div>
</td>
<td>
<span class="delete-ui" tabindex="0" title="Delete Token">
<span class="delete-ui" tabindex="0">
<span class="delete-ui-button" ng-click="deleteToken(token.code)"><button class="btn btn-danger" type="button">Delete</button></span>
<i class="fa fa-times"></i>
<i class="fa fa-times" bs-tooltip="tooltip.title" data-placement="right" title="Delete Token"></i>
</span>
</td>
</tr>
@ -246,7 +263,7 @@
<!-- Modal message dialog -->
<div class="modal fade" id="onlyadminModal">
<div class="modal fade" id="channgechangepermModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
@ -254,7 +271,8 @@
<h4 class="modal-title">Cannot change permissions</h4>
</div>
<div class="modal-body">
The selected permissions could not be changed because the user is the only <b>admin</b> on the repo.
<span ng-show="!changePermError">You do not have permission to change the permissions on the repository.</span>
<span ng-show="changePermError">{{ changePermError }}</span>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
@ -283,4 +301,24 @@
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<!-- Modal message dialog -->
<div class="modal fade" id="confirmaddoutsideModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Add User?</h4>
</div>
<div class="modal-body">
The selected user is outside of your organization. Are you sure you want to grant the user access to this repository?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" ng-click="grantRole()">Yes, I'm sure</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
</div>

View file

@ -4,25 +4,41 @@
<div class="container ready-indicator" ng-show="!loading" data-status="{{ loading ? '' : 'ready' }}">
<div class="repo-list" ng-show="!user.anonymous">
<a href="/new/">
<button class="btn btn-success" style="float: right">
<i class="fa fa-upload user-tool" title="Create new repository"></i>
Create Repository
</button>
</a>
<div ng-class="user.organizations.length ? 'section-header' : ''">
<div class="button-bar-right">
<a href="/new/">
<button class="btn btn-success">
<i class="fa fa-upload user-tool" title="Create new repository"></i>
Create Repository
</button>
</a>
<a href="/organization/{{ namespace }}" ng-show="namespace != user.username">
<button class="btn btn-default">
<i class="fa fa-group user-tool"></i>
View Organization
</button>
</a>
</div>
<span class="namespace-selector" user="user" namespace="namespace" ng-show="user.organizations"></span>
</div>
<h3>Your Repositories</h3>
<div ng-show="private_repositories.length > 0">
<div class="repo-listing" ng-repeat="repository in private_repositories">
<h3 ng-show="namespace == user.username">Your Repositories</h3>
<h3 ng-show="namespace != user.username">Repositories</h3>
<div ng-show="user_repositories.length > 0">
<div class="repo-listing" ng-repeat="repository in user_repositories">
<span class="repo-circle no-background" repo="repository"></span>
<a ng-href="/repository/{{repository.namespace}}/{{ repository.name }}">{{repository.namespace}}/{{repository.name}}</a>
<div class="description" ng-bind-html-unsafe="getCommentFirstLine(repository.description)"></div>
<div class="description markdown-view" content="repository.description" first-line-only="true"></div>
</div>
</div>
<div ng-show="private_repositories.length == 0" style="padding:20px;">
<div ng-show="user_repositories.length == 0" style="padding:20px;">
<div class="alert alert-info">
<h4>You don't have any repositories yet!</h4>
<h4 ng-show="namespace == user.username">You don't have any repositories yet!</h4>
<h4 ng-show="namespace != user.username">This organization doesn't have any repositories, or you have not been provided access.</h4>
<a href="/guide"><b>Click here</b> to learn how to create a repository</a>
</div>
@ -34,7 +50,7 @@
<div class="repo-listing" ng-repeat="repository in public_repositories">
<span class="repo-circle no-background" repo="repository"></span>
<a ng-href="/repository/{{repository.namespace}}/{{ repository.name }}">{{repository.namespace}}/{{repository.name}}</a>
<div class="description" ng-bind-html-unsafe="getCommentFirstLine(repository.description)"></div>
<div class="description markdown-view" content="repository.description" first-line-only="true"></div>
</div>
</div>
</div>

View file

@ -12,22 +12,7 @@
</div>
<div id="collapseSignin" class="panel-collapse collapse in">
<div class="panel-body">
<form class="form-signin" ng-submit="signin();">
<input type="text" class="form-control input-lg" name="username" placeholder="Username" ng-model="user.username" autofocus>
<input type="password" class="form-control input-lg" name="password" placeholder="Password" ng-model="user.password">
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign In</button>
<span class="social-alternate">
<i class="fa fa-circle"></i>
<span class="inner-text">OR</span>
</span>
<a id='github-signin-link' href="https://github.com/login/oauth/authorize?client_id={{ githubClientId }}&scope=user:email{{ mixpanelDistinctIdClause }}" class="btn btn-primary btn-lg btn-block"><i class="fa fa-github fa-lg"></i> Sign In with GitHub</a>
</form>
<div class="alert alert-danger" ng-show="invalidCredentials">Invalid username or password.</div>
<div class="alert alert-danger" ng-show="needsEmailVerification">You must verify your email address before you can sign in.</div>
<div class="signin-form"></div>
</div>
</div>
</div>
@ -56,17 +41,3 @@
</div>
</div>
</div>
<!-- <script type="text/javascript">
function appendMixpanelId() {
if (mixpanel.get_distinct_id !== undefined) {
var signinLink = document.getElementById("github-signin-link");
signinLink.href += ("&state=" + mixpanel.get_distinct_id());
} else {
// Mixpanel not yet loaded, try again later
window.setTimeout(appendMixpanelId, 200);
}
};
appendMixpanelId();
</script> -->

View file

@ -0,0 +1,79 @@
<div class="loading" ng-show="loading">
<i class="fa fa-spinner fa-spin fa-3x"></i>
</div>
<div class="loading" ng-show="!loading && !organization">
No matching team found
</div>
<div class="team-view container" ng-show="!loading && organization">
<div class="organization-header" organization="organization" team-name="teamname"></div>
<div class="description markdown-input" content="team.description" can-write="organization.is_admin"
content-changed="updateForDescription" field-title="'team description'"></div>
<div class="panel panel-default">
<div class="panel-heading">Team Members
<i class="info-icon fa fa-info-circle" data-placement="left" data-content="Users that inherit all permissions delegated to this team"></i>
</div>
<div class="panel-body">
<table class="permissions">
<tr ng-repeat="(name, member) in members">
<td class="user entity">
<i class="fa fa-user"></i>
<span>{{ member.username }}</span>
</td>
<td>
<span class="delete-ui" tabindex="0" title="Remove User" ng-show="canEditMembers">
<span class="delete-ui-button" ng-click="removeMember(member.username)"><button class="btn btn-danger">Remove</button></span>
<i class="fa fa-times"></i>
</span>
</td>
</tr>
<tr ng-show="canEditMembers">
<td colspan="2">
<span class="entity-search" organization="''" input-title="'Add a user...'" entity-selected="addNewMember"></span>
</td>
</tr>
</table>
</div>
</div>
</div>
<!-- Modal message dialog -->
<div class="modal fade" id="cannotChangeTeamModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Cannot change team</h4>
</div>
<div class="modal-body">
You do not have permission to change properties of this team.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<!-- Modal message dialog -->
<div class="modal fade" id="cannotChangeMembersModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Cannot change members</h4>
</div>
<div class="modal-body">
You do not have permission to change the members of this team.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->

View file

@ -1,80 +1,181 @@
<div class="container user-admin">
<div class="loading" ng-show="planLoading || planChanging">
<i class="fa fa-spinner fa-spin fa-3x"></i>
</div>
<div class="row" ng-show="errorMessage">
<div class="col-md-12">
<div class="alert alert-danger">{{ errorMessage }}</div>
<div class="loading" ng-show="loading">
<i class="fa fa-spinner fa-spin fa-3x"></i>
</div>
<div class="loading" ng-show="!loading && !user">
No matching user found
</div>
<div class="user-admin container" ng-show="!loading && user">
<div class="row">
<div class="organization-header-element">
<img src="//www.gravatar.com/avatar/{{ user.gravatar }}?s=24&amp;d=identicon">
<span class="organization-name">
{{ user.username }}
</span>
</div>
</div>
<div class="row" ng-show="askForPassword">
<div class="col-md-12">
<div class="alert alert-warning">Your account does not currently have a password. You will need to create a password before you will be able to <strong>push</strong> or <strong>pull</strong> repositories.</div>
</div>
</div>
<div class="row" ng-hide="planLoading">
<div class="col-md-3" ng-repeat='plan in plans'>
<div class="panel" ng-class="{'panel-success': subscription.plan == plan.stripeId, 'panel-default': subscription.plan != plan.stripeId}">
<div class="panel-heading">
{{ plan.title }}
<span class="pull-right" ng-show="subscription.plan == plan.stripeId">
<i class="fa fa-ok"></i>
Subscribed
</span>
</div>
<div class="panel-body panel-plan">
<div class="plan-price">${{ plan.price / 100 }}</div>
<div class="plan-description"><b>{{ plan.privateRepos }}</b> Private Repositories</div>
<div ng-switch='plan.stripeId'>
<div ng-switch-when='free'>
<button class="btn button-hidden">Hidden!</button>
</div>
<div ng-switch-default>
<button class="btn btn-primary" ng-show="subscription.plan === 'free'" ng-click="subscribe(plan.stripeId)">Subscribe</button>
<button class="btn btn-default" ng-hide="subscription.plan === 'free' || subscription.plan === plan.stripeId" ng-click="changeSubscription(plan.stripeId)">Change</button>
<button class="btn btn-danger" ng-show="subscription.plan === plan.stripeId" ng-click="cancelSubscription()">Cancel</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row" ng-show="subscription">
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
Plan Usage
</div>
<div class="panel-body">
<div class="used-description">
<b>{{ subscription.usedPrivateRepos }}</b> of <b>{{ subscribedPlan.privateRepos }}</b> private repositories used
</div>
<div class="progress">
<div ng-class="'progress-bar ' + (planUsagePercent > 90 ? 'progress-bar-danger' : '')" role="progressbar" aria-valuenow="{{ subscription.usedPrivateRepos }}" aria-valuemin="0" aria-valuemax="{{ subscribedPlan.privateRepos }}" style="width: {{ planUsagePercent }}%;">
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="loading" ng-show="updatingUser">
<i class="fa fa-spinner fa-spin fa-3x"></i>
<!-- Side tabs -->
<div class="col-md-2">
<ul class="nav nav-pills nav-stacked">
<li class="active"><a href="javascript:void(0)" data-toggle="tab" data-target="#plan">Plan and Usage</a></li>
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#password">Set Password</a></li>
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#migrate" id="migrateTab">Convert to Organization</a></li>
</ul>
</div>
<div class="col-md-3">
<div class="panel panel-default">
<div class="panel-heading">
Change Password
<!-- Content -->
<div class="col-md-10">
<div class="tab-content">
<!-- Plans tab -->
<div id="plan" class="tab-pane active">
<div class="plan-manager" user="user.username" ready-for-plan="readyForPlan()"></div>
</div>
<div class="panel-body">
<form class="form-change-pw" name="changePasswordForm" ng-submit="changePassword()" data-trigger="manual" data-content="{{ changePasswordError }}" data-placement="right" ng-show="!awaitingConfirmation && !registering">
<input type="password" class="form-control" placeholder="Your new password" ng-model="user.password" required>
<input type="password" class="form-control" placeholder="Verify your new password" ng-model="user.repeatPassword" match="user.password" required>
<button class="btn btn-danger" ng-disabled="changePasswordForm.$invalid" type="submit" analytics-on analytics-event="register">Change Password</button>
<span class="help-block" ng-show="changePasswordSuccess">Password changed successfully</span>
</form>
<!-- Change password tab -->
<div id="password" class="tab-pane">
<div class="loading" ng-show="updatingUser">
<i class="fa fa-spinner fa-spin fa-3x"></i>
</div>
<div class="row">
<form class="form-change-pw col-md-6" name="changePasswordForm" ng-submit="changePassword()" data-trigger="manual"
data-content="{{ changePasswordError }}" data-placement="right" ng-show="!awaitingConfirmation && !registering">
<input type="password" class="form-control" placeholder="Your new password" ng-model="user.password" required>
<input type="password" class="form-control" placeholder="Verify your new password" ng-model="user.repeatPassword"
match="user.password" required>
<button class="btn btn-danger" ng-disabled="changePasswordForm.$invalid" type="submit"
analytics-on analytics-event="register">Change Password</button>
<span class="help-block" ng-show="changePasswordSuccess">Password changed successfully</span>
</form>
</div>
</div>
<!-- Convert to organization tab -->
<div id="migrate" class="tab-pane">
<!-- Step 0 -->
<div class="panel" ng-show="convertStep == 0">
<div class="panel-body" ng-show="user.organizations.length > 0">
<div class="alert alert-info">
Cannot convert this account into an organization, as it is a member of {{user.organizations.length}} other
organization{{user.organizations.length > 1 ? 's' : ''}}. Please leave
{{user.organizations.length > 1 ? 'those organizations' : 'that organization'}} first.
</div>
</div>
<div class="panel-body" ng-show="user.organizations.length == 0">
<div class="alert alert-danger">
Converting a user account into an organization <b>cannot be undone</b>.<br> Here be many fire-breathing dragons!
</div>
<button class="btn btn-danger" ng-click="showConvertForm()">Start conversion process</button>
</div>
</div>
<!-- Step 1 -->
<div class="convert-form" ng-show="convertStep == 1">
<h3>Convert to organization</h3>
<form method="post" name="convertForm" id="convertForm" ng-submit="convertToOrg()">
<div class="form-group">
<label for="orgName">Organization Name</label>
<div class="existing-data">
<img src="//www.gravatar.com/avatar/{{ user.gravatar }}?s=24&amp;d=identicon">
{{ user.username }}</div>
<span class="description">This will continue to be the namespace for your repositories</span>
</div>
<div class="form-group">
<label for="orgName">Admin User</label>
<input id="adminUsername" name="adminUsername" type="text" class="form-control" placeholder="Admin Username"
ng-model="org.adminUser" required autofocus>
<input id="adminPassword" name="adminPassword" type="password" class="form-control" placeholder="Admin Password"
ng-model="org.adminPassword" required>
<span class="description">The username and password for an <b>existing account</b> that will become administrator of the organization</span>
</div>
<!-- Plans Table -->
<div class="form-group plan-group">
<label>Organization Plan</label>
<div class="plans-table" plans="orgPlans" current-plan="org.plan"></div>
</div>
<div class="button-bar">
<button class="btn btn-large btn-danger" type="submit" ng-disabled="convertForm.$invalid || !org.plan">
Convert To Organization
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Modal message dialog -->
<div class="modal fade" id="cannotconvertModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Cannot convert account</h4>
</div>
<div class="modal-body">
Your account could not be converted. Please try again in a moment.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<!-- Modal message dialog -->
<div class="modal fade" id="invalidadminModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Username or password invalid</h4>
</div>
<div class="modal-body">
The username or password specified for the admin account is not valid.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<!-- Modal message dialog -->
<div class="modal fade" id="reallyconvertModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Convert to organization?</h4>
</div>
<div class="modal-body">
<div class="alert alert-danger">You will not be able to login to this account once converted</div>
<div>Are you <b>absolutely sure</b> you would like to convert this account to an organization? Once done, there is no going back.</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal" ng-click="reallyConvert()">Absolutely: Convert Now</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->

View file

@ -14,7 +14,7 @@
<span style="color: #aaa;"> {{repo.namespace}}</span> <span style="color: #ccc">/</span> {{repo.name}}
<span class="settings-cog" ng-show="repo.can_admin" title="Repository Settings">
<span class="settings-cog" ng-show="repo.can_admin" title="Repository Settings" bs-tooltip="tooltip.title" data-placement="bottom">
<a href="{{ '/repository/' + repo.namespace + '/' + repo.name + '/admin' }}">
<i class="fa fa-cog fa-lg"></i>
</a>
@ -52,12 +52,8 @@
</div>
<!-- Description -->
<div class="description">
<p ng-class="'lead ' + (repo.can_write ? 'editable' : 'noteditable')" ng-click="editDescription()">
<span class="content" ng-bind-html-unsafe="getMarkedDown(repo.description)"></span>
<i class="fa fa-edit"></i>
</p>
</div>
<div class="description markdown-input" content="repo.description" can-write="repo.can_write"
content-changed="updateForDescription" field-title="'repository description'"></div>
<!-- Empty message -->
<div class="repo-content" ng-show="!currentTag.image && !repo.is_building">
@ -79,7 +75,7 @@
<div class="panel panel-default">
<div class="panel-heading">
<!-- Tag dropdown -->
<div class="tag-dropdown dropdown" title="Tags">
<div class="tag-dropdown dropdown" title="Tags" bs-tooltip="tooltip.title" data-placement="top">
<i class="fa fa-tag"><span class="tag-count">{{getTagCount(repo)}}</span></i>
<a href="javascript:void(0)" class="dropdown-toggle" data-toggle="dropdown">{{currentTag.name}} <b class="caret"></b></a>
<ul class="dropdown-menu">
@ -107,7 +103,7 @@
<div class="panel panel-default">
<div class="panel-heading">
<!-- Image dropdown -->
<div class="tag-dropdown dropdown" title="Images">
<div class="tag-dropdown dropdown" title="Images" bs-tooltip="tooltip.title" data-placement="top">
<i class="fa fa-archive"><span class="tag-count">{{imageHistory.length}}</span></i>
<a href="javascript:void(0)" class="dropdown-toggle" data-toggle="dropdown">{{currentImage.id.substr(0, 12)}} <b class="caret"></b></a>
<ul class="dropdown-menu">
@ -122,7 +118,8 @@
<div class="panel-body">
<div id="current-image">
<div ng-show="currentImage.comment">
<blockquote style="margin-top: 10px;" ng-bind-html-unsafe="getMarkedDown(currentImage.comment)">
<blockquote style="margin-top: 10px;">
<span class="markdown-view" content="currentImage.comment"></span>
</blockquote>
</div>
@ -141,15 +138,18 @@
<div class="changes-container small-changes-container"
ng-show="currentImageChanges.changed.length || currentImageChanges.added.length || currentImageChanges.removed.length">
<div class="changes-count-container accordion-toggle" data-toggle="collapse" data-parent="#accordion" data-target="#collapseChanges">
<span class="change-count added" ng-show="currentImageChanges.added.length > 0" title="Files Added">
<span class="change-count added" ng-show="currentImageChanges.added.length > 0" title="Files Added"
bs-tooltip="tooltip.title" data-placement="top">
<i class="fa fa-plus-square"></i>
<b>{{currentImageChanges.added.length}}</b>
</span>
<span class="change-count removed" ng-show="currentImageChanges.removed.length > 0" title="Files Removed">
<span class="change-count removed" ng-show="currentImageChanges.removed.length > 0" title="Files Removed"
bs-tooltip="tooltip.title" data-placement="top">
<i class="fa fa-minus-square"></i>
<b>{{currentImageChanges.removed.length}}</b>
</span>
<span class="change-count changed" ng-show="currentImageChanges.changed.length > 0" title="Files Changed">
<span class="change-count changed" ng-show="currentImageChanges.changed.length > 0" title="Files Changed"
bs-tooltip="tooltip.title" data-placement="top">
<i class="fa fa-pencil-square"></i>
<b>{{currentImageChanges.changed.length}}</b>
</span>
@ -182,29 +182,4 @@
</div>
</div>
</div>
<!-- Modal edit for the description -->
<div class="modal fade" id="editModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Edit Repository Description</h4>
</div>
<div class="modal-body">
<div class="wmd-panel">
<div id="wmd-button-bar-description"></div>
<textarea class="wmd-input" id="wmd-input-description" placeholder="Enter description">{{ repo.description }}</textarea>
</div>
<div id="wmd-preview-description" class="wmd-panel wmd-preview"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" ng-click="saveDescription()">Save changes</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
</div>