Merge master into branch
|
@ -9,33 +9,131 @@
|
|||
}
|
||||
}
|
||||
|
||||
.repo-search {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.repo-search {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#quay-logo {
|
||||
width: 80px;
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
#padding-container {
|
||||
padding: 20px;
|
||||
padding-top: 20px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
.d3-tip {
|
||||
position: absolute;
|
||||
left: -100000px;
|
||||
}
|
||||
|
||||
#co-l-footer-wrapper {
|
||||
clear: both;
|
||||
min-height: 100%;
|
||||
height: auto !important;
|
||||
height: 100%;
|
||||
margin-bottom: -64px;
|
||||
}
|
||||
|
||||
#co-l-footer-wrapper #co-l-footer-push {
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
#co-l-footer img {
|
||||
height: 50px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
#co-l-footer .col-md-4 {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#co-l-footer {
|
||||
clear: both;
|
||||
position: relative;
|
||||
background-color: white;
|
||||
height: 64px;
|
||||
min-height: 64px;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.co-img-bg-network {
|
||||
background: url('/static/img/network-tile.png') left top repeat, linear-gradient(30deg, #2277ad, #144768) no-repeat left top fixed;
|
||||
background-color: #2277ad;
|
||||
background-size: auto, 100% 100%;
|
||||
}
|
||||
|
||||
.co-m-navbar {
|
||||
background-color: white;
|
||||
margin: 0;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.co-fx-box-shadow {
|
||||
-webkit-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
|
||||
-moz-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
|
||||
-ms-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
|
||||
-o-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
|
||||
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.co-fx-box-shadow-heavy {
|
||||
-webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.4);
|
||||
-moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.4);
|
||||
-ms-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.4);
|
||||
-o-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.4);
|
||||
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.main-panel {
|
||||
margin-bottom: 20px;
|
||||
background-color: #fff;
|
||||
border: 1px solid transparent;
|
||||
padding: 30px;
|
||||
|
||||
-webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.4);
|
||||
-moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.4);
|
||||
-ms-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.4);
|
||||
-o-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.4);
|
||||
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: none !important;
|
||||
}
|
||||
|
||||
nav.navbar {
|
||||
border: 0px;
|
||||
border-radius: 0px;
|
||||
background-image: linear-gradient(to top, #535C66 0%,#6E8194 100%);
|
||||
}
|
||||
|
||||
nav.navbar-default .navbar-brand {
|
||||
padding-left: 14px;
|
||||
border-right: 1px solid rgb(134, 140, 163);
|
||||
padding-right: 14px;
|
||||
padding-top: 5px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
nav.navbar-default .navbar-nav>li>a {
|
||||
color: white;
|
||||
letter-spacing: 0.5px;
|
||||
color: #428bca;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
nav.navbar-default .navbar-nav>li>a.active {
|
||||
color: #f04c5c;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-nav>li>a:hover, .navbar-default .navbar-nav>li>a:focus {
|
||||
color: #BEE1FF;
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-nav>.open>a, .navbar-default .navbar-nav>.open>a:hover, .navbar-default .navbar-nav>.open>a:focus {
|
||||
cursor: pointer;
|
||||
background: rgba(255, 255, 255, 0.4) !important;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.notification-view-element {
|
||||
|
@ -366,6 +464,22 @@ i.toggle-icon:hover {
|
|||
|
||||
.docker-auth-dialog .token-dialog-body .well {
|
||||
margin-bottom: 0px;
|
||||
position: relative;
|
||||
padding-right: 24px;
|
||||
}
|
||||
|
||||
.docker-auth-dialog .token-dialog-body .well i.fa-refresh {
|
||||
position: absolute;
|
||||
top: 9px;
|
||||
right: 9px;
|
||||
font-size: 20px;
|
||||
color: gray;
|
||||
transition: all 0.5s ease-in-out;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.docker-auth-dialog .token-dialog-body .well i.fa-refresh:hover {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.docker-auth-dialog .token-view {
|
||||
|
@ -399,17 +513,6 @@ i.toggle-icon:hover {
|
|||
margin: 0 auto -176px;
|
||||
}
|
||||
|
||||
.footer-container, .push {
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.footer-container.fixed {
|
||||
position: fixed;
|
||||
bottom: 16px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.button-hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
@ -489,6 +592,14 @@ i.toggle-icon:hover {
|
|||
line-height: 25px;
|
||||
}
|
||||
|
||||
.logs-view-element .log .log-description code {
|
||||
max-width: 300px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.logs-view-element .log-performer {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
@ -634,7 +745,7 @@ i.toggle-icon:hover {
|
|||
}
|
||||
|
||||
.user-notification.notification-animated {
|
||||
width: 21px;
|
||||
min-width: 21px;
|
||||
|
||||
transform: scale(0);
|
||||
-moz-transform: scale(0);
|
||||
|
@ -671,12 +782,12 @@ i.toggle-icon:hover {
|
|||
.user-tools .user-tool {
|
||||
font-size: 24px;
|
||||
margin-top: 14px;
|
||||
color: white;
|
||||
color: #428bca;
|
||||
}
|
||||
|
||||
.user-tools i.user-tool:hover {
|
||||
cursor: pointer;
|
||||
color: #BEE1FF;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.status-box a {
|
||||
|
@ -728,7 +839,7 @@ i.toggle-icon:hover {
|
|||
background-color: red;
|
||||
}
|
||||
|
||||
.phase-icon.waiting, .phase-icon.starting, .phase-icon.initializing {
|
||||
.phase-icon.waiting, .phase-icon.unpacking, .phase-icon.starting, .phase-icon.initializing {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
|
@ -1000,12 +1111,12 @@ i.toggle-icon:hover {
|
|||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
.plans-list .plan.bus-small {
|
||||
.plans-list .plan.bus-small, .plans-list .plan.bus-coreos-trial {
|
||||
border-top: 6px solid #46ac39;
|
||||
margin-top: -10px;
|
||||
}
|
||||
|
||||
.plans-list .plan.bus-small .plan-box {
|
||||
.plans-list .plan.bus-small .plan-box, .plans-list .plan.bus-coreos-trial .plan-box {
|
||||
background: black !important;
|
||||
}
|
||||
|
||||
|
@ -1040,6 +1151,10 @@ i.toggle-icon:hover {
|
|||
display: inline;
|
||||
}
|
||||
|
||||
.hidden-xs-inline {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
@media (min-width: 991px) {
|
||||
.visible-md-inline {
|
||||
display: inline;
|
||||
|
@ -1056,6 +1171,13 @@ i.toggle-icon:hover {
|
|||
}
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
.hidden-xs-inline {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.visible-xl {
|
||||
display: none;
|
||||
}
|
||||
|
@ -1085,7 +1207,7 @@ i.toggle-icon:hover {
|
|||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.plans-list .plan.bus-small button {
|
||||
.plans-list .plan.bus-small button, .plans-list .plan.bus-coreos-trial button {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
|
@ -1230,14 +1352,64 @@ i.toggle-icon:hover {
|
|||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.plans .plan-faq dd{
|
||||
.plans .plan-faq dd {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.enterprise-plan .plan-combine {
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.enterprise-plan .plan-combine .plus {
|
||||
font-size: 22px;
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.enterprise-plan a {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.enterprise-plan .plan-combine img {
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
.enterprise-tour .tour-section {
|
||||
margin-bottom: 50px !important;
|
||||
padding-bottom: 50px !important;
|
||||
border-bottom: 1px solid #eee !important;
|
||||
}
|
||||
|
||||
.enterprise-tour .tour-section p {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.enterprise-tour .btn {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.feature-illustration {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.feature-illustration svg {
|
||||
margin: 0 auto;
|
||||
width: auto !important;
|
||||
max-width: 100%;
|
||||
max-height: 110px;
|
||||
}
|
||||
|
||||
.loading {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.jumbotron {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.jumbotron .disclaimer-link {
|
||||
font-size: .3em;
|
||||
vertical-align: 23px;
|
||||
|
@ -1255,25 +1427,19 @@ i.toggle-icon:hover {
|
|||
color: #555;
|
||||
}
|
||||
|
||||
.landing-page .wrapper > nav {
|
||||
display: none;
|
||||
.landing-page #padding-container {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.landing-page .nav > li > a {
|
||||
border-radius: 4px;
|
||||
.landing-page .main-panel {
|
||||
padding: 0px;
|
||||
border: 0px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.landing-page .nav > li > a:hover, .landing-page .nav > li > a:focus {
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.landing-page .nav .user-view {
|
||||
color: white !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.landing-page .user-tool {
|
||||
color: white;
|
||||
.landing-page.signedin .main-panel {
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.landing {
|
||||
|
@ -1284,10 +1450,6 @@ i.toggle-icon:hover {
|
|||
font-size: 14px;
|
||||
}
|
||||
|
||||
.landing-content {
|
||||
|
||||
}
|
||||
|
||||
.landing-background {
|
||||
z-index: 0;
|
||||
|
||||
|
@ -1297,10 +1459,13 @@ i.toggle-icon:hover {
|
|||
left: 0px;
|
||||
right: 0px;
|
||||
|
||||
background-color: #1d1d1d;
|
||||
background-image: url(../img/landing-back-opt.jpg);
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background: url('/static/img/network-tile.png') left top repeat, linear-gradient(30deg, #2277ad, #144768) no-repeat left top fixed;
|
||||
background-color: #2277ad;
|
||||
background-size: auto, 100% 100%;
|
||||
}
|
||||
|
||||
.landing-page.signedin .landing-background {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.landing-filter {
|
||||
|
@ -1320,6 +1485,55 @@ i.toggle-icon:hover {
|
|||
z-index: 2;
|
||||
}
|
||||
|
||||
.landing .call-to-action i.fa {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.landing .call-to-action {
|
||||
height: 40px;
|
||||
font-size: 18px;
|
||||
padding-left: 14px;
|
||||
padding-right: 14px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
|
||||
background: rgba(15, 131, 203, 0.6);
|
||||
display: inline-block;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.landing .announcement {
|
||||
position: absolute;
|
||||
z-index: 9;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
|
||||
display: block;
|
||||
background: rgba(8, 61, 95, 0.6);
|
||||
min-height: 45px;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
line-height: 45px;
|
||||
}
|
||||
|
||||
.landing .announcement .spacer {
|
||||
display: inline-block;
|
||||
width: 45px;
|
||||
}
|
||||
|
||||
.landing .announcement img {
|
||||
height: 45px;
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
.landing .announcement .plus {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.landing {
|
||||
color: white;
|
||||
|
||||
|
@ -1346,104 +1560,6 @@ i.toggle-icon:hover {
|
|||
font-size: 40px;
|
||||
}
|
||||
|
||||
.landing .header-bar .navbar-brand {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.landing .header-bar form {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.landing .header-bar {
|
||||
font-size: 16px;
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 20px;
|
||||
color: white;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.landing .header-bar .user-tools a {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.landing .header-bar .user-tools i {
|
||||
margin-top: 0px;
|
||||
padding: 12px;
|
||||
border-radius: 4px;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.landing .header-bar .user-tools i:hover {
|
||||
background: rgba(255, 255, 255, 0.2) !important;
|
||||
}
|
||||
|
||||
.landing .navbar-links a {
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
border-radius: 6px;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.landing .navbar-links li a:hover {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.landing .nav .dropdown-menu a {
|
||||
color: black;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
@media (max-width: 971px) {
|
||||
.landing .navbar-collapse {
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.navbar-header {
|
||||
float: none;
|
||||
}
|
||||
|
||||
.navbar-toggle {
|
||||
display: block;
|
||||
color: white;
|
||||
font-size: 48px;
|
||||
line-height: 28px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.navbar-collapse {
|
||||
border-top: 1px solid transparent;
|
||||
box-shadow: inset 0 1px 0 rgba(255,255,255,0.1);
|
||||
}
|
||||
|
||||
.navbar-collapse.collapse {
|
||||
display: none!important;
|
||||
}
|
||||
|
||||
.navbar-nav {
|
||||
float: none!important;
|
||||
margin: 7.5px -15px;
|
||||
}
|
||||
|
||||
.navbar-nav>li {
|
||||
float: none;
|
||||
}
|
||||
|
||||
.navbar-nav>li>a {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.navbar-collapse.collapse.in { display: block!important; }
|
||||
}
|
||||
|
||||
.landing .messages b {
|
||||
color: #59B2FF;
|
||||
}
|
||||
|
||||
.landing .messages h1 {
|
||||
font-size: 48px;
|
||||
}
|
||||
|
@ -1651,10 +1767,15 @@ form input.ng-valid.ng-dirty,
|
|||
font-size: 26px;
|
||||
}
|
||||
|
||||
.page-footer {
|
||||
padding: 10px;
|
||||
padding-bottom: 0px;
|
||||
border-top: 1px solid #eee;
|
||||
.footer-container, .push {
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.footer-container.fixed {
|
||||
position: fixed;
|
||||
bottom: 16px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.page-footer-padder {
|
||||
|
@ -1838,6 +1959,7 @@ p.editable:hover i {
|
|||
}
|
||||
|
||||
.right-tag-controls {
|
||||
cursor: default;
|
||||
display: inline-block;
|
||||
float: right;
|
||||
padding: 4px;
|
||||
|
@ -2151,6 +2273,14 @@ p.editable:hover i {
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.copy-box-element.disabled .input-group-addon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.copy-box-element.disabled input {
|
||||
border-radius: 4px !important;
|
||||
}
|
||||
|
||||
.global-zeroclipboard-container embed {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@ -3141,6 +3271,10 @@ p.editable:hover i {
|
|||
display: inline-block;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.billing-invoices-element .invoice-title {
|
||||
padding: 6px;
|
||||
cursor: pointer;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="copy-box-element">
|
||||
<div class="copy-box-element" ng-class="disabled ? 'disabled' : ''">
|
||||
<div class="id-container">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" value="{{ value }}" readonly>
|
||||
|
|
|
@ -10,19 +10,33 @@
|
|||
</div>
|
||||
<div class="modal-body token-dialog-body">
|
||||
<div class="alert alert-info">The docker <u>username</u> is <b>{{ username }}</b> and the <u>password</u> is the token below. You may use any value for email.</div>
|
||||
<div class="well well-sm">
|
||||
|
||||
<div class="well well-sm" ng-show="regenerating">
|
||||
Regenerating Token...
|
||||
<i class="fa fa-refresh fa-spin"></i>
|
||||
</div>
|
||||
|
||||
<div class="well well-sm" ng-show="!regenerating">
|
||||
<input id="token-view" class="token-view" type="text" value="{{ token }}" onClick="this.select();" readonly>
|
||||
<i class="fa fa-refresh" ng-show="supportsRegenerate" ng-click="askRegenerate()"
|
||||
data-title="Regenerate Token"
|
||||
data-placement="left"
|
||||
bs-tooltip></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="modal-footer" ng-show="regenerating">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
<div class="modal-footer" ng-show="!regenerating">
|
||||
<span class="download-cfg" ng-show="isDownloadSupported()">
|
||||
<i class="fa fa-download"></i>
|
||||
<a href="javascript:void(0)" ng-click="downloadCfg(shownRobot)">Download .dockercfg file</a>
|
||||
</span>
|
||||
<div id="clipboardCopied" style="display: none">
|
||||
Copied to clipboard
|
||||
<div class="clipboard-copied-message" style="display: none">
|
||||
Copied
|
||||
</div>
|
||||
<button id="copyClipboard" type="button" class="btn btn-primary" data-clipboard-target="token-view">Copy to clipboard</button>
|
||||
<input type="hidden" name="command-data" id="command-data" value="{{ command }}">
|
||||
<button id="copyClipboard" type="button" class="btn btn-primary" data-clipboard-target="command-data">Copy Login Command</button>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
|
|
|
@ -4,19 +4,19 @@
|
|||
≡
|
||||
</button>
|
||||
<a class="navbar-brand" href="/" target="{{ appLinkTarget() }}">
|
||||
<img src="/static/img/quay-box-white.png" data-title="Quay.io" data-placement="bottom" bs-tooltip>
|
||||
<img id="quay-logo" src="/static/img/black-horizontal.svg">
|
||||
</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() }}">Tour</a></li>
|
||||
<li><a ng-href="/repository/" target="{{ appLinkTarget() }}">Repositories</a></li>
|
||||
<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() }}">Tutorial</a></li>
|
||||
<li quay-require="['BILLING']"><a ng-href="/plans/" target="{{ appLinkTarget() }}">Pricing</a></li>
|
||||
<li><a ng-href="{{ user.organizations.length ? '/organizations/' : '/tour/organizations/' }}" target="{{ appLinkTarget() }}">Organizations</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>
|
||||
|
||||
|
||||
|
@ -37,15 +37,7 @@
|
|||
<a href="javascript:void(0)" class="dropdown-toggle user-dropdown user-view" data-toggle="dropdown">
|
||||
<img src="//www.gravatar.com/avatar/{{ user.gravatar }}?s=32&d=identicon" />
|
||||
{{ user.username }}
|
||||
<span class="badge user-notification notification-animated"
|
||||
ng-show="notificationService.notifications.length"
|
||||
ng-class="notificationService.notificationClasses"
|
||||
bs-tooltip=""
|
||||
data-title="User Notifications"
|
||||
data-placement="left"
|
||||
data-container="body">
|
||||
{{ notificationService.notifications.length }}
|
||||
</span>
|
||||
<span class="notifications-bubble"></span>
|
||||
<b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
|
@ -58,11 +50,7 @@
|
|||
<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="badge user-notification"
|
||||
ng-class="notificationService.notificationClasses"
|
||||
ng-show="notificationService.notifications.length">
|
||||
{{ notificationService.notifications.length }}
|
||||
</span>
|
||||
<span class="notifications-bubble"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li><a ng-href="/organizations/" target="{{ appLinkTarget() }}">Organizations</a></li>
|
||||
|
|
|
@ -37,7 +37,8 @@
|
|||
<input id="log-filter" class="form-control" placeholder="Filter Logs" type="text" ng-model="search.$">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="table-container">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<th>Description</th>
|
||||
|
@ -77,5 +78,6 @@
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
<div class="aside-content">
|
||||
<div class="aside-header">
|
||||
<button type="button" class="close" ng-click="$hide()">×</button>
|
||||
<h4 class="aside-title">Notifications</h4>
|
||||
<h4 class="aside-title">
|
||||
Notifications
|
||||
<span class="notifications-bubble"></span>
|
||||
</h4>
|
||||
</div>
|
||||
<div class="aside-body">
|
||||
<div ng-repeat="notification in notificationService.notifications">
|
||||
|
|
7
static/directives/notifications-bubble.html
Normal file
|
@ -0,0 +1,7 @@
|
|||
<span class="notifications-bubble-element">
|
||||
<span class="badge user-notification notification-animated"
|
||||
ng-show="notificationService.notifications.length"
|
||||
ng-class="notificationService.notificationClasses">
|
||||
{{ notificationService.notifications.length }}<span ng-if="notificationService.additionalNotifications">+</span>
|
||||
</span>
|
||||
</span>
|
|
@ -31,7 +31,7 @@
|
|||
</div>
|
||||
|
||||
<div class="docker-auth-dialog" username="shownRobot.name" token="shownRobot.token"
|
||||
shown="!!shownRobot" counter="showRobotCounter">
|
||||
shown="!!shownRobot" counter="showRobotCounter" supports-regenerate="true" regenerate="regenerateToken(username)">
|
||||
<i class="fa fa-wrench"></i> {{ shownRobot.name }}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -4,16 +4,23 @@
|
|||
placeholder="Username or E-mail Address" 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" quay-require="['GITHUB_LOGIN']">
|
||||
<i class="fa fa-circle"></i>
|
||||
<span class="inner-text">OR</span>
|
||||
</span>
|
||||
|
||||
<div class="external-login-button" provider="github" redirect-url="redirectUrl" sign-in-started="markStarted()"></div>
|
||||
<div class="external-login-button" provider="google" redirect-url="redirectUrl" sign-in-started="markStarted()"></div>
|
||||
</form>
|
||||
<div class="alert alert-warning" ng-show="tryAgainSoon > 0">
|
||||
Too many attempts have been made to login. Please try again in {{ tryAgainSoon }} second<span ng-if="tryAgainSoon != 1">s</span>.
|
||||
</div>
|
||||
|
||||
<span ng-show="tryAgainSoon == 0">
|
||||
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign In</button>
|
||||
|
||||
<span class="social-alternate" quay-show="Features.GITHUB_LOGIN || Features.GOOGLE_LOGIN">
|
||||
<i class="fa fa-circle"></i>
|
||||
<span class="inner-text">OR</span>
|
||||
</span>
|
||||
|
||||
<div class="external-login-button" provider="github" redirect-url="redirectUrl" sign-in-started="markStarted()"></div>
|
||||
<div class="external-login-button" provider="google" redirect-url="redirectUrl" sign-in-started="markStarted()"></div>
|
||||
</span>
|
||||
</form>
|
||||
|
||||
<div class="alert alert-danger" ng-show="invalidCredentials">Invalid username or password.</div>
|
||||
<div class="alert alert-danger" ng-show="needsEmailVerification">
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
</span>
|
||||
<div class="external-login-button" provider="github"></div>
|
||||
<div class="external-login-button" provider="google"></div>
|
||||
<p class="help-block" quay-require="['BILLING']">No credit card required.</p>
|
||||
</div>
|
||||
</form>
|
||||
<div ng-show="registering" style="text-align: center">
|
||||
|
|
|
@ -226,71 +226,208 @@
|
|||
|
||||
|
||||
<!-- Enterprise -->
|
||||
<div class="product-tour" ng-if="kind == 'enterprise'">
|
||||
<div class="product-tour enterprise-tour" ng-if="kind == 'enterprise'">
|
||||
<div class="tour-section row tour-header">
|
||||
<div class="col-md-12">
|
||||
<div class="tour-section-title">Quay.io in your data center</div>
|
||||
<div class="tour-section-title">Run Quay.io Behind Your Firewall</div>
|
||||
<div class="tour-section-description">
|
||||
All of the power of Quay.io, easily deployed to your data center via docker.
|
||||
</div>
|
||||
<div class="tour-section-description">
|
||||
<div class="row">
|
||||
<div class="alert alert-info col-md-4 col-md-offset-4"><strong>docker run quay.io/quay/enterprise</strong></div>
|
||||
<div class="col-lg-6 enterprise-plan col-lg-offset-3">
|
||||
<div class="plan-combine">
|
||||
<img src="/static/img/quay-logo.png">
|
||||
<span class="plus">+</span>
|
||||
<img src="/static/img/coreos.svg" style="height: 50px">
|
||||
</div>
|
||||
Quay.io has partnered with CoreOS to offer <a href="https://coreos.com/products/enterprise-registry">Enterprise Registry</a>, a version
|
||||
of Quay.io that can be hosted behind your firewall.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tour-section row">
|
||||
<div class="col-sm-3 enterprise-icon">
|
||||
<span class="fa-stack fa-5x">
|
||||
<i class="fa fa-circle fa-stack-2x"></i>
|
||||
<i class="fa fa-lock fa-stack-1x fa-inverse"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-sm-9">
|
||||
<div class="tour-section-title">Take control of your own security</div>
|
||||
<div class="tour-section-description">
|
||||
The nature of machine images is that they often contain keys and passwords. We're pretty proud of the <a href="/security/">security</a> of our hosted offering, but we recognize that there are situations, such as compliance or auditing, where you must control your own end to end security. Quay.io Enterprise Edition runs in your own data centers, inside your firewall.
|
||||
<div class="tour-section row features">
|
||||
<div class="col-lg-4 col-md-4 col-sm-4 feature-desc">
|
||||
<div class="feature-illustration">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
preserveAspectRatio="xMinYMin" width="100px" viewBox="0 0 144 144" enable-background="new 0 0 144 144" xml:space="preserve">
|
||||
<path fill="none" stroke="#010101" stroke-width="2" stroke-miterlimit="10" d="M124.979,62.559
|
||||
c0.695,3.413,1.058,6.944,1.058,10.56c0,29.104-23.591,52.695-52.695,52.695c-17.612,0-33.207-8.641-42.776-21.913"/>
|
||||
<path fill="none" stroke="#010101" stroke-width="2" stroke-miterlimit="10" d="M21.319,81.551c-0.44-2.744-0.671-5.561-0.671-8.431
|
||||
c0-29.104,23.591-52.695,52.695-52.695c17.442,0,32.906,8.474,42.497,21.532"/>
|
||||
<polygon fill="#010101" points="122.993,57.123 119.268,67.523 131.435,63.599 "/>
|
||||
<polygon fill="#010101" points="23.006,87.718 26.73,77.318 14.565,81.242 "/>
|
||||
<g enable-background="new ">
|
||||
<path d="M41.5,75.337v-5.679c0-0.204,0.071-0.403,0.215-0.598c0.143-0.194,0.307-0.302,0.491-0.322l4.757-0.737
|
||||
c0.225-0.716,0.552-1.493,0.982-2.332c-0.696-0.982-1.617-2.159-2.762-3.53c-0.144-0.225-0.215-0.43-0.215-0.613
|
||||
c0-0.246,0.071-0.45,0.215-0.614c0.45-0.613,1.289-1.523,2.517-2.731c1.228-1.207,2.036-1.811,2.425-1.811
|
||||
c0.225,0,0.439,0.072,0.645,0.215l3.529,2.762c0.696-0.368,1.483-0.695,2.363-0.981c0.225-2.21,0.46-3.785,0.706-4.727
|
||||
c0.143-0.491,0.45-0.737,0.921-0.737h5.708c0.225,0,0.43,0.077,0.614,0.23c0.185,0.153,0.287,0.333,0.307,0.537l0.706,4.696
|
||||
c0.695,0.204,1.462,0.521,2.302,0.951l3.622-2.731c0.164-0.143,0.368-0.215,0.614-0.215c0.225,0,0.44,0.082,0.645,0.245
|
||||
c2.946,2.722,4.42,4.358,4.42,4.911c0,0.184-0.072,0.379-0.215,0.583c-0.245,0.327-0.675,0.88-1.289,1.657
|
||||
c-0.614,0.778-1.074,1.392-1.382,1.842c0.471,0.982,0.818,1.821,1.044,2.517l4.665,0.706c0.205,0.041,0.379,0.148,0.521,0.322
|
||||
c0.144,0.174,0.215,0.373,0.215,0.599v5.678c0,0.205-0.071,0.404-0.215,0.599c-0.143,0.194-0.307,0.302-0.49,0.322l-4.758,0.736
|
||||
c-0.225,0.717-0.553,1.494-0.982,2.333c0.695,0.981,1.617,2.159,2.763,3.529c0.144,0.205,0.215,0.409,0.215,0.614
|
||||
c0,0.245-0.071,0.439-0.215,0.583c-0.471,0.613-1.315,1.529-2.532,2.747c-1.217,1.217-2.021,1.826-2.409,1.826
|
||||
c-0.225,0-0.44-0.072-0.645-0.215l-3.529-2.763c-0.757,0.389-1.545,0.706-2.363,0.951c-0.226,2.21-0.46,3.796-0.706,4.758
|
||||
c-0.144,0.491-0.45,0.736-0.921,0.736h-5.708c-0.226,0-0.43-0.077-0.614-0.23s-0.287-0.332-0.307-0.537l-0.706-4.695
|
||||
c-0.696-0.204-1.463-0.522-2.302-0.952l-3.622,2.732c-0.144,0.143-0.348,0.215-0.614,0.215c-0.226,0-0.44-0.082-0.645-0.246
|
||||
c-2.946-2.721-4.42-4.358-4.42-4.91c0-0.185,0.072-0.379,0.215-0.584c0.205-0.286,0.624-0.828,1.259-1.626
|
||||
c0.634-0.798,1.115-1.422,1.442-1.872c-0.471-0.9-0.829-1.739-1.074-2.518l-4.665-0.736c-0.205-0.02-0.379-0.117-0.522-0.291
|
||||
C41.571,75.762,41.5,75.562,41.5,75.337z M55.587,66.988c-1.534,1.535-2.302,3.387-2.302,5.556s0.768,4.021,2.302,5.555
|
||||
c1.535,1.535,3.386,2.302,5.556,2.302c2.168,0,4.021-0.767,5.555-2.302C68.233,76.564,69,74.713,69,72.544
|
||||
s-0.767-4.021-2.302-5.556c-1.535-1.534-3.387-2.302-5.555-2.302C58.974,64.687,57.122,65.454,55.587,66.988z M76.857,58.978
|
||||
v-4.297c0-0.327,1.523-0.645,4.572-0.951c0.266-0.593,0.573-1.125,0.922-1.596c-1.044-2.312-1.566-3.724-1.566-4.235
|
||||
c0-0.082,0.041-0.154,0.123-0.215c0.082-0.041,0.439-0.246,1.074-0.614s1.238-0.716,1.811-1.044c0.573-0.326,0.88-0.49,0.922-0.49
|
||||
c0.163,0,0.633,0.476,1.411,1.427c0.777,0.951,1.31,1.642,1.597,2.071c0.408-0.04,0.715-0.061,0.92-0.061s0.512,0.021,0.921,0.061
|
||||
c1.044-1.452,1.984-2.598,2.823-3.438l0.185-0.061c0.081,0,1.351,0.716,3.806,2.148c0.082,0.061,0.123,0.133,0.123,0.215
|
||||
c0,0.512-0.521,1.923-1.565,4.235c0.348,0.471,0.655,1.003,0.921,1.596c3.049,0.307,4.573,0.624,4.573,0.951v4.297
|
||||
c0,0.328-1.524,0.645-4.573,0.952c-0.246,0.552-0.553,1.084-0.921,1.596c1.044,2.312,1.565,3.725,1.565,4.235
|
||||
c0,0.082-0.041,0.153-0.123,0.215c-2.496,1.453-3.765,2.179-3.806,2.179c-0.164,0-0.634-0.48-1.411-1.442
|
||||
c-0.778-0.961-1.311-1.657-1.597-2.087c-0.409,0.041-0.716,0.062-0.921,0.062s-0.512-0.021-0.92-0.062
|
||||
c-0.287,0.43-0.819,1.126-1.597,2.087c-0.778,0.962-1.248,1.442-1.411,1.442c-0.042,0-1.311-0.726-3.807-2.179
|
||||
c-0.082-0.062-0.123-0.133-0.123-0.215c0-0.511,0.522-1.923,1.566-4.235c-0.369-0.512-0.676-1.044-0.922-1.596
|
||||
C78.381,59.622,76.857,59.306,76.857,58.978z M76.857,90.406v-4.297c0-0.327,1.523-0.645,4.572-0.951
|
||||
c0.266-0.594,0.573-1.125,0.922-1.596c-1.044-2.312-1.566-3.725-1.566-4.236c0-0.081,0.041-0.153,0.123-0.215
|
||||
c0.082-0.04,0.439-0.245,1.074-0.613s1.238-0.716,1.811-1.044c0.573-0.327,0.88-0.491,0.922-0.491c0.163,0,0.633,0.477,1.411,1.428
|
||||
c0.777,0.951,1.31,1.642,1.597,2.071c0.408-0.04,0.715-0.062,0.92-0.062s0.512,0.021,0.921,0.062
|
||||
c1.044-1.452,1.984-2.598,2.823-3.438l0.185-0.062c0.081,0,1.351,0.717,3.806,2.148c0.082,0.062,0.123,0.134,0.123,0.215
|
||||
c0,0.512-0.521,1.924-1.565,4.236c0.348,0.471,0.655,1.002,0.921,1.596c3.049,0.307,4.573,0.624,4.573,0.951v4.297
|
||||
c0,0.328-1.524,0.645-4.573,0.951c-0.246,0.553-0.553,1.085-0.921,1.597c1.044,2.312,1.565,3.724,1.565,4.235
|
||||
c0,0.081-0.041,0.153-0.123,0.215c-2.496,1.452-3.765,2.179-3.806,2.179c-0.164,0-0.634-0.48-1.411-1.442
|
||||
c-0.778-0.962-1.311-1.657-1.597-2.087c-0.409,0.041-0.716,0.062-0.921,0.062s-0.512-0.021-0.92-0.062
|
||||
c-0.287,0.43-0.819,1.125-1.597,2.087c-0.778,0.962-1.248,1.442-1.411,1.442c-0.042,0-1.311-0.727-3.807-2.179
|
||||
c-0.082-0.062-0.123-0.134-0.123-0.215c0-0.512,0.522-1.924,1.566-4.235c-0.369-0.512-0.676-1.044-0.922-1.597
|
||||
C78.381,91.051,76.857,90.734,76.857,90.406z M84.715,56.829c0,1.085,0.383,2.011,1.15,2.778c0.768,0.767,1.693,1.15,2.777,1.15
|
||||
s2.011-0.384,2.777-1.15c0.768-0.768,1.151-1.693,1.151-2.778c0-1.063-0.389-1.984-1.166-2.762
|
||||
c-0.778-0.777-1.698-1.167-2.763-1.167s-1.984,0.39-2.762,1.167C85.103,54.845,84.715,55.766,84.715,56.829z M84.715,88.258
|
||||
c0,1.085,0.383,2.011,1.15,2.777c0.768,0.768,1.693,1.151,2.777,1.151s2.011-0.384,2.777-1.151
|
||||
c0.768-0.767,1.151-1.692,1.151-2.777c0-1.063-0.389-1.984-1.166-2.762c-0.778-0.777-1.698-1.167-2.763-1.167
|
||||
s-1.984,0.39-2.762,1.167C85.103,86.273,84.715,87.194,84.715,88.258z"/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<h4>Deployment Made Easy</h4>
|
||||
<p>Trigger container builds when your code is checked into Github and passes tests. Automatically pushed into your repository for immediate access by your servers.</p>
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-4 col-sm-4 feature-desc">
|
||||
<div class="feature-illustration">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
preserveAspectRatio="xMinYMin" width="140px" viewBox="0 0 202.5 144" enable-background="new 0 0 202.5 144" xml:space="preserve">
|
||||
<circle fill="none" stroke="#010101" stroke-width="1.9753" stroke-miterlimit="10" cx="72" cy="72" r="52.567"/>
|
||||
<circle fill="none" stroke="#010101" stroke-width="1.9753" stroke-miterlimit="10" cx="132.006" cy="72" r="52.567"/>
|
||||
<g>
|
||||
<path fill="#00A3A0" d="M90.699,77.453c0-0.552,0.019-1.091,0.055-1.617s0.109-1.094,0.219-1.703s0.247-1.175,0.414-1.696
|
||||
c0.167-0.521,0.391-1.028,0.672-1.523c0.281-0.495,0.604-0.917,0.969-1.266c0.364-0.349,0.81-0.627,1.336-0.836
|
||||
c0.526-0.208,1.106-0.312,1.742-0.312c0.094,0,0.312,0.112,0.656,0.336c0.344,0.224,0.731,0.474,1.164,0.75
|
||||
c0.433,0.276,0.995,0.526,1.688,0.75c0.692,0.224,1.388,0.336,2.086,0.336s1.394-0.112,2.086-0.336
|
||||
c0.692-0.224,1.255-0.474,1.688-0.75c0.433-0.276,0.82-0.526,1.164-0.75c0.344-0.224,0.562-0.336,0.656-0.336
|
||||
c0.636,0,1.216,0.104,1.742,0.312c0.526,0.208,0.972,0.487,1.336,0.836c0.364,0.349,0.688,0.771,0.969,1.266
|
||||
c0.281,0.495,0.505,1.003,0.672,1.523c0.167,0.521,0.305,1.086,0.414,1.696s0.183,1.177,0.219,1.703s0.055,1.065,0.055,1.617
|
||||
c0,1.25-0.38,2.236-1.141,2.961c-0.761,0.724-1.771,1.086-3.031,1.086H94.871c-1.261,0-2.271-0.362-3.031-1.086
|
||||
C91.079,79.689,90.699,78.703,90.699,77.453z M97.457,67.742c-1.172-1.172-1.758-2.586-1.758-4.242s0.586-3.07,1.758-4.242
|
||||
s2.586-1.758,4.242-1.758s3.07,0.586,4.242,1.758s1.758,2.586,1.758,4.242s-0.586,3.07-1.758,4.242s-2.586,1.758-4.242,1.758
|
||||
S98.629,68.914,97.457,67.742z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#4BA0D8" d="M42.782,57.118c0-0.552,0.018-1.091,0.055-1.617c0.036-0.526,0.109-1.094,0.219-1.703
|
||||
s0.247-1.174,0.414-1.695c0.167-0.521,0.391-1.028,0.672-1.523c0.281-0.495,0.604-0.917,0.969-1.266
|
||||
c0.364-0.349,0.81-0.627,1.336-0.836c0.526-0.208,1.106-0.312,1.742-0.312c0.094,0,0.312,0.112,0.656,0.336
|
||||
c0.344,0.224,0.731,0.474,1.164,0.75c0.432,0.276,0.995,0.526,1.688,0.75c0.692,0.224,1.388,0.336,2.086,0.336
|
||||
c0.698,0,1.393-0.112,2.086-0.336c0.692-0.224,1.255-0.474,1.688-0.75c0.432-0.276,0.82-0.526,1.164-0.75
|
||||
c0.344-0.224,0.562-0.336,0.656-0.336c0.635,0,1.216,0.104,1.742,0.312c0.526,0.208,0.971,0.487,1.336,0.836
|
||||
c0.364,0.349,0.688,0.771,0.969,1.266c0.281,0.495,0.505,1.003,0.672,1.523c0.167,0.521,0.305,1.086,0.414,1.695
|
||||
s0.182,1.177,0.219,1.703c0.036,0.526,0.055,1.065,0.055,1.617c0,1.25-0.38,2.237-1.141,2.961
|
||||
c-0.761,0.724-1.771,1.086-3.031,1.086H46.954c-1.261,0-2.271-0.362-3.031-1.086C43.162,59.355,42.782,58.368,42.782,57.118z
|
||||
M49.54,47.407c-1.172-1.172-1.758-2.586-1.758-4.242s0.586-3.07,1.758-4.242s2.586-1.758,4.242-1.758s3.07,0.586,4.242,1.758
|
||||
s1.758,2.586,1.758,4.242s-0.586,3.07-1.758,4.242s-2.586,1.758-4.242,1.758S50.712,48.579,49.54,47.407z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#4BA0D8" d="M27.422,90.324c0-0.552,0.018-1.091,0.055-1.617c0.036-0.526,0.109-1.094,0.219-1.703
|
||||
s0.247-1.175,0.414-1.695c0.167-0.521,0.391-1.028,0.672-1.523s0.604-0.917,0.969-1.266c0.364-0.349,0.81-0.628,1.336-0.836
|
||||
c0.526-0.208,1.106-0.312,1.742-0.312c0.094,0,0.312,0.112,0.656,0.336s0.731,0.474,1.164,0.75c0.432,0.276,0.995,0.526,1.688,0.75
|
||||
c0.692,0.224,1.388,0.336,2.086,0.336c0.698,0,1.393-0.112,2.086-0.336c0.692-0.224,1.255-0.474,1.688-0.75
|
||||
c0.432-0.276,0.82-0.526,1.164-0.75s0.562-0.336,0.656-0.336c0.635,0,1.216,0.104,1.742,0.312c0.526,0.208,0.971,0.487,1.336,0.836
|
||||
c0.364,0.349,0.688,0.771,0.969,1.266s0.505,1.003,0.672,1.523c0.167,0.521,0.305,1.086,0.414,1.695s0.182,1.177,0.219,1.703
|
||||
c0.036,0.526,0.055,1.065,0.055,1.617c0,1.25-0.38,2.236-1.141,2.961c-0.761,0.724-1.771,1.086-3.031,1.086H31.594
|
||||
c-1.261,0-2.271-0.362-3.031-1.086C27.802,92.561,27.422,91.574,27.422,90.324z M34.18,80.613
|
||||
c-1.172-1.172-1.758-2.586-1.758-4.242s0.586-3.07,1.758-4.242s2.586-1.758,4.242-1.758s3.07,0.586,4.242,1.758
|
||||
s1.758,2.586,1.758,4.242s-0.586,3.07-1.758,4.242s-2.586,1.758-4.242,1.758S35.352,81.785,34.18,80.613z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#4BA0D8" d="M54.999,106.043c0-0.552,0.018-1.091,0.055-1.617c0.036-0.525,0.109-1.094,0.219-1.703
|
||||
s0.247-1.174,0.414-1.695c0.167-0.521,0.391-1.028,0.672-1.523c0.281-0.494,0.604-0.916,0.969-1.266
|
||||
c0.364-0.349,0.81-0.627,1.336-0.836c0.526-0.208,1.106-0.312,1.742-0.312c0.094,0,0.312,0.112,0.656,0.336
|
||||
c0.344,0.225,0.731,0.475,1.164,0.75c0.432,0.276,0.995,0.526,1.688,0.75c0.692,0.225,1.388,0.336,2.086,0.336
|
||||
c0.698,0,1.393-0.111,2.086-0.336c0.692-0.224,1.255-0.474,1.688-0.75c0.432-0.275,0.82-0.525,1.164-0.75
|
||||
c0.344-0.224,0.562-0.336,0.656-0.336c0.635,0,1.216,0.104,1.742,0.312c0.525,0.209,0.971,0.487,1.336,0.836
|
||||
c0.364,0.35,0.688,0.771,0.969,1.266c0.281,0.495,0.505,1.003,0.672,1.523c0.166,0.521,0.305,1.086,0.414,1.695
|
||||
s0.182,1.178,0.219,1.703c0.036,0.526,0.055,1.065,0.055,1.617c0,1.25-0.381,2.237-1.141,2.961
|
||||
c-0.761,0.724-1.771,1.086-3.031,1.086H59.171c-1.261,0-2.271-0.362-3.031-1.086C55.379,108.28,54.999,107.293,54.999,106.043z
|
||||
M61.757,96.332c-1.172-1.172-1.758-2.586-1.758-4.242s0.586-3.07,1.758-4.242s2.586-1.758,4.242-1.758s3.07,0.586,4.242,1.758
|
||||
s1.758,2.586,1.758,4.242s-0.586,3.07-1.758,4.242s-2.586,1.758-4.242,1.758S62.929,97.504,61.757,96.332z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#00A651" d="M141.867,57.118c0-0.552,0.018-1.091,0.055-1.617c0.035-0.526,0.109-1.094,0.219-1.703
|
||||
s0.246-1.174,0.414-1.695c0.166-0.521,0.391-1.028,0.672-1.523c0.281-0.495,0.604-0.917,0.969-1.266
|
||||
c0.363-0.349,0.809-0.627,1.336-0.836c0.525-0.208,1.105-0.312,1.742-0.312c0.094,0,0.312,0.112,0.656,0.336
|
||||
c0.344,0.224,0.73,0.474,1.164,0.75c0.432,0.276,0.994,0.526,1.688,0.75c0.691,0.224,1.387,0.336,2.086,0.336
|
||||
c0.697,0,1.393-0.112,2.086-0.336c0.691-0.224,1.254-0.474,1.688-0.75c0.432-0.276,0.82-0.526,1.164-0.75
|
||||
c0.344-0.224,0.562-0.336,0.656-0.336c0.635,0,1.215,0.104,1.742,0.312c0.525,0.208,0.971,0.487,1.336,0.836
|
||||
c0.363,0.349,0.688,0.771,0.969,1.266c0.281,0.495,0.504,1.003,0.672,1.523c0.166,0.521,0.305,1.086,0.414,1.695
|
||||
s0.182,1.177,0.219,1.703c0.035,0.526,0.055,1.065,0.055,1.617c0,1.25-0.381,2.237-1.141,2.961
|
||||
c-0.762,0.724-1.771,1.086-3.031,1.086h-13.656c-1.262,0-2.271-0.362-3.031-1.086C142.246,59.354,141.867,58.368,141.867,57.118z
|
||||
M148.625,47.407c-1.172-1.172-1.758-2.586-1.758-4.242s0.586-3.07,1.758-4.242s2.586-1.758,4.242-1.758s3.07,0.586,4.242,1.758
|
||||
s1.758,2.586,1.758,4.242s-0.586,3.07-1.758,4.242s-2.586,1.758-4.242,1.758S149.797,48.579,148.625,47.407z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#00A651" d="M132.005,102.458c0-0.552,0.019-1.091,0.055-1.617s0.109-1.094,0.219-1.703s0.247-1.175,0.414-1.695
|
||||
s0.391-1.028,0.672-1.523s0.604-0.917,0.969-1.266s0.81-0.628,1.336-0.836s1.106-0.312,1.742-0.312
|
||||
c0.094,0,0.312,0.112,0.656,0.336s0.731,0.474,1.164,0.75s0.995,0.526,1.688,0.75s1.388,0.336,2.086,0.336s1.394-0.112,2.086-0.336
|
||||
s1.255-0.474,1.688-0.75s0.82-0.526,1.164-0.75s0.562-0.336,0.656-0.336c0.636,0,1.216,0.104,1.742,0.312s0.972,0.487,1.336,0.836
|
||||
s0.688,0.771,0.969,1.266s0.505,1.003,0.672,1.523s0.305,1.086,0.414,1.695s0.183,1.177,0.219,1.703s0.055,1.065,0.055,1.617
|
||||
c0,1.25-0.38,2.236-1.141,2.961c-0.761,0.724-1.771,1.086-3.031,1.086h-13.656c-1.261,0-2.271-0.362-3.031-1.086
|
||||
C132.385,104.694,132.005,103.708,132.005,102.458z M138.763,92.747c-1.172-1.172-1.758-2.586-1.758-4.242s0.586-3.07,1.758-4.242
|
||||
s2.586-1.758,4.242-1.758s3.07,0.586,4.242,1.758s1.758,2.586,1.758,4.242s-0.586,3.07-1.758,4.242s-2.586,1.758-4.242,1.758
|
||||
S139.935,93.919,138.763,92.747z"/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<h4>Teamwork Optimized</h4>
|
||||
<p>Control how the different teams and projects within your enterprise collaborate on repositories.</p>
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-4 col-sm-4 feature-desc">
|
||||
<div class="feature-illustration">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
preserveAspectRatio="xMinYMin" width="100px" viewBox="0 0 144 144" enable-background="new 0 0 144 144" xml:space="preserve">
|
||||
<path d="M103.5,123.357V110.5c0-0.595,0.208-1.101,0.625-1.518c0.416-0.416,0.922-0.625,1.518-0.625h0.715v-4.286
|
||||
c0-2.737,0.982-5.089,2.946-7.053c1.964-1.965,4.315-2.947,7.054-2.947c2.737,0,5.089,0.982,7.054,2.947
|
||||
c1.964,1.964,2.946,4.315,2.946,7.053v4.286h0.714c0.595,0,1.102,0.209,1.518,0.625c0.417,0.417,0.625,0.923,0.625,1.518v12.857
|
||||
c0,0.596-0.208,1.102-0.625,1.518c-0.416,0.417-0.923,0.625-1.518,0.625h-21.429c-0.596,0-1.102-0.208-1.518-0.625
|
||||
C103.708,124.459,103.5,123.953,103.5,123.357z M110.643,108.357h11.429v-4.286c0-1.577-0.558-2.924-1.674-4.04
|
||||
s-2.463-1.674-4.04-1.674c-1.578,0-2.924,0.558-4.041,1.674c-1.115,1.116-1.674,2.463-1.674,4.04V108.357z"/>
|
||||
<polyline fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" points="99.889,122.5 21.5,122.5 21.5,20.5
|
||||
123.5,20.5 123.5,92.469 "/>
|
||||
<rect x="32.214" y="61.422" fill="#4CA0D8" width="20.156" height="20.156"/>
|
||||
<rect x="92.63" y="61.422" fill="#4CA0D8" width="20.156" height="20.156"/>
|
||||
<rect x="62.422" y="61.422" fill="#4CA0D8" width="20.156" height="20.156"/>
|
||||
<rect x="32.214" y="31.874" fill="#4CA0D8" width="20.156" height="20.156"/>
|
||||
<rect x="92.63" y="31.874" fill="#4CA0D8" width="20.156" height="20.156"/>
|
||||
<rect x="62.422" y="31.874" fill="#4CA0D8" width="20.156" height="20.156"/>
|
||||
<rect x="32.214" y="91.909" fill="#4CA0D8" width="20.156" height="20.156"/>
|
||||
<g>
|
||||
<path fill="#4CA0D8" d="M101.579,106.437c0.361-0.361,0.756-0.666,1.179-0.913v-1.452c0-3.714,1.346-6.943,4-9.599
|
||||
c1.073-1.073,2.244-1.921,3.499-2.564H92.63v20.156H99.9V110.5C99.9,108.94,100.48,107.535,101.579,106.437z"/>
|
||||
</g>
|
||||
<rect x="62.422" y="91.909" fill="#4CA0D8" width="20.156" height="20.156"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h4>Secure, Private Storage</h4>
|
||||
<p>Containers often contain keys and passwords — take control of your registry by running it behind your firewall on <a href="https://coreos.com/products/managed-linux" data-category="Products: Managed Linux" data-event="Product: Managed Linux">CoreOS Managed Linux</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tour-section row">
|
||||
<div class="col-sm-3 col-sm-push-9 enterprise-icon">
|
||||
<span class="fa-stack fa-5x">
|
||||
<i class="fa fa-circle fa-stack-2x"></i>
|
||||
<i class="fa fa-bar-chart-o fa-stack-1x fa-inverse"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-sm-9 col-sm-pull-3">
|
||||
<div class="tour-section-title">Auditing and insight done right</div>
|
||||
<div class="tour-section-description">
|
||||
Our platform has built in logging and insight tools, allowing you to see who performed every action on the contents and access control settings of your repositories. This will help you pass internal auditing and compliance requirements more easily.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tour-section row">
|
||||
<div class="col-sm-3 enterprise-icon">
|
||||
<span class="fa-stack fa-5x">
|
||||
<i class="fa fa-circle fa-stack-2x"></i>
|
||||
<i class="fa fa-users fa-stack-1x fa-inverse"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-sm-9">
|
||||
<div class="tour-section-title">Organize your repositories like you organize your business</div>
|
||||
<div class="tour-section-description">
|
||||
The built in teams and organizations features of <span class="registry-name"></span> allow you to finely control how the different teams and projects within your enterprise collaborate on repositories.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tour-action">
|
||||
<a href="mailto:support@devtable.com?Subject=Enterprise%20Quay.io%20Inquiry" data-title="Email us to find out more." bs-tooltip="tooltip.title">
|
||||
<button class="btn btn-success">
|
||||
Contact Us
|
||||
</button>
|
||||
</a>
|
||||
<div class="row" style="text-align: center; margin-bottom: 20px;">
|
||||
<a href="https://coreos.com/products/enterprise-registry" class="btn btn-primary">Learn more about Enterprise Registry</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
48
static/img/black-horizontal.svg
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="325.68px" height="112.574px" viewBox="0 0 325.68 112.574" enable-background="new 0 0 325.68 112.574"
|
||||
xml:space="preserve">
|
||||
<path d="M95.701,60.164c0,27.658,9.385,30.316,24.336,30.316c14.95-0.083,24.502-3.488,24.502-30.316
|
||||
c0-28.489-10.133-31.229-24.502-31.229C105.916,28.934,95.701,31.675,95.701,60.164 M107.329,60.164
|
||||
c0-19.352,3.738-20.515,12.708-20.515c9.22,0,12.874,1.578,12.874,20.515c0,16.363-3.073,19.602-12.874,19.602
|
||||
C109.654,79.766,107.329,76.775,107.329,60.164z M116.465,92.889c0.665,10.632,11.711,13.538,20.1,11.711v-9.385
|
||||
c-4.9,1.329-10.881,2.076-13.538-2.326H116.465z"/>
|
||||
<path d="M150.438,75.364c0,8.472,2.907,15.532,13.123,15.532c6.727,0,9.635-2.824,14.037-5.399l2.243,4.651h9.386V46.044h-11.628
|
||||
v31.645c-3.405,2.658-5.98,3.821-10.631,3.821c-2.907,0-4.901-1.495-4.901-5.897V46.044h-11.628V75.364z"/>
|
||||
<path d="M195.457,78.935c0,5.731,3.987,11.462,12.459,11.711c6.728,0.166,12.957-4.402,13.455-5.316l2.409,4.818h9.22V59.417
|
||||
c0-10.964-6.479-14.203-15.947-14.203c-8.223,0-14.286,0.665-20.1,2.907v7.226c3.571-0.249,14.618-0.914,18.522-0.914
|
||||
c3.654,0,5.897,0.665,5.897,5.399c0.083,0.083,0,2.824,0,2.824c0,0.083-12.957,0-12.957,0c-9.469,0-12.957,5.648-12.957,12.127
|
||||
V78.935z M207.085,77.274v-2.16c0-1.91,0.499-4.236,3.572-4.485l10.714-0.831v8.057c0,0-5.316,3.488-10.133,3.488
|
||||
C209.078,81.344,207.085,80.929,207.085,77.274z"/>
|
||||
<path d="M236.573,46.044l8.638,32.891c2.159,8.14,6.977,11.213,13.123,11.213l-6.229,22.426h8.306l6.063-8.472l15.283-58.058H269.63
|
||||
l-8.804,34.137c-0.664-0.083-3.489,0.249-4.402-3.239l-7.641-30.898H236.573z"/>
|
||||
<path d="M283.668,89.321c0,0.621,0.443,1.021,1.065,1.021h3.815c0.621,0,1.109-0.222,1.109-1.021v-3.992
|
||||
c0-0.71-0.311-1.109-1.109-1.109h-3.815c-0.71,0-1.065,0.444-1.065,1.109V89.321z"/>
|
||||
<path d="M294.138,63.281c0,0.621,0.444,1.021,1.065,1.021h4.658c0.621,0,0.976-0.355,0.976-1.021v-3.904
|
||||
c0-0.621-0.311-1.153-0.976-1.153h-4.658c-0.71,0-1.065,0.444-1.065,1.153V63.281z M294.36,90.342h6.211V66.785h-6.211V90.342z"/>
|
||||
<path d="M304.208,78.896c0,8.429,2.617,11.667,10.736,11.667c8.251,0,10.735-2.928,10.735-11.667
|
||||
c0-9.361-2.617-12.333-10.735-12.333C307.003,66.563,304.208,69.27,304.208,78.896 M310.419,78.896c0-6.61,0.843-7.364,4.525-7.364
|
||||
c3.726,0,4.525,0.754,4.525,7.364c0,6.21-1.02,6.654-4.525,6.654C311.661,85.55,310.419,84.974,310.419,78.896z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M38.505,0c13.241,0,24.037,13.64,24.588,30.737h-8.876
|
||||
c0-11.805-7.035-21.374-15.712-21.374c-8.678,0-15.713,9.569-15.713,21.374h-8.876C14.467,13.64,25.264,0,38.505,0"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M38.504,57.156c2.483,0,4.495,2.013,4.495,4.495c0,0.946-0.292,1.823-0.791,2.547
|
||||
l2.294,12.511H32.507l2.294-12.511c-0.499-0.724-0.791-1.601-0.791-2.547C34.009,59.168,36.022,57.156,38.504,57.156"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.394,34.801h4.724c1.317,0,2.394,1.077,2.394,2.394v59.474
|
||||
c0,1.317-1.077,2.394-2.394,2.394H2.394C1.077,99.063,0,97.986,0,96.669V37.195C0,35.878,1.077,34.801,2.394,34.801"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.314,34.801h4.724c1.316,0,2.394,1.077,2.394,2.394v59.474
|
||||
c0,1.317-1.077,2.394-2.394,2.394h-4.724c-1.316,0-2.394-1.077-2.394-2.394V37.195C13.92,35.878,14.997,34.801,16.314,34.801"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M29.183,34.801h4.724c1.317,0,2.394,1.077,2.394,2.394V51.96
|
||||
c0,1.317-1.077,2.394-2.394,2.394h-4.724c-1.317,0-2.394-1.077-2.394-2.394V37.195C26.789,35.878,27.866,34.801,29.183,34.801"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M43.103,34.801h4.724c1.316,0,2.393,1.077,2.393,2.394V51.96
|
||||
c0,1.317-1.077,2.394-2.393,2.394h-4.724c-1.316,0-2.394-1.077-2.394-2.394V37.195C40.709,35.878,41.786,34.801,43.103,34.801"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M55.971,34.801h4.724c1.317,0,2.394,1.077,2.394,2.394v59.474
|
||||
c0,1.317-1.077,2.394-2.394,2.394h-4.724c-1.316,0-2.393-1.077-2.393-2.394V37.195C53.578,35.878,54.655,34.801,55.971,34.801"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M69.891,34.801h4.724c1.317,0,2.394,1.077,2.394,2.394v59.474
|
||||
c0,1.317-1.077,2.394-2.394,2.394h-4.724c-1.317,0-2.394-1.077-2.394-2.394V37.195C67.498,35.878,68.575,34.801,69.891,34.801"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M29.183,79.51h4.724c1.317,0,2.394,1.077,2.394,2.394V96.67
|
||||
c0,1.317-1.077,2.394-2.394,2.394h-4.724c-1.317,0-2.394-1.077-2.394-2.394V81.904C26.789,80.588,27.866,79.51,29.183,79.51"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M43.103,79.51h4.724c1.316,0,2.393,1.077,2.393,2.394V96.67
|
||||
c0,1.317-1.077,2.394-2.393,2.394h-4.724c-1.316,0-2.394-1.077-2.394-2.394V81.904C40.709,80.588,41.786,79.51,43.103,79.51"/>
|
||||
</svg>
|
After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 103 KiB |
BIN
static/img/coreos-globe-color-lg.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
51
static/img/coreos-wordmark-horiz-white.svg
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="792px" height="306px" viewBox="0 0 792 306" enable-background="new 0 0 792 306" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M136.168,45.527C76.898,45.527,28.689,93.739,28.689,153c0,59.265,48.209,107.474,107.479,107.474
|
||||
c59.252,0,107.465-48.209,107.465-107.474C243.633,93.739,195.42,45.527,136.168,45.527z M176.542,180.428
|
||||
c-0.889,0.129-1.767,0.254-2.659,0.368c-8.111,1.049-16.77,1.761-25.819,2.099c-3.895,0.145-7.872,0.233-11.895,0.233
|
||||
c-4.035,0-8-0.087-11.907-0.233c-9.038-0.338-17.703-1.05-25.807-2.099c-0.723-6.047-1.213-12.339-1.458-18.811
|
||||
c-0.117-2.956-0.175-5.956-0.175-8.985c0-3.032,0.058-6.026,0.175-8.988c0.245-6.473,0.735-12.761,1.458-18.808
|
||||
c0.145-1.259,0.309-2.51,0.478-3.746c5.294-38.424,19.952-66.069,37.235-66.069c53.903,0,97.608,43.699,97.609,97.611
|
||||
C233.777,165.196,210.296,175.688,176.542,180.428z"/>
|
||||
</g>
|
||||
<path fill="#FFFFFF" d="M176.541,125.569c-0.979-1.428-2.029-2.796-3.148-4.11c-8.956-10.557-22.297-17.265-37.224-17.265
|
||||
c-4.839,0-9.148,7.407-11.907,18.909c-1.096,4.586-1.947,9.819-2.495,15.498c-0.432,4.551-0.665,9.391-0.665,14.399
|
||||
s0.233,9.849,0.665,14.396c4.554,0.432,9.387,0.664,14.402,0.664c5.009,0,9.842-0.232,14.396-0.664
|
||||
c10.011-0.95,18.653-2.875,24.775-5.411c6.046-2.501,9.624-5.615,9.624-8.985C184.963,142.832,181.858,133.388,176.541,125.569z"
|
||||
/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M344.891,100.053c12.585,0,22.816,6.138,29.262,13.062l-10.064,11.326
|
||||
c-5.353-5.192-11.175-8.495-19.041-8.495c-16.839,0-28.953,14.16-28.953,37.291c0,23.448,11.169,37.608,28.32,37.608
|
||||
c9.128,0,15.895-3.775,21.717-10.228l10.067,11.169c-8.335,9.598-19.038,14.95-32.099,14.95c-26.119,0-46.731-18.88-46.731-53.025
|
||||
C297.37,120.036,318.454,100.053,344.891,100.053z"/>
|
||||
<path fill="#FFFFFF" d="M416.961,125.701c19.352,0,36.822,14.793,36.822,40.597c0,25.647-17.471,40.439-36.822,40.439
|
||||
c-19.197,0-36.66-14.792-36.66-40.439C380.301,140.494,397.764,125.701,416.961,125.701z M416.961,191.945
|
||||
c11.33,0,18.25-10.228,18.25-25.647c0-15.577-6.92-25.804-18.25-25.804s-18.094,10.227-18.094,25.804
|
||||
C398.867,181.717,405.631,191.945,416.961,191.945z"/>
|
||||
<path fill="#FFFFFF" d="M459.771,127.589h14.943l1.26,13.688h0.629c5.506-10.07,13.691-15.577,21.871-15.577
|
||||
c3.938,0,6.455,0.472,8.811,1.574l-3.148,15.734c-2.67-0.784-4.717-1.257-8.018-1.257c-6.139,0-13.539,4.245-18.256,15.893v47.203
|
||||
h-18.092L459.771,127.589L459.771,127.589z"/>
|
||||
<path fill="#FFFFFF" d="M541.121,125.701c20.928,0,31.941,15.107,31.941,36.667c0,3.458-0.314,6.604-0.787,8.495h-49.09
|
||||
c1.57,14.003,10.379,21.869,22.811,21.869c6.613,0,12.273-2.041,17.941-5.662l6.135,11.326
|
||||
c-7.395,4.878-16.676,8.341-26.432,8.341c-21.404,0-38.08-14.95-38.08-40.439C505.561,141.12,523.023,125.701,541.121,125.701z
|
||||
M557.326,159.376c0-12.277-5.189-19.671-15.732-19.671c-9.125,0-16.996,6.768-18.57,19.671H557.326z"/>
|
||||
<path fill="#FFFFFF" d="M600.602,152.607c0-32.729,17.785-53.344,42.799-53.344c24.863,0,42.641,20.615,42.641,53.344
|
||||
c0,32.889-17.777,54.13-42.641,54.13C618.387,206.737,600.602,185.496,600.602,152.607z M678.49,152.607
|
||||
c0-28.639-14.158-46.731-35.09-46.731c-21.084,0-35.248,18.093-35.248,46.731c0,28.796,14.164,47.521,35.248,47.521
|
||||
C664.332,200.128,678.49,181.403,678.49,152.607z"/>
|
||||
<path fill="#FFFFFF" d="M699.738,186.125c7.557,8.495,18.412,14.003,30.529,14.003c15.732,0,25.807-8.499,25.807-20.767
|
||||
c0-12.904-8.494-17.154-18.723-21.717l-15.736-7.082c-8.969-3.936-20.934-10.385-20.934-25.808
|
||||
c0-14.947,12.904-25.492,30.059-25.492c12.588,0,22.658,5.665,28.949,12.435l-4.244,4.878c-5.982-6.452-14.32-10.7-24.705-10.7
|
||||
c-13.691,0-22.816,7.239-22.816,18.565c0,11.962,10.385,16.521,17.936,19.985l15.738,6.921
|
||||
c11.486,5.195,21.713,11.647,21.713,27.539s-13.061,27.851-33.201,27.851c-15.107,0-26.75-6.451-34.932-15.576L699.738,186.125z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.1 KiB |
49
static/img/coreos.svg
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="792px" height="306px" viewBox="0 0 792 306" enable-background="new 0 0 792 306" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#53A3DA" d="M136.168,45.527C76.898,45.527,28.689,93.739,28.689,153c0,59.265,48.209,107.474,107.479,107.474
|
||||
c59.252,0,107.465-48.209,107.465-107.474C243.633,93.739,195.42,45.527,136.168,45.527z"/>
|
||||
<path fill="#F1606D" d="M136.168,55.389c-17.283,0-31.941,27.645-37.235,66.069c-0.169,1.236-0.333,2.487-0.478,3.746
|
||||
c-0.723,6.047-1.213,12.335-1.458,18.808c-0.117,2.962-0.175,5.956-0.175,8.988c0,3.029,0.058,6.029,0.175,8.985
|
||||
c0.245,6.472,0.735,12.764,1.458,18.811c8.104,1.049,16.769,1.761,25.807,2.099c3.907,0.146,7.872,0.233,11.907,0.233
|
||||
c4.023,0,8-0.088,11.895-0.233c9.049-0.338,17.708-1.05,25.819-2.099c0.892-0.114,1.77-0.239,2.659-0.368
|
||||
c33.754-4.74,57.235-15.232,57.235-27.428C233.776,99.088,190.071,55.389,136.168,55.389z"/>
|
||||
<path fill="#FFFFFF" d="M176.541,125.569c-0.979-1.428-2.029-2.796-3.148-4.11c-8.956-10.557-22.297-17.265-37.224-17.265
|
||||
c-4.839,0-9.148,7.407-11.907,18.909c-1.096,4.586-1.947,9.819-2.495,15.498c-0.432,4.551-0.665,9.391-0.665,14.399
|
||||
s0.233,9.849,0.665,14.396c4.554,0.432,9.387,0.664,14.402,0.664c5.009,0,9.842-0.232,14.396-0.664
|
||||
c10.011-0.95,18.653-2.875,24.775-5.411c6.046-2.501,9.624-5.615,9.624-8.985C184.963,142.832,181.858,133.388,176.541,125.569z"
|
||||
/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#231F20" d="M344.891,100.053c12.585,0,22.816,6.138,29.262,13.062l-10.064,11.326
|
||||
c-5.353-5.192-11.175-8.495-19.041-8.495c-16.839,0-28.953,14.16-28.953,37.291c0,23.448,11.169,37.608,28.32,37.608
|
||||
c9.128,0,15.895-3.775,21.717-10.228l10.067,11.169c-8.335,9.598-19.038,14.95-32.099,14.95c-26.119,0-46.731-18.88-46.731-53.025
|
||||
C297.37,120.036,318.454,100.053,344.891,100.053z"/>
|
||||
<path fill="#231F20" d="M416.961,125.701c19.352,0,36.822,14.793,36.822,40.597c0,25.647-17.471,40.439-36.822,40.439
|
||||
c-19.197,0-36.66-14.792-36.66-40.439C380.301,140.494,397.764,125.701,416.961,125.701z M416.961,191.945
|
||||
c11.33,0,18.25-10.228,18.25-25.647c0-15.577-6.92-25.804-18.25-25.804s-18.094,10.227-18.094,25.804
|
||||
C398.867,181.717,405.631,191.945,416.961,191.945z"/>
|
||||
<path fill="#231F20" d="M459.771,127.589h14.943l1.26,13.688h0.629c5.506-10.07,13.691-15.577,21.871-15.577
|
||||
c3.938,0,6.455,0.472,8.811,1.574l-3.148,15.734c-2.67-0.784-4.717-1.257-8.018-1.257c-6.139,0-13.539,4.245-18.256,15.893v47.203
|
||||
h-18.092V127.589z"/>
|
||||
<path fill="#231F20" d="M541.121,125.701c20.928,0,31.941,15.107,31.941,36.667c0,3.458-0.314,6.604-0.787,8.495h-49.09
|
||||
c1.57,14.003,10.379,21.869,22.811,21.869c6.613,0,12.273-2.041,17.941-5.662l6.135,11.326
|
||||
c-7.395,4.878-16.676,8.341-26.432,8.341c-21.404,0-38.08-14.95-38.08-40.439C505.561,141.12,523.023,125.701,541.121,125.701z
|
||||
M557.326,159.376c0-12.277-5.189-19.671-15.732-19.671c-9.125,0-16.996,6.768-18.57,19.671H557.326z"/>
|
||||
<path fill="#F1606D" d="M600.602,152.607c0-32.729,17.785-53.344,42.799-53.344c24.863,0,42.641,20.615,42.641,53.344
|
||||
c0,32.889-17.777,54.13-42.641,54.13C618.387,206.737,600.602,185.496,600.602,152.607z M678.49,152.607
|
||||
c0-28.639-14.158-46.731-35.09-46.731c-21.084,0-35.248,18.093-35.248,46.731c0,28.796,14.164,47.521,35.248,47.521
|
||||
C664.332,200.128,678.49,181.403,678.49,152.607z"/>
|
||||
<path fill="#53A4D9" d="M699.738,186.125c7.557,8.495,18.412,14.003,30.529,14.003c15.732,0,25.807-8.499,25.807-20.767
|
||||
c0-12.904-8.494-17.154-18.723-21.717l-15.736-7.082c-8.969-3.936-20.934-10.385-20.934-25.808
|
||||
c0-14.947,12.904-25.492,30.059-25.492c12.588,0,22.658,5.665,28.949,12.435l-4.244,4.878c-5.982-6.452-14.32-10.7-24.705-10.7
|
||||
c-13.691,0-22.816,7.239-22.816,18.565c0,11.962,10.385,16.521,17.936,19.985l15.738,6.921
|
||||
c11.486,5.195,21.713,11.647,21.713,27.539s-13.061,27.851-33.201,27.851c-15.107,0-26.75-6.451-34.932-15.576L699.738,186.125z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.1 KiB |
BIN
static/img/image-view.png
Normal file
After Width: | Height: | Size: 113 KiB |
BIN
static/img/network-tile.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 95 KiB |
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 66 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 74 KiB |
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 95 KiB |
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 81 KiB |
606
static/js/app.js
|
@ -1,6 +1,46 @@
|
|||
var TEAM_PATTERN = '^[a-zA-Z][a-zA-Z0-9]+$';
|
||||
var ROBOT_PATTERN = '^[a-zA-Z][a-zA-Z0-9]{3,29}$';
|
||||
|
||||
$.fn.clipboardCopy = function() {
|
||||
if (zeroClipboardSupported) {
|
||||
(new ZeroClipboard($(this)));
|
||||
return true;
|
||||
}
|
||||
|
||||
this.hide();
|
||||
return false;
|
||||
};
|
||||
|
||||
var zeroClipboardSupported = true;
|
||||
ZeroClipboard.config({
|
||||
'swfPath': 'static/lib/ZeroClipboard.swf'
|
||||
});
|
||||
|
||||
ZeroClipboard.on("error", function(e) {
|
||||
zeroClipboardSupported = false;
|
||||
});
|
||||
|
||||
ZeroClipboard.on('aftercopy', function(e) {
|
||||
var container = e.target.parentNode.parentNode.parentNode;
|
||||
var message = $(container).find('.clipboard-copied-message')[0];
|
||||
|
||||
// Resets the animation.
|
||||
var elem = message;
|
||||
elem.style.display = 'none';
|
||||
elem.classList.remove('animated');
|
||||
|
||||
// Show the notification.
|
||||
setTimeout(function() {
|
||||
elem.style.display = 'inline-block';
|
||||
elem.classList.add('animated');
|
||||
}, 10);
|
||||
|
||||
// Reset the notification.
|
||||
setTimeout(function() {
|
||||
elem.style.display = 'none';
|
||||
}, 5000);
|
||||
});
|
||||
|
||||
function getRestUrl(args) {
|
||||
var url = '';
|
||||
for (var i = 0; i < arguments.length; ++i) {
|
||||
|
@ -59,18 +99,8 @@ function getFirstTextLine(commentString) {
|
|||
}
|
||||
|
||||
function createRobotAccount(ApiService, is_org, orgname, name, callback) {
|
||||
ApiService.createRobot(is_org ? orgname : null, null, {'robot_shortname': name}).then(callback, function(resp) {
|
||||
bootbox.dialog({
|
||||
"message": resp.data ? resp.data['message'] : 'The robot account could not be created',
|
||||
"title": "Cannot create robot account",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
ApiService.createRobot(is_org ? orgname : null, null, {'robot_shortname': name})
|
||||
.then(callback, ApiService.errorDisplay('Cannot create robot account'));
|
||||
}
|
||||
|
||||
function createOrganizationTeam(ApiService, orgname, teamname, callback) {
|
||||
|
@ -84,18 +114,8 @@ function createOrganizationTeam(ApiService, orgname, teamname, callback) {
|
|||
'teamname': teamname
|
||||
};
|
||||
|
||||
ApiService.updateOrganizationTeam(data, params).then(callback, function(resp) {
|
||||
bootbox.dialog({
|
||||
"message": resp.data ? resp.data : 'The team could not be created',
|
||||
"title": "Cannot create team",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
ApiService.updateOrganizationTeam(data, params)
|
||||
.then(callback, ApiService.errorDisplay('Cannot create team'));
|
||||
}
|
||||
|
||||
function getMarkedDown(string) {
|
||||
|
@ -121,7 +141,7 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
|||
* pauses in the UI for ngRepeat's when the array is significant in size.
|
||||
*/
|
||||
$provide.factory('AngularViewArray', ['$interval', function($interval) {
|
||||
var ADDTIONAL_COUNT = 50;
|
||||
var ADDTIONAL_COUNT = 20;
|
||||
|
||||
function _ViewArray() {
|
||||
this.isVisible = false;
|
||||
|
@ -364,7 +384,7 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
|||
var uiService = {};
|
||||
|
||||
uiService.hidePopover = function(elem) {
|
||||
var popover = $('#signupButton').data('bs.popover');
|
||||
var popover = $(elem).data('bs.popover');
|
||||
if (popover) {
|
||||
popover.hide();
|
||||
}
|
||||
|
@ -398,15 +418,19 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
|||
|
||||
$provide.factory('UtilService', ['$sanitize', function($sanitize) {
|
||||
var utilService = {};
|
||||
|
||||
utilService.textToSafeHtml = function(text) {
|
||||
|
||||
utilService.escapeHtmlString = function(text) {
|
||||
var adjusted = text.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'");
|
||||
|
||||
return $sanitize(adjusted);
|
||||
return adjusted;
|
||||
};
|
||||
|
||||
utilService.textToSafeHtml = function(text) {
|
||||
return $sanitize(utilService.escapeHtmlString(text));
|
||||
};
|
||||
|
||||
return utilService;
|
||||
|
@ -417,6 +441,29 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
|||
var pingService = {};
|
||||
var pingCache = {};
|
||||
|
||||
var invokeCallback = function($scope, pings, callback) {
|
||||
if (pings[0] == -1) {
|
||||
setTimeout(function() {
|
||||
$scope.$apply(function() {
|
||||
callback(-1, false, -1);
|
||||
});
|
||||
}, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
var sum = 0;
|
||||
for (var i = 0; i < pings.length; ++i) {
|
||||
sum += pings[i];
|
||||
}
|
||||
|
||||
// Report the average ping.
|
||||
setTimeout(function() {
|
||||
$scope.$apply(function() {
|
||||
callback(Math.floor(sum / pings.length), true, pings.length);
|
||||
});
|
||||
}, 0);
|
||||
};
|
||||
|
||||
var reportPingResult = function($scope, url, ping, callback) {
|
||||
// Lookup the cached ping data, if any.
|
||||
var cached = pingCache[url];
|
||||
|
@ -429,28 +476,15 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
|||
// If an error occurred, report it and done.
|
||||
if (ping < 0) {
|
||||
cached['pings'] = [-1];
|
||||
setTimeout(function() {
|
||||
$scope.$apply(function() {
|
||||
callback(-1, false, -1);
|
||||
});
|
||||
}, 0);
|
||||
invokeCallback($scope, pings, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, add the current ping and determine the average.
|
||||
cached['pings'].push(ping);
|
||||
|
||||
var sum = 0;
|
||||
for (var i = 0; i < cached['pings'].length; ++i) {
|
||||
sum += cached['pings'][i];
|
||||
}
|
||||
|
||||
// Report the average ping.
|
||||
setTimeout(function() {
|
||||
$scope.$apply(function() {
|
||||
callback(Math.floor(sum / cached['pings'].length), true, cached['pings'].length);
|
||||
});
|
||||
}, 0);
|
||||
// Invoke the callback.
|
||||
invokeCallback($scope, cached['pings'], callback);
|
||||
|
||||
// Schedule another check if we've done less than three.
|
||||
if (cached['pings'].length < 3) {
|
||||
|
@ -486,12 +520,7 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
|||
|
||||
pingService.pingUrl = function($scope, url, callback) {
|
||||
if (pingCache[url]) {
|
||||
cached = pingCache[url];
|
||||
setTimeout(function() {
|
||||
$scope.$apply(function() {
|
||||
callback(cached.result, cached.success);
|
||||
});
|
||||
}, 0);
|
||||
invokeCallback($scope, pingCache[url]['pings'], callback);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -526,7 +555,7 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
|||
return builderService;
|
||||
}]);
|
||||
|
||||
$provide.factory('StringBuilderService', ['$sce', function($sce) {
|
||||
$provide.factory('StringBuilderService', ['$sce', 'UtilService', function($sce, UtilService) {
|
||||
var stringBuilderService = {};
|
||||
|
||||
stringBuilderService.buildString = function(value_or_func, metadata) {
|
||||
|
@ -581,6 +610,8 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
|||
if (key.indexOf('image') >= 0) {
|
||||
value = value.substr(0, 12);
|
||||
}
|
||||
|
||||
var safe = UtilService.escapeHtmlString(value);
|
||||
var markedDown = getMarkedDown(value);
|
||||
markedDown = markedDown.substr('<p>'.length, markedDown.length - '<p></p>'.length);
|
||||
|
||||
|
@ -589,7 +620,7 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
|||
markedDown = '<i class="fa fa-' + icon + '"></i>' + markedDown;
|
||||
}
|
||||
|
||||
description = description.replace('{' + key + '}', '<code>' + markedDown + '</code>');
|
||||
description = description.replace('{' + key + '}', '<code title="' + safe + '">' + markedDown + '</code>');
|
||||
}
|
||||
}
|
||||
return $sce.trustAsHtml(description.replace('\n', '<br>'));
|
||||
|
@ -682,7 +713,7 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
|||
return config;
|
||||
}]);
|
||||
|
||||
$provide.factory('ApiService', ['Restangular', function(Restangular) {
|
||||
$provide.factory('ApiService', ['Restangular', '$q', function(Restangular, $q) {
|
||||
var apiService = {};
|
||||
|
||||
var getResource = function(path, opt_background) {
|
||||
|
@ -779,6 +810,65 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
|||
}
|
||||
};
|
||||
|
||||
var freshLoginFailCheck = function(opName, opArgs) {
|
||||
return function(resp) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
// If the error is a fresh login required, show the dialog.
|
||||
if (resp.status == 401 && resp.data['error_type'] == 'fresh_login_required') {
|
||||
bootbox.dialog({
|
||||
"message": 'It has been more than a few minutes since you last logged in, ' +
|
||||
'so please verify your password to perform this sensitive operation:' +
|
||||
'<form style="margin-top: 10px" action="javascript:void(0)">' +
|
||||
'<input id="freshPassword" class="form-control" type="password" placeholder="Current Password">' +
|
||||
'</form>',
|
||||
"title": 'Please Verify',
|
||||
"buttons": {
|
||||
"verify": {
|
||||
"label": "Verify",
|
||||
"className": "btn-success",
|
||||
"callback": function() {
|
||||
var info = {
|
||||
'password': $('#freshPassword').val()
|
||||
};
|
||||
|
||||
$('#freshPassword').val('');
|
||||
|
||||
// Conduct the sign in of the user.
|
||||
apiService.verifyUser(info).then(function() {
|
||||
// On success, retry the operation. if it succeeds, then resolve the
|
||||
// deferred promise with the result. Otherwise, reject the same.
|
||||
apiService[opName].apply(apiService, opArgs).then(function(resp) {
|
||||
deferred.resolve(resp);
|
||||
}, function(resp) {
|
||||
deferred.reject(resp);
|
||||
});
|
||||
}, function(resp) {
|
||||
// Reject with the sign in error.
|
||||
deferred.reject({'data': {'message': 'Invalid verification credentials'}});
|
||||
});
|
||||
}
|
||||
},
|
||||
"close": {
|
||||
"label": "Cancel",
|
||||
"className": "btn-default",
|
||||
"callback": function() {
|
||||
deferred.reject(resp);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Return a new promise. We'll accept or reject it based on the result
|
||||
// of the login.
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
// Otherwise, we just 'raise' the error via the reject method on the promise.
|
||||
return $q.reject(resp);
|
||||
};
|
||||
};
|
||||
|
||||
var buildMethodsForOperation = function(operation, resource, resourceMap) {
|
||||
var method = operation['method'].toLowerCase();
|
||||
var operationName = operation['nickname'];
|
||||
|
@ -792,7 +882,15 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
|||
'ignoreLoadingBar': true
|
||||
});
|
||||
}
|
||||
return one['custom' + method.toUpperCase()](opt_options);
|
||||
|
||||
var opObj = one['custom' + method.toUpperCase()](opt_options);
|
||||
|
||||
// If the operation requires_fresh_login, then add a specialized error handler that
|
||||
// will defer the operation's result if sudo is requested.
|
||||
if (operation['requires_fresh_login']) {
|
||||
opObj = opObj.catch(freshLoginFailCheck(operationName, arguments));
|
||||
}
|
||||
return opObj;
|
||||
};
|
||||
|
||||
// If the method for the operation is a GET, add an operationAsResource method.
|
||||
|
@ -841,6 +939,38 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
|||
buildMethodsForEndpointResource(endpointResource, resourceMap);
|
||||
}
|
||||
|
||||
apiService.getErrorMessage = function(resp, defaultMessage) {
|
||||
var message = defaultMessage;
|
||||
if (resp['data']) {
|
||||
message = resp['data']['error_message'] || resp['data']['message'] || resp['data']['error_description'] || message;
|
||||
}
|
||||
|
||||
return message;
|
||||
};
|
||||
|
||||
apiService.errorDisplay = function(defaultMessage, opt_handler) {
|
||||
return function(resp) {
|
||||
var message = apiService.getErrorMessage(resp, defaultMessage);
|
||||
if (opt_handler) {
|
||||
var handlerMessage = opt_handler(resp);
|
||||
if (handlerMessage) {
|
||||
message = handlerMessage;
|
||||
}
|
||||
}
|
||||
|
||||
bootbox.dialog({
|
||||
"message": message,
|
||||
"title": defaultMessage,
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
return apiService;
|
||||
}]);
|
||||
|
||||
|
@ -1097,7 +1227,8 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
|||
'user': null,
|
||||
'notifications': [],
|
||||
'notificationClasses': [],
|
||||
'notificationSummaries': []
|
||||
'notificationSummaries': [],
|
||||
'additionalNotifications': false
|
||||
};
|
||||
|
||||
var pollTimerHandle = null;
|
||||
|
@ -1193,7 +1324,9 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
|||
'uuid': notification.id
|
||||
};
|
||||
|
||||
ApiService.updateUserNotification(notification, params);
|
||||
ApiService.updateUserNotification(notification, params, function() {
|
||||
notificationService.update();
|
||||
}, ApiService.errorDisplay('Could not update notification'));
|
||||
|
||||
var index = $.inArray(notification, notificationService.notifications);
|
||||
if (index >= 0) {
|
||||
|
@ -1250,6 +1383,7 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
|||
|
||||
ApiService.listUserNotifications().then(function(resp) {
|
||||
notificationService.notifications = resp['notifications'];
|
||||
notificationService.additionalNotifications = resp['additional'];
|
||||
notificationService.notificationClasses = notificationService.getClasses(notificationService.notifications);
|
||||
});
|
||||
};
|
||||
|
@ -1512,7 +1646,7 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
|||
});
|
||||
};
|
||||
|
||||
planService.changePlan = function($scope, orgname, planId, callbacks) {
|
||||
planService.changePlan = function($scope, orgname, planId, callbacks, opt_async) {
|
||||
if (!Features.BILLING) { return; }
|
||||
|
||||
if (callbacks['started']) {
|
||||
|
@ -1525,7 +1659,7 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
|||
planService.getCardInfo(orgname, function(cardInfo) {
|
||||
if (plan.price > 0 && (previousSubscribeFailure || !cardInfo.last4)) {
|
||||
var title = cardInfo.last4 ? 'Subscribe' : 'Start Trial ({{amount}} plan)';
|
||||
planService.showSubscribeDialog($scope, orgname, planId, callbacks, title);
|
||||
planService.showSubscribeDialog($scope, orgname, planId, callbacks, title, /* async */true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1598,9 +1732,34 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
|||
return email;
|
||||
};
|
||||
|
||||
planService.showSubscribeDialog = function($scope, orgname, planId, callbacks, opt_title) {
|
||||
planService.showSubscribeDialog = function($scope, orgname, planId, callbacks, opt_title, opt_async) {
|
||||
if (!Features.BILLING) { return; }
|
||||
|
||||
// If the async parameter is true and this is a browser that does not allow async popup of the
|
||||
// Stripe dialog (such as Mobile Safari or IE), show a bootbox to show the dialog instead.
|
||||
var isIE = navigator.appName.indexOf("Internet Explorer") != -1;
|
||||
var isMobileSafari = navigator.userAgent.match(/(iPod|iPhone|iPad)/) && navigator.userAgent.match(/AppleWebKit/);
|
||||
|
||||
if (opt_async && (isIE || isMobileSafari)) {
|
||||
bootbox.dialog({
|
||||
"message": "Please click 'Subscribe' to continue",
|
||||
"buttons": {
|
||||
"subscribe": {
|
||||
"label": "Subscribe",
|
||||
"className": "btn-primary",
|
||||
"callback": function() {
|
||||
planService.showSubscribeDialog($scope, orgname, planId, callbacks, opt_title, false);
|
||||
}
|
||||
},
|
||||
"close": {
|
||||
"label": "Cancel",
|
||||
"className": "btn-default"
|
||||
}
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (callbacks['opening']) {
|
||||
callbacks['opening']();
|
||||
}
|
||||
|
@ -1693,7 +1852,7 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
|||
when('/repository/:namespace/:name/build', {templateUrl: '/static/partials/repo-build.html', controller:RepoBuildCtrl, reloadOnSearch: false}).
|
||||
when('/repository/:namespace/:name/build/:buildid/buildpack', {templateUrl: '/static/partials/build-package.html', controller:BuildPackageCtrl, reloadOnSearch: false}).
|
||||
when('/repository/', {title: 'Repositories', description: 'Public and private docker repositories list',
|
||||
templateUrl: '/static/partials/repo-list.html', controller: RepoListCtrl}).
|
||||
templateUrl: '/static/partials/repo-list.html', controller: RepoListCtrl, reloadOnSearch: false}).
|
||||
when('/user/', {title: 'Account Settings', description:'Account settings for ' + title, templateUrl: '/static/partials/user-admin.html',
|
||||
reloadOnSearch: false, controller: UserAdminCtrl}).
|
||||
when('/superuser/', {title: 'Superuser Admin Panel', description:'Admin panel for ' + title, templateUrl: '/static/partials/super-user.html',
|
||||
|
@ -1819,6 +1978,26 @@ quayApp.directive('quayShow', function($animate, Features, Config) {
|
|||
});
|
||||
|
||||
|
||||
quayApp.directive('quaySection', function($animate, $location, $rootScope) {
|
||||
return {
|
||||
priority: 590,
|
||||
restrict: 'A',
|
||||
link: function($scope, $element, $attr, ctrl, $transclude) {
|
||||
var update = function() {
|
||||
var result = $location.path().indexOf('/' + $attr.quaySection) == 0;
|
||||
$animate[!result ? 'removeClass' : 'addClass']($element, 'active');
|
||||
};
|
||||
|
||||
$scope.$watch(function(){
|
||||
return $location.path();
|
||||
}, update);
|
||||
|
||||
$scope.$watch($attr.quaySection, update);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
quayApp.directive('quayClasses', function(Features, Config) {
|
||||
return {
|
||||
priority: 580,
|
||||
|
@ -2018,18 +2197,7 @@ quayApp.directive('applicationReference', function () {
|
|||
template: '/static/directives/application-reference-dialog.html',
|
||||
show: true
|
||||
});
|
||||
}, function() {
|
||||
bootbox.dialog({
|
||||
"message": 'The application could not be found; it might have been deleted.',
|
||||
"title": "Cannot find application",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}, ApiService.errorDisplay('Application could not be found'));
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -2110,6 +2278,8 @@ quayApp.directive('copyBox', function () {
|
|||
'hoveringMessage': '=hoveringMessage'
|
||||
},
|
||||
controller: function($scope, $element, $rootScope) {
|
||||
$scope.disabled = false;
|
||||
|
||||
var number = $rootScope.__copyBoxIdCounter || 0;
|
||||
$rootScope.__copyBoxIdCounter = number + 1;
|
||||
$scope.inputId = "copy-box-input-" + number;
|
||||
|
@ -2119,27 +2289,7 @@ quayApp.directive('copyBox', function () {
|
|||
|
||||
input.attr('id', $scope.inputId);
|
||||
button.attr('data-clipboard-target', $scope.inputId);
|
||||
|
||||
var clip = new ZeroClipboard($(button), { 'moviePath': 'static/lib/ZeroClipboard.swf' });
|
||||
clip.on('complete', function(e) {
|
||||
var message = $(this.parentNode.parentNode.parentNode).find('.clipboard-copied-message')[0];
|
||||
|
||||
// Resets the animation.
|
||||
var elem = message;
|
||||
elem.style.display = 'none';
|
||||
elem.classList.remove('animated');
|
||||
|
||||
// Show the notification.
|
||||
setTimeout(function() {
|
||||
elem.style.display = 'inline-block';
|
||||
elem.classList.add('animated');
|
||||
}, 10);
|
||||
|
||||
// Reset the notification.
|
||||
setTimeout(function() {
|
||||
elem.style.display = 'none';
|
||||
}, 5000);
|
||||
});
|
||||
$scope.disabled = !button.clipboardCopy();
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
|
@ -2194,7 +2344,7 @@ quayApp.directive('externalLoginButton', function () {
|
|||
'provider': '@provider',
|
||||
'action': '@action'
|
||||
},
|
||||
controller: function($scope, $location, $timeout, ApiService, KeyService, UserService, CookieService, Features, Config) {
|
||||
controller: function($scope, $timeout, $interval, ApiService, KeyService, CookieService, Features, Config) {
|
||||
$scope.startSignin = function(service) {
|
||||
$scope.signInStarted({'service': service});
|
||||
|
||||
|
@ -2228,15 +2378,39 @@ quayApp.directive('signinForm', function () {
|
|||
'signInStarted': '&signInStarted',
|
||||
'signedIn': '&signedIn'
|
||||
},
|
||||
controller: function($scope, $location, $timeout, ApiService, KeyService, UserService, CookieService, Features, Config) {
|
||||
controller: function($scope, $location, $timeout, $interval, ApiService, KeyService, UserService, CookieService, Features, Config) {
|
||||
$scope.tryAgainSoon = 0;
|
||||
$scope.tryAgainInterval = null;
|
||||
|
||||
$scope.markStarted = function() {
|
||||
if ($scope.signInStarted != null) {
|
||||
$scope.signInStarted();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.cancelInterval = function() {
|
||||
$scope.tryAgainSoon = 0;
|
||||
|
||||
if ($scope.tryAgainInterval) {
|
||||
$interval.cancel($scope.tryAgainInterval);
|
||||
}
|
||||
|
||||
$scope.tryAgainInterval = null;
|
||||
};
|
||||
|
||||
$scope.$watch('user.username', function() {
|
||||
$scope.cancelInterval();
|
||||
});
|
||||
|
||||
$scope.$on('$destroy', function() {
|
||||
$scope.cancelInterval();
|
||||
});
|
||||
|
||||
$scope.signin = function() {
|
||||
if ($scope.tryAgainSoon > 0) { return; }
|
||||
|
||||
$scope.markStarted();
|
||||
$scope.cancelInterval();
|
||||
|
||||
ApiService.signinUser($scope.user).then(function() {
|
||||
$scope.needsEmailVerification = false;
|
||||
|
@ -2258,8 +2432,23 @@ quayApp.directive('signinForm', function () {
|
|||
$location.path($scope.redirectUrl ? $scope.redirectUrl : '/');
|
||||
}, 500);
|
||||
}, function(result) {
|
||||
$scope.needsEmailVerification = result.data.needsEmailVerification;
|
||||
$scope.invalidCredentials = result.data.invalidCredentials;
|
||||
if (result.status == 429 /* try again later */) {
|
||||
$scope.needsEmailVerification = false;
|
||||
$scope.invalidCredentials = false;
|
||||
|
||||
$scope.cancelInterval();
|
||||
|
||||
$scope.tryAgainSoon = result.headers('Retry-After');
|
||||
$scope.tryAgainInterval = $interval(function() {
|
||||
$scope.tryAgainSoon--;
|
||||
if ($scope.tryAgainSoon <= 0) {
|
||||
$scope.cancelInterval();
|
||||
}
|
||||
}, 1000, $scope.tryAgainSoon);
|
||||
} else {
|
||||
$scope.needsEmailVerification = result.data.needsEmailVerification;
|
||||
$scope.invalidCredentials = result.data.invalidCredentials;
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
@ -2370,11 +2559,42 @@ quayApp.directive('dockerAuthDialog', function (Config) {
|
|||
'username': '=username',
|
||||
'token': '=token',
|
||||
'shown': '=shown',
|
||||
'counter': '=counter'
|
||||
'counter': '=counter',
|
||||
'supportsRegenerate': '@supportsRegenerate',
|
||||
'regenerate': '®enerate'
|
||||
},
|
||||
controller: function($scope, $element) {
|
||||
controller: function($scope, $element) {
|
||||
var updateCommand = function() {
|
||||
var escape = function(v) {
|
||||
if (!v) { return v; }
|
||||
return v.replace('$', '\\$');
|
||||
};
|
||||
$scope.command = 'docker login -e="." -u="' + escape($scope.username) +
|
||||
'" -p="' + $scope.token + '" ' + Config['SERVER_HOSTNAME'];
|
||||
};
|
||||
|
||||
$scope.$watch('username', updateCommand);
|
||||
$scope.$watch('token', updateCommand);
|
||||
|
||||
$scope.regenerating = true;
|
||||
|
||||
$scope.askRegenerate = function() {
|
||||
bootbox.confirm('Are you sure you want to regenerate the token? All existing login credentials will become invalid', function(resp) {
|
||||
if (resp) {
|
||||
$scope.regenerating = true;
|
||||
$scope.regenerate({'username': $scope.username, 'token': $scope.token});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.isDownloadSupported = function() {
|
||||
try { return !!new Blob(); } catch(e){}
|
||||
var isSafari = /^((?!chrome).)*safari/i.test(navigator.userAgent);
|
||||
if (isSafari) {
|
||||
// Doesn't work properly in Safari, sadly.
|
||||
return false;
|
||||
}
|
||||
|
||||
try { return !!new Blob(); } catch(e) {}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
@ -2392,6 +2612,8 @@ quayApp.directive('dockerAuthDialog', function (Config) {
|
|||
};
|
||||
|
||||
var show = function(r) {
|
||||
$scope.regenerating = false;
|
||||
|
||||
if (!$scope.shown || !$scope.username || !$scope.token) {
|
||||
$('#dockerauthmodal').modal('hide');
|
||||
return;
|
||||
|
@ -2632,6 +2854,8 @@ quayApp.directive('logsView', function () {
|
|||
return 'Delete notification of event "' + eventData['title'] + '" for repository {repo}';
|
||||
},
|
||||
|
||||
'regenerate_robot_token': 'Regenerated token for robot {robot}',
|
||||
|
||||
// Note: These are deprecated.
|
||||
'add_repo_webhook': 'Add webhook in repository {repo}',
|
||||
'delete_repo_webhook': 'Delete webhook in repository {repo}'
|
||||
|
@ -2675,6 +2899,7 @@ quayApp.directive('logsView', function () {
|
|||
'reset_application_client_secret': 'Reset Client Secret',
|
||||
'add_repo_notification': 'Add repository notification',
|
||||
'delete_repo_notification': 'Delete repository notification',
|
||||
'regenerate_robot_token': 'Regenerate Robot Token',
|
||||
|
||||
// Note: these are deprecated.
|
||||
'add_repo_webhook': 'Add webhook',
|
||||
|
@ -2801,18 +3026,7 @@ quayApp.directive('applicationManager', function () {
|
|||
|
||||
ApiService.createOrganizationApplication(data, params).then(function(resp) {
|
||||
$scope.applications.push(resp);
|
||||
}, function(resp) {
|
||||
bootbox.dialog({
|
||||
"message": resp['message'] || 'The application could not be created',
|
||||
"title": "Cannot create application",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}, ApiService.errorDisplay('Cannot create application'));
|
||||
};
|
||||
|
||||
var update = function() {
|
||||
|
@ -2857,6 +3071,20 @@ quayApp.directive('robotsManager', function () {
|
|||
$scope.shownRobot = null;
|
||||
$scope.showRobotCounter = 0;
|
||||
|
||||
$scope.regenerateToken = function(username) {
|
||||
if (!username) { return; }
|
||||
|
||||
var shortName = $scope.getShortenedName(username);
|
||||
ApiService.regenerateRobotToken($scope.organization, null, {'robot_shortname': shortName}).then(function(updated) {
|
||||
var index = $scope.findRobotIndexByName(username);
|
||||
if (index >= 0) {
|
||||
$scope.robots.splice(index, 1);
|
||||
$scope.robots.push(updated);
|
||||
}
|
||||
$scope.shownRobot = updated;
|
||||
}, ApiService.errorDisplay('Cannot regenerate robot account token'));
|
||||
};
|
||||
|
||||
$scope.showRobot = function(info) {
|
||||
$scope.shownRobot = info;
|
||||
$scope.showRobotCounter++;
|
||||
|
@ -2897,18 +3125,7 @@ quayApp.directive('robotsManager', function () {
|
|||
if (index >= 0) {
|
||||
$scope.robots.splice(index, 1);
|
||||
}
|
||||
}, function() {
|
||||
bootbox.dialog({
|
||||
"message": 'The selected robot account could not be deleted',
|
||||
"title": "Cannot delete robot account",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}, ApiService.errorDisplay('Cannot delete robot account'));
|
||||
};
|
||||
|
||||
var update = function() {
|
||||
|
@ -2973,18 +3190,7 @@ quayApp.directive('prototypeManager', function () {
|
|||
|
||||
ApiService.updateOrganizationPrototypePermission(data, params).then(function(resp) {
|
||||
prototype.role = role;
|
||||
}, function(resp) {
|
||||
bootbox.dialog({
|
||||
"message": resp.data ? resp.data : 'The permission could not be modified',
|
||||
"title": "Cannot modify permission",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}, ApiService.errorDisplay('Cannot modify permission'));
|
||||
};
|
||||
|
||||
$scope.comparePrototypes = function(p) {
|
||||
|
@ -3024,23 +3230,16 @@ quayApp.directive('prototypeManager', function () {
|
|||
data['activating_user'] = $scope.activatingForNew;
|
||||
}
|
||||
|
||||
var errorHandler = ApiService.errorDisplay('Cannot create permission',
|
||||
function(resp) {
|
||||
$('#addPermissionDialogModal').modal('hide');
|
||||
});
|
||||
|
||||
ApiService.createOrganizationPrototypePermission(data, params).then(function(resp) {
|
||||
$scope.prototypes.push(resp);
|
||||
$scope.loading = false;
|
||||
$('#addPermissionDialogModal').modal('hide');
|
||||
}, function(resp) {
|
||||
$('#addPermissionDialogModal').modal('hide');
|
||||
bootbox.dialog({
|
||||
"message": resp.data ? resp.data : 'The permission could not be created',
|
||||
"title": "Cannot create permission",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}, errorHandler);
|
||||
};
|
||||
|
||||
$scope.deletePrototype = function(prototype) {
|
||||
|
@ -3054,18 +3253,7 @@ quayApp.directive('prototypeManager', function () {
|
|||
ApiService.deleteOrganizationPrototypePermission(null, params).then(function(resp) {
|
||||
$scope.prototypes.splice($scope.prototypes.indexOf(prototype), 1);
|
||||
$scope.loading = false;
|
||||
}, function(resp) {
|
||||
bootbox.dialog({
|
||||
"message": resp.data ? resp.data : 'The permission could not be deleted',
|
||||
"title": "Cannot delete permission",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}, ApiService.errorDisplay('Cannot delete permission'));
|
||||
};
|
||||
|
||||
var update = function() {
|
||||
|
@ -3836,9 +4024,11 @@ quayApp.directive('billingOptions', function () {
|
|||
|
||||
var save = function() {
|
||||
$scope.working = true;
|
||||
|
||||
var errorHandler = ApiService.errorDisplay('Could not change user details');
|
||||
ApiService.changeDetails($scope.organization, $scope.obj).then(function(resp) {
|
||||
$scope.working = false;
|
||||
});
|
||||
}, errorHandler);
|
||||
};
|
||||
|
||||
var checkSave = function() {
|
||||
|
@ -3890,7 +4080,7 @@ quayApp.directive('planManager', function () {
|
|||
return true;
|
||||
};
|
||||
|
||||
$scope.changeSubscription = function(planId) {
|
||||
$scope.changeSubscription = function(planId, opt_async) {
|
||||
if ($scope.planChanging) { return; }
|
||||
|
||||
var callbacks = {
|
||||
|
@ -3904,7 +4094,7 @@ quayApp.directive('planManager', function () {
|
|||
}
|
||||
};
|
||||
|
||||
PlanService.changePlan($scope, $scope.organization, planId, callbacks);
|
||||
PlanService.changePlan($scope, $scope.organization, planId, callbacks, opt_async);
|
||||
};
|
||||
|
||||
$scope.cancelSubscription = function() {
|
||||
|
@ -3967,7 +4157,7 @@ quayApp.directive('planManager', function () {
|
|||
if ($scope.readyForPlan) {
|
||||
var planRequested = $scope.readyForPlan();
|
||||
if (planRequested && planRequested != PlanService.getFreePlan()) {
|
||||
$scope.changeSubscription(planRequested);
|
||||
$scope.changeSubscription(planRequested, /* async */true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -3998,7 +4188,7 @@ quayApp.directive('namespaceSelector', function () {
|
|||
'namespace': '=namespace',
|
||||
'requireCreate': '=requireCreate'
|
||||
},
|
||||
controller: function($scope, $element, $routeParams, CookieService) {
|
||||
controller: function($scope, $element, $routeParams, $location, CookieService) {
|
||||
$scope.namespaces = {};
|
||||
|
||||
$scope.initialize = function(user) {
|
||||
|
@ -4035,6 +4225,10 @@ quayApp.directive('namespaceSelector', function () {
|
|||
|
||||
if (newNamespace) {
|
||||
CookieService.putPermanent('quay.namespace', newNamespace);
|
||||
|
||||
if ($routeParams['namespace'] && $routeParams['namespace'] != newNamespace) {
|
||||
$location.search({'namespace': newNamespace});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -4385,26 +4579,17 @@ quayApp.directive('setupTriggerDialog', function () {
|
|||
|
||||
$scope.activating = true;
|
||||
|
||||
var errorHandler = ApiService.errorDisplay('Cannot activate build trigger', function(resp) {
|
||||
$scope.hide();
|
||||
$scope.canceled({'trigger': $scope.trigger});
|
||||
});
|
||||
|
||||
ApiService.activateBuildTrigger(data, params).then(function(resp) {
|
||||
$scope.hide();
|
||||
$scope.trigger['is_active'] = true;
|
||||
$scope.trigger['pull_robot'] = resp['pull_robot'];
|
||||
$scope.activated({'trigger': $scope.trigger});
|
||||
}, function(resp) {
|
||||
$scope.hide();
|
||||
$scope.canceled({'trigger': $scope.trigger});
|
||||
|
||||
bootbox.dialog({
|
||||
"message": resp['data']['message'] || 'The build trigger setup could not be completed',
|
||||
"title": "Could not activate build trigger",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}, errorHandler);
|
||||
};
|
||||
|
||||
var check = function() {
|
||||
|
@ -4744,6 +4929,9 @@ quayApp.directive('buildMessage', function () {
|
|||
case 'waiting':
|
||||
return 'Waiting for available build worker';
|
||||
|
||||
case 'unpacking':
|
||||
return 'Unpacking build package';
|
||||
|
||||
case 'pulling':
|
||||
return 'Pulling base image';
|
||||
|
||||
|
@ -4799,6 +4987,7 @@ quayApp.directive('buildProgress', function () {
|
|||
case 'starting':
|
||||
case 'waiting':
|
||||
case 'cannot_load':
|
||||
case 'unpacking':
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
@ -5018,6 +5207,23 @@ quayApp.directive('twitterView', function () {
|
|||
});
|
||||
|
||||
|
||||
quayApp.directive('notificationsBubble', function () {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
templateUrl: '/static/directives/notifications-bubble.html',
|
||||
replace: false,
|
||||
transclude: false,
|
||||
restrict: 'C',
|
||||
scope: {
|
||||
},
|
||||
controller: function($scope, UserService, NotificationService) {
|
||||
$scope.notificationService = NotificationService;
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
});
|
||||
|
||||
|
||||
quayApp.directive('notificationView', function () {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
|
@ -5329,7 +5535,9 @@ quayApp.directive('locationView', function () {
|
|||
'local_us': { 'country': 'US', 'data': 'quay-registry.s3.amazonaws.com', 'title': 'United States' },
|
||||
'local_eu': { 'country': 'EU', 'data': 'quay-registry-eu.s3-eu-west-1.amazonaws.com', 'title': 'Europe' },
|
||||
|
||||
's3_us_east_1': { 'country': 'US', 'data': 'quay-registry.s3.amazonaws.com', 'title': 'United States' },
|
||||
's3_us_east_1': { 'country': 'US', 'data': 'quay-registry.s3.amazonaws.com', 'title': 'United States (East)' },
|
||||
's3_us_west_1': { 'country': 'US', 'data': 'quay-registry-cali.s3.amazonaws.com', 'title': 'United States (West)' },
|
||||
|
||||
's3_eu_west_1': { 'country': 'EU', 'data': 'quay-registry-eu.s3-eu-west-1.amazonaws.com', 'title': 'Europe' },
|
||||
|
||||
's3_ap_southeast_1': { 'country': 'SG', 'data': 'quay-registry-singapore.s3-ap-southeast-1.amazonaws.com', 'title': 'Singapore' },
|
||||
|
@ -5344,7 +5552,9 @@ quayApp.directive('locationView', function () {
|
|||
|
||||
$scope.getLocationTooltip = function(location, ping) {
|
||||
var tip = $scope.getLocationTitle(location) + '<br>';
|
||||
if (ping < 0) {
|
||||
if (ping == null) {
|
||||
tip += '(Loading)';
|
||||
} else if (ping < 0) {
|
||||
tip += '<br><b>Note: Could not contact server</b>';
|
||||
} else {
|
||||
tip += 'Estimated Ping: ' + (ping ? ping + 'ms' : '(Loading)');
|
||||
|
@ -5367,7 +5577,7 @@ quayApp.directive('locationView', function () {
|
|||
};
|
||||
|
||||
$scope.getLocationPing = function(location) {
|
||||
var url = 'http://' + LOCATIONS[location]['data'] + '/okay.txt';
|
||||
var url = 'https://' + LOCATIONS[location]['data'] + '/okay.txt';
|
||||
PingService.pingUrl($scope, url, function(ping, success, count) {
|
||||
if (count == 3 || !success) {
|
||||
$scope.locationPing = success ? ping : -1;
|
||||
|
@ -5424,7 +5634,8 @@ quayApp.directive('tagSpecificImagesView', function () {
|
|||
scope: {
|
||||
'repository': '=repository',
|
||||
'tag': '=tag',
|
||||
'images': '=images'
|
||||
'images': '=images',
|
||||
'imageCutoff': '=imageCutoff'
|
||||
},
|
||||
controller: function($scope, $element) {
|
||||
$scope.getFirstTextLine = getFirstTextLine;
|
||||
|
@ -5446,7 +5657,7 @@ quayApp.directive('tagSpecificImagesView', function () {
|
|||
return classes;
|
||||
};
|
||||
|
||||
var forAllTagImages = function(tag, callback) {
|
||||
var forAllTagImages = function(tag, callback, opt_cutoff) {
|
||||
if (!tag) { return; }
|
||||
|
||||
if (!$scope.imageByDBID) {
|
||||
|
@ -5464,10 +5675,14 @@ quayApp.directive('tagSpecificImagesView', function () {
|
|||
|
||||
callback(tag_image);
|
||||
|
||||
var ancestors = tag_image.ancestors.split('/');
|
||||
var ancestors = tag_image.ancestors.split('/').reverse();
|
||||
for (var i = 0; i < ancestors.length; ++i) {
|
||||
var image = $scope.imageByDBID[ancestors[i]];
|
||||
if (image) {
|
||||
if (image == opt_cutoff) {
|
||||
return;
|
||||
}
|
||||
|
||||
callback(image);
|
||||
}
|
||||
}
|
||||
|
@ -5489,7 +5704,7 @@ quayApp.directive('tagSpecificImagesView', function () {
|
|||
var ids = {};
|
||||
forAllTagImages(currentTag, function(image) {
|
||||
ids[image.dbid] = true;
|
||||
});
|
||||
}, $scope.imageCutoff);
|
||||
return ids;
|
||||
};
|
||||
|
||||
|
@ -5587,15 +5802,14 @@ quayApp.run(['$location', '$rootScope', 'Restangular', 'UserService', 'PlanServi
|
|||
|
||||
// Handle session expiration.
|
||||
Restangular.setErrorInterceptor(function(response) {
|
||||
if (response.status == 401) {
|
||||
if (response.data['session_required'] == null || response.data['session_required'] === true) {
|
||||
$('#sessionexpiredModal').modal({});
|
||||
return false;
|
||||
}
|
||||
if (response.status == 401 && response.data['error_type'] == 'invalid_token' &&
|
||||
response.data['session_required'] !== false) {
|
||||
$('#sessionexpiredModal').modal({});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Features.BILLING && response.status == 402) {
|
||||
$('#overlicenseModal').modal({});
|
||||
if (response.status == 503) {
|
||||
$('#cannotContactService').modal({});
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,25 +1,3 @@
|
|||
$.fn.clipboardCopy = function() {
|
||||
var clip = new ZeroClipboard($(this), { 'moviePath': 'static/lib/ZeroClipboard.swf' });
|
||||
|
||||
clip.on('complete', function() {
|
||||
// Resets the animation.
|
||||
var elem = $('#clipboardCopied')[0];
|
||||
if (!elem) {
|
||||
return;
|
||||
}
|
||||
|
||||
elem.style.display = 'none';
|
||||
elem.classList.remove('animated');
|
||||
|
||||
// Show the notification.
|
||||
setTimeout(function() {
|
||||
if (!elem) { return; }
|
||||
elem.style.display = 'inline-block';
|
||||
elem.classList.add('animated');
|
||||
}, 10);
|
||||
});
|
||||
};
|
||||
|
||||
function GuideCtrl() {
|
||||
}
|
||||
|
||||
|
@ -431,6 +409,27 @@ function RepoCtrl($scope, $sanitize, Restangular, ImageMetadataService, ApiServi
|
|||
$location.search('current', buildInfo.id);
|
||||
};
|
||||
|
||||
$scope.isPushing = function(images) {
|
||||
if (!images) { return false; }
|
||||
|
||||
var cached = images.__isPushing;
|
||||
if (cached !== undefined) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
return images.__isPushing = $scope.isPushingInternal(images);
|
||||
};
|
||||
|
||||
$scope.isPushingInternal = function(images) {
|
||||
if (!images) { return false; }
|
||||
|
||||
for (var i = 0; i < images.length; ++i) {
|
||||
if (images[i].uploading) { return true; }
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
$scope.getTooltipCommand = function(image) {
|
||||
var sanitized = ImageMetadataService.getEscapedFormattedCommand(image);
|
||||
return '<span class=\'codetooltip\'>' + sanitized + '</span>';
|
||||
|
@ -511,48 +510,37 @@ function RepoCtrl($scope, $sanitize, Restangular, ImageMetadataService, ApiServi
|
|||
'image': image.id
|
||||
};
|
||||
|
||||
var errorHandler = ApiService.errorDisplay('Cannot create or move tag', function(resp) {
|
||||
$('#addTagModal').modal('hide');
|
||||
});
|
||||
|
||||
ApiService.changeTagImage(data, params).then(function(resp) {
|
||||
$scope.creatingTag = false;
|
||||
loadViewInfo();
|
||||
$('#addTagModal').modal('hide');
|
||||
}, function(resp) {
|
||||
$('#addTagModal').modal('hide');
|
||||
bootbox.dialog({
|
||||
"message": resp.data ? resp.data : 'Could not create or move tag',
|
||||
"title": "Cannot create or move tag",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}, errorHandler);
|
||||
};
|
||||
|
||||
$scope.deleteTag = function(tagName) {
|
||||
if (!$scope.repo.can_admin) { return; }
|
||||
$('#confirmdeleteTagModal').modal('hide');
|
||||
|
||||
var params = {
|
||||
'repository': namespace + '/' + name,
|
||||
'tag': tagName
|
||||
};
|
||||
|
||||
var errorHandler = ApiService.errorDisplay('Cannot delete tag', function() {
|
||||
$('#confirmdeleteTagModal').modal('hide');
|
||||
$scope.deletingTag = false;
|
||||
});
|
||||
|
||||
$scope.deletingTag = true;
|
||||
|
||||
ApiService.deleteFullTag(null, params).then(function() {
|
||||
loadViewInfo();
|
||||
}, function(resp) {
|
||||
bootbox.dialog({
|
||||
"message": resp.data ? resp.data : 'Could not delete tag',
|
||||
"title": "Cannot delete tag",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#confirmdeleteTagModal').modal('hide');
|
||||
$scope.deletingTag = false;
|
||||
}, errorHandler);
|
||||
};
|
||||
|
||||
$scope.getImagesForTagBySize = function(tag) {
|
||||
|
@ -731,8 +719,6 @@ function RepoCtrl($scope, $sanitize, Restangular, ImageMetadataService, ApiServi
|
|||
|
||||
// Load the builds for this repository. If none are active it will cancel the poll.
|
||||
startBuildInfoTimer(repo);
|
||||
|
||||
$('#copyClipboard').clipboardCopy();
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -1341,17 +1327,16 @@ function RepoAdminCtrl($scope, Restangular, ApiService, KeyService, $routeParams
|
|||
};
|
||||
|
||||
$scope.deleteRole = function(entityName, kind) {
|
||||
var errorHandler = ApiService.errorDisplay('Cannot change permission', function(resp) {
|
||||
if (resp.status == 409) {
|
||||
return 'Cannot change permission as you do not have the authority';
|
||||
}
|
||||
});
|
||||
|
||||
var permissionDelete = Restangular.one(getRestUrl('repository', namespace, name, 'permissions', kind, entityName));
|
||||
permissionDelete.customDELETE().then(function() {
|
||||
delete $scope.permissions[kind][entityName];
|
||||
}, function(resp) {
|
||||
if (resp.status == 409) {
|
||||
$scope.changePermError = resp.data || '';
|
||||
$('#channgechangepermModal').modal({});
|
||||
} else {
|
||||
$('#cannotchangeModal').modal({});
|
||||
}
|
||||
});
|
||||
}, errorHandler);
|
||||
};
|
||||
|
||||
$scope.addRole = function(entityName, role, kind) {
|
||||
|
@ -1362,9 +1347,7 @@ function RepoAdminCtrl($scope, Restangular, ApiService, KeyService, $routeParams
|
|||
var permissionPost = Restangular.one(getRestUrl('repository', namespace, name, 'permissions', kind, entityName));
|
||||
permissionPost.customPUT(permission).then(function(result) {
|
||||
$scope.permissions[kind][entityName] = result;
|
||||
}, function(result) {
|
||||
$('#cannotchangeModal').modal({});
|
||||
});
|
||||
}, ApiService.errorDisplay('Cannot change permission'));
|
||||
};
|
||||
|
||||
$scope.roles = [
|
||||
|
@ -1579,18 +1562,7 @@ function RepoAdminCtrl($scope, Restangular, ApiService, KeyService, $routeParams
|
|||
window.console.log(resp);
|
||||
var url = '/repository/' + namespace + '/' + name + '/build?current=' + resp['id'];
|
||||
document.location = url;
|
||||
}, function(resp) {
|
||||
bootbox.dialog({
|
||||
"message": resp['message'] || 'The build could not be started',
|
||||
"title": "Could not start build",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}, ApiService.errorDisplay('Could not start build'));
|
||||
};
|
||||
|
||||
$scope.deleteTrigger = function(trigger) {
|
||||
|
@ -1720,18 +1692,7 @@ function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, Use
|
|||
|
||||
ApiService.deleteUserAuthorization(null, params).then(function(resp) {
|
||||
$scope.authorizedApps.splice($scope.authorizedApps.indexOf(accessTokenInfo), 1);
|
||||
}, function(resp) {
|
||||
bootbox.dialog({
|
||||
"message": resp.message || 'Could not revoke authorization',
|
||||
"title": "Cannot revoke authorization",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}, ApiService.errorDisplay('Could not revoke authorization'));
|
||||
};
|
||||
|
||||
$scope.loadLogs = function() {
|
||||
|
@ -1740,7 +1701,6 @@ function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, Use
|
|||
};
|
||||
|
||||
$scope.loadInvoices = function() {
|
||||
if (!$scope.hasPaidBusinessPlan) { return; }
|
||||
$scope.invoicesShown++;
|
||||
};
|
||||
|
||||
|
@ -1809,7 +1769,7 @@ function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, Use
|
|||
$scope.changeEmailForm.$setPristine();
|
||||
}, function(result) {
|
||||
$scope.updatingUser = false;
|
||||
UIService.showFormError('#changeEmailForm', result);
|
||||
UIService.showFormError('#changeEmailForm', result);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -1819,7 +1779,8 @@ function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, Use
|
|||
$scope.updatingUser = true;
|
||||
$scope.changePasswordSuccess = false;
|
||||
|
||||
ApiService.changeUserDetails($scope.cuser).then(function() {
|
||||
ApiService.changeUserDetails($scope.cuser).then(function(resp) {
|
||||
|
||||
$scope.updatingUser = false;
|
||||
$scope.changePasswordSuccess = true;
|
||||
|
||||
|
@ -1926,9 +1887,6 @@ function ImageViewCtrl($scope, $routeParams, $rootScope, $timeout, ApiService, I
|
|||
|
||||
// Fetch the image's changes.
|
||||
fetchChanges();
|
||||
|
||||
$('#copyClipboard').clipboardCopy();
|
||||
|
||||
return image;
|
||||
});
|
||||
};
|
||||
|
@ -2196,13 +2154,14 @@ function OrgViewCtrl($rootScope, $scope, ApiService, $routeParams) {
|
|||
'teamname': teamname
|
||||
};
|
||||
|
||||
var errorHandler = ApiService.errorDisplay('Cannot delete team', function() {
|
||||
$scope.currentDeleteTeam = null;
|
||||
});
|
||||
|
||||
ApiService.deleteOrganizationTeam(null, params).then(function() {
|
||||
delete $scope.organization.teams[teamname];
|
||||
$scope.currentDeleteTeam = null;
|
||||
}, function() {
|
||||
$('#cannotchangeModal').modal({});
|
||||
$scope.currentDeleteTeam = null;
|
||||
});
|
||||
}, errorHandler);
|
||||
};
|
||||
|
||||
var loadOrganization = function() {
|
||||
|
@ -2496,9 +2455,9 @@ function NewOrgCtrl($scope, $routeParams, $timeout, $location, UserService, Plan
|
|||
};
|
||||
|
||||
PlanService.changePlan($scope, org.name, $scope.holder.currentPlan.stripeId, callbacks);
|
||||
}, function(result) {
|
||||
}, function(resp) {
|
||||
$scope.creating = false;
|
||||
$scope.createError = result.data.error_description || result.data;
|
||||
$scope.createError = ApiService.getErrorMessage(resp);
|
||||
$timeout(function() {
|
||||
$('#orgName').popover('show');
|
||||
});
|
||||
|
@ -2575,18 +2534,7 @@ function ManageApplicationCtrl($scope, $routeParams, $rootScope, $location, $tim
|
|||
$timeout(function() {
|
||||
$location.path('/organization/' + orgname + '/admin');
|
||||
}, 500);
|
||||
}, function(resp) {
|
||||
bootbox.dialog({
|
||||
"message": resp.message || 'Could not delete application',
|
||||
"title": "Cannot delete application",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}, ApiService.errorDisplay('Could not delete application'));
|
||||
};
|
||||
|
||||
$scope.updateApplication = function() {
|
||||
|
@ -2604,22 +2552,13 @@ function ManageApplicationCtrl($scope, $routeParams, $rootScope, $location, $tim
|
|||
delete $scope.application['gravatar_email'];
|
||||
}
|
||||
|
||||
var errorHandler = ApiService.errorDisplay('Could not update application', function(resp) {
|
||||
$scope.updating = false;
|
||||
});
|
||||
|
||||
ApiService.updateOrganizationApplication($scope.application, params).then(function(resp) {
|
||||
$scope.application = resp;
|
||||
$scope.updating = false;
|
||||
}, function(resp) {
|
||||
$scope.updating = false;
|
||||
bootbox.dialog({
|
||||
"message": resp.message || 'Could not update application',
|
||||
"title": "Cannot update application",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}, errorHandler);
|
||||
};
|
||||
|
||||
$scope.resetClientSecret = function() {
|
||||
|
@ -2632,18 +2571,7 @@ function ManageApplicationCtrl($scope, $routeParams, $rootScope, $location, $tim
|
|||
|
||||
ApiService.resetOrganizationApplicationClientSecret(null, params).then(function(resp) {
|
||||
$scope.application = resp;
|
||||
}, function(resp) {
|
||||
bootbox.dialog({
|
||||
"message": resp.message || 'Could not reset client secret',
|
||||
"title": "Cannot reset client secret",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}, ApiService.errorDisplay('Could not reset client secret'));
|
||||
};
|
||||
|
||||
var loadOrganization = function() {
|
||||
|
@ -2739,18 +2667,7 @@ function SuperUserAdminCtrl($scope, ApiService, Features, UserService) {
|
|||
|
||||
ApiService.changeInstallUser(data, params).then(function(resp) {
|
||||
$scope.loadUsersInternal();
|
||||
}, function(resp) {
|
||||
bootbox.dialog({
|
||||
"message": resp.data ? resp.data.message : 'Could not change user',
|
||||
"title": "Cannot change user",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}, ApiService.errorDisplay('Could not change user'));
|
||||
};
|
||||
|
||||
$scope.deleteUser = function(user) {
|
||||
|
@ -2762,49 +2679,10 @@ function SuperUserAdminCtrl($scope, ApiService, Features, UserService) {
|
|||
|
||||
ApiService.deleteInstallUser(null, params).then(function(resp) {
|
||||
$scope.loadUsersInternal();
|
||||
}, function(resp) {
|
||||
bootbox.dialog({
|
||||
"message": resp.data ? resp.data.message : 'Could not delete user',
|
||||
"title": "Cannot delete user",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}, ApiService.errorDisplay('Cannot delete user'));
|
||||
};
|
||||
|
||||
var seatUsageLoaded = function(usage) {
|
||||
$scope.usageLoading = false;
|
||||
|
||||
if (usage.count > usage.allowed) {
|
||||
$scope.limit = 'over';
|
||||
} else if (usage.count == usage.allowed) {
|
||||
$scope.limit = 'at';
|
||||
} else if (usage.count >= usage.allowed * 0.7) {
|
||||
$scope.limit = 'near';
|
||||
} else {
|
||||
$scope.limit = 'none';
|
||||
}
|
||||
|
||||
if (!$scope.chart) {
|
||||
$scope.chart = new UsageChart();
|
||||
$scope.chart.draw('seat-usage-chart');
|
||||
}
|
||||
|
||||
$scope.chart.update(usage.count, usage.allowed);
|
||||
};
|
||||
|
||||
var loadSeatUsage = function() {
|
||||
$scope.usageLoading = true;
|
||||
ApiService.getSeatCount().then(function(resp) {
|
||||
seatUsageLoaded(resp);
|
||||
});
|
||||
};
|
||||
|
||||
loadSeatUsage();
|
||||
$scope.loadUsers();
|
||||
}
|
||||
|
||||
function TourCtrl($scope, $location) {
|
||||
|
|
|
@ -148,6 +148,8 @@ ImageHistoryTree.prototype.updateDimensions_ = function() {
|
|||
var ch = dimensions.ch;
|
||||
|
||||
// Set the height of the container so that it never goes offscreen.
|
||||
if (!$('#' + container).removeOverscroll) { return; }
|
||||
|
||||
$('#' + container).removeOverscroll();
|
||||
var viewportHeight = $(window).height();
|
||||
var boundingBox = document.getElementById(container).getBoundingClientRect();
|
||||
|
@ -402,6 +404,10 @@ ImageHistoryTree.prototype.buildRoot_ = function() {
|
|||
var roots = [];
|
||||
for (var i = 0; i < this.images_.length; ++i) {
|
||||
var image = this.images_[i];
|
||||
|
||||
// Skip images that are currently uploading.
|
||||
if (image.uploading) { continue; }
|
||||
|
||||
var imageNode = imageByDBID[image.dbid];
|
||||
var ancestors = this.getAncestors_(image);
|
||||
var immediateParent = ancestors[ancestors.length - 1] * 1;
|
||||
|
@ -432,6 +438,10 @@ ImageHistoryTree.prototype.buildRoot_ = function() {
|
|||
var maxChildCount = roots.length;
|
||||
for (var i = 0; i < this.images_.length; ++i) {
|
||||
var image = this.images_[i];
|
||||
|
||||
// Skip images that are currently uploading.
|
||||
if (image.uploading) { continue; }
|
||||
|
||||
var imageNode = imageByDBID[image.dbid];
|
||||
maxChildCount = Math.max(maxChildCount, this.determineMaximumChildCount_(imageNode));
|
||||
}
|
||||
|
@ -582,6 +592,10 @@ ImageHistoryTree.prototype.setTag_ = function(tagName) {
|
|||
// Ensure that the children are in the correct order.
|
||||
for (var i = 0; i < this.images_.length; ++i) {
|
||||
var image = this.images_[i];
|
||||
|
||||
// Skip images that are currently uploading.
|
||||
if (image.uploading) { continue; }
|
||||
|
||||
var imageNode = this.imageByDBID_[image.dbid];
|
||||
var ancestors = this.getAncestors_(image);
|
||||
var immediateParent = ancestors[ancestors.length - 1] * 1;
|
||||
|
|
17
static/lib/ZeroClipboard.min.js
vendored
Executable file → Normal file
BIN
static/lib/ZeroClipboard.swf
Executable file → Normal file
|
@ -7,41 +7,49 @@
|
|||
<div class="col-sm-12 about-basic-info">
|
||||
<h3>The Basics</h3>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="col-sm-3">
|
||||
<div class="about-basic-icon"><i class="fa fa-3x fa-calendar"></i></div>
|
||||
<div class="about-basic-text">
|
||||
<b> Founded</b><br>
|
||||
2012
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="col-sm-3">
|
||||
<div class="about-basic-icon"><i class="fa fa-3x fa-globe"></i></div>
|
||||
<div class="about-basic-text">
|
||||
<b> Location</b><br>
|
||||
New York City, NY
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="col-sm-3">
|
||||
<div class="about-basic-icon"><i class="fa fa-3x fa-users"></i></div>
|
||||
<div class="about-basic-text">
|
||||
<b> Worker Bees</b><br>
|
||||
<b> Local Worker Bees</b><br>
|
||||
2
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<div class="about-basic-icon"><img src="/static/img/coreos-globe-color-lg.png" style="height: 42px; vertical-align: bottom;"></div>
|
||||
<div class="about-basic-text">
|
||||
<b> CoreOS</b><br>
|
||||
August, 2014
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<h3>Our Story</h3>
|
||||
<p>Quay.io was originally created out of necessesity when we wanted to use Docker containers with DevTable IDE. We were using Docker containers to host and isolate server processes invoked on behalf of our users and often running their code. We started by building the Docker image dynamically whenever we spun up a new host node. The image was monolithic. It was too large, took too long to build, and was hard to manage conflicts. It was everything that Docker wasn't supposed to be. When we decided to split it up into pre-built images and host them somewhere, we noticed that there wasn't a good place to host images securely. Determined to scratch our own itch, we built Quay.io, and officially launched it as an aside in our presentation to the <a href="http://www.meetup.com/Docker-NewYorkCity/events/142142762/">Docker New York City Meetup</a> on October 2nd, 2013.</p>
|
||||
<p>Since that time, our users have demanded that Quay.io become our main focus. Our customers rely on us to make sure they can store and distribute their Docker images, and we understand that solemn responsibility. Our customers have been fantastic with giving us great feedback and suggestions. We are working as hard as we can to deliver on the promise and execute our vision of what a top notch Docker registry should be. We thank you for taking this journey with us.</p>
|
||||
<p>Quay.io was originally created out of necessesity when we wanted to use Docker containers with our original IDE product. We were using Docker containers to host and isolate server processes invoked on behalf of our users and often running their code. We started by building the Docker image dynamically whenever we spun up a new host node. The image was monolithic. It was too large, took too long to build, and was hard to manage conflicts. It was everything that Docker wasn't supposed to be. When we decided to split it up into pre-built images and host them somewhere, we noticed that there wasn't a good place to host images securely. Determined to scratch our own itch, we built Quay.io, and officially launched it as an aside in our presentation to the <a href="http://www.meetup.com/Docker-NewYorkCity/events/142142762/">Docker New York City Meetup</a> on October 2nd, 2013.</p>
|
||||
<p>After launch, our customers demanded that Quay.io become our main focus. They rely on us to make sure they can store and distribute their Docker images, and we understand that solemn responsibility. Our customers have been fantastic with giving us great feedback and suggestions.</p>
|
||||
<p>In August, 2014, Quay.io joined <a href="https://coreos.com">CoreOS</a> to provide registry support for the enterprise. As ever, we are working as hard as we can to deliver on the promise and execute our vision of what a top notch Docker registry should be.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<h3>The Team</h3>
|
||||
Our team is composed of two software engineers turned entrepreneurs:
|
||||
<h3>The Quay.io Team at CoreOS</h3>
|
||||
The Quay.io team is composed of two software engineers:
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
@ -67,12 +75,7 @@
|
|||
<img class="img-rounded founder-photo" src="http://www.gravatar.com/avatar/9fc3232622773fb2e8f71c0027601bc5?s=128&d=mm">
|
||||
</div>
|
||||
<div class="col-sm-7 col-md-10">
|
||||
<p>Joseph graduated from University of Pennsylvania with a Bachelors and Masters in Computer Science. After a record setting (probably) five internships with Google, he took a full time position there to continue his work on exciting products such as Google Spreadsheets, the Google Closure Compiler, and Google APIs. Joseph was one of the original duo responsible for inventing the language and framework on which DevTable is built.</p>
|
||||
<p>Joseph graduated from University of Pennsylvania with a Bachelors and Masters in Computer Science. After a record setting (probably) five internships with Google, he took a full time position there to continue his work on exciting products such as Google Spreadsheets, the Google Closure Compiler, and Google APIs. </p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<p>With a combined 10 years experience building tools for software engineers, our founding team knows what it takes to make software engineers happy doing their work. Combined with our love for the web, we are ready to make a difference in the way people think about software development in the cloud.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
<div class="landing-background" ng-class="user.anonymous ? 'landing': 'signedin'"></div>
|
||||
<div class="landing-filter" ng-class="user.anonymous ? 'landing': 'signedin'"></div>
|
||||
<div class="landing-content">
|
||||
<img class="logo" src="/static/img/white_horizontal.png">
|
||||
|
||||
<div class="header-bar"></div>
|
||||
|
||||
<div class="container">
|
||||
<div class="row messages">
|
||||
<div class="col-md-7">
|
||||
|
@ -28,7 +24,7 @@
|
|||
<a ng-href="/repository/{{ repository.namespace }}/{{ repository.name }}">{{repository.namespace}}/{{repository.name}}</a>
|
||||
<div class="markdown-view description" content="repository.description" first-line-only="true"></div>
|
||||
</div>
|
||||
<a href="/repository/?namespace={{ user.username }}">See All Repositories</a>
|
||||
<a href="/repository/?namespace={{ namespace }}">See All Repositories</a>
|
||||
</div>
|
||||
|
||||
<!-- No Repos -->
|
||||
|
|
|
@ -1,18 +1,25 @@
|
|||
<div class="jumbotron landing">
|
||||
<div class="announcement">
|
||||
<span class="hidden-xs-inline">
|
||||
<img src="/static/img/white_horizontal.png" style="height: 40px">
|
||||
<span class="plus">+</span>
|
||||
<img src="/static/img/coreos-wordmark-horiz-white.svg">
|
||||
</span>
|
||||
|
||||
<span class="spacer"></span>
|
||||
Quay.io is now part of CoreOS! <a href="http://blog.devtable.com/" target="_blank">Read the blog post.</a>
|
||||
</div>
|
||||
|
||||
<div class="landing-background" ng-class="user.anonymous ? 'landing': 'signedin'"></div>
|
||||
<div class="landing-filter" ng-class="user.anonymous ? 'landing': 'signedin'"></div>
|
||||
<div class="landing-content">
|
||||
<img class="logo" src="/static/img/white_horizontal.png">
|
||||
|
||||
<div class="header-bar"></div>
|
||||
|
||||
<div class="landing-content">
|
||||
<div class="container">
|
||||
<div class="row messages">
|
||||
<div class="col-md-7">
|
||||
<div ng-show="user.anonymous">
|
||||
<h1>Secure hosting for <b>private</b> Docker<a class="disclaimer-link" href="/disclaimer" target="_self">*</a> repositories</h1>
|
||||
<h3>Use the Docker images <b>your team</b> needs with the safety of <b>private</b> repositories</h3>
|
||||
<div class="sellcall"><a href="/plans/">Private repository plans starting at $12/mo</a></div>
|
||||
<a href="/plans/?trial-plan=bus-coreos-trial" class="call-to-action">Get 20 free private repos for 6 months<i class="fa fa-arrow-right"></i></a>
|
||||
</div>
|
||||
|
||||
<div ng-show="!user.anonymous">
|
||||
|
@ -27,7 +34,7 @@
|
|||
<a ng-href="/repository/{{ repository.namespace }}/{{ repository.name }}">{{repository.namespace}}/{{repository.name}}</a>
|
||||
<div class="markdown-view description" content="repository.description" first-line-only="true"></div>
|
||||
</div>
|
||||
<a href="/repository/?namespace={{ user.username }}">See All Repositories</a>
|
||||
<a href="/repository/?namespace={{ namespace }}">See All Repositories</a>
|
||||
</div>
|
||||
|
||||
<!-- No Repos -->
|
||||
|
@ -265,7 +272,7 @@
|
|||
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="container" ng-if="user.anonymous">
|
||||
<div class="row">
|
||||
<div style="border-top: 1px solid #eee; padding-top: 20px;" class="col-md-12">
|
||||
<a href="https://mixpanel.com/f/partner"><img src="//cdn.mxpnl.com/site_media/images/partner/badge_light.png" alt="Mobile Analytics" /></a>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<div class="container create-org" ng-show="!creating">
|
||||
|
||||
<div class="row header-row">
|
||||
<div class="col-md-8 col-md-offset-1">
|
||||
<div class="col-md-12">
|
||||
<h2>Create Organization</h2>
|
||||
|
||||
<div class="steps-container" ng-show="false">
|
||||
|
@ -44,8 +44,7 @@
|
|||
|
||||
<!-- Step 2 -->
|
||||
<div class="row" ng-show="user && !user.anonymous && !created">
|
||||
<div class="col-md-1"></div>
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-12">
|
||||
<div class="step-container">
|
||||
<h3>Setup the new organization</h3>
|
||||
|
||||
|
@ -54,7 +53,7 @@
|
|||
<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" data-container="body" ng-pattern="/^[a-z0-9_]{4,30}$/">
|
||||
data-placement="bottom" data-container="body" ng-pattern="/^[a-z0-9_]{4,30}$/">
|
||||
<span class="description">This will also be the namespace for your repositories</span>
|
||||
</div>
|
||||
|
||||
|
@ -85,8 +84,7 @@
|
|||
|
||||
<!-- Step 3 -->
|
||||
<div class="row" ng-show="user && !user.anonymous && created">
|
||||
<div class="col-md-1"></div>
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-12">
|
||||
<div class="step-container">
|
||||
<h3>Organization Created</h3>
|
||||
<h4><a href="/organization/{{ org.name }}">Manage Teams Now</a></h4>
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
|
||||
<!-- Header -->
|
||||
<div class="row">
|
||||
<div class="col-md-1"></div>
|
||||
<div class="col-md-8">
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="section">
|
||||
<div class="new-header">
|
||||
<span style="color: #444;">
|
||||
|
@ -45,8 +45,8 @@
|
|||
|
||||
<!-- Private/public -->
|
||||
<div class="row">
|
||||
<div class="col-md-1"></div>
|
||||
<div class="col-md-8">
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="section-title">Repository Visibility</div>
|
||||
<div class="section">
|
||||
<div class="repo-option">
|
||||
|
@ -98,8 +98,8 @@
|
|||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-1"></div>
|
||||
<div class="col-md-8">
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="section">
|
||||
<div class="section-title">Initialize repository</div>
|
||||
|
||||
|
@ -137,8 +137,8 @@
|
|||
</div>
|
||||
|
||||
<div class="row" ng-show="repo.initialize == 'dockerfile' || repo.initialize == 'zipfile'">
|
||||
<div class="col-md-1"></div>
|
||||
<div class="col-md-8">
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="section">
|
||||
<div class="section-title">Upload <span ng-if="repo.initialize == 'dockerfile'">Dockerfile</span><span ng-if="repo.initialize == 'zipfile'">Archive</span></div>
|
||||
<div style="padding-top: 20px;">
|
||||
|
@ -153,8 +153,8 @@
|
|||
</div>
|
||||
|
||||
<div class="row" ng-show="repo.initialize == 'github'">
|
||||
<div class="col-md-1"></div>
|
||||
<div class="col-md-8">
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="alert alert-info">
|
||||
You will be redirected to authorize via GitHub once the repository has been created
|
||||
</div>
|
||||
|
@ -162,8 +162,8 @@
|
|||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-1"></div>
|
||||
<div class="col-md-8">
|
||||
|
||||
<div class="col-md-12">
|
||||
<button class="btn btn-large btn-success" type="submit"
|
||||
ng-disabled="uploading || building || newRepoForm.$invalid || (repo.is_public == '0' && (planRequired || checkingPlan)) || ((repo.initialize == 'dockerfile' || repo.initialize == 'zipfile') && !hasDockerfile)">
|
||||
<i class="fa fa-large" ng-class="repo.is_public == '1' ? 'fa-unlock' : 'fa-lock'" style="margin-right: 4px"></i>
|
||||
|
|
|
@ -34,6 +34,13 @@
|
|||
</span>
|
||||
<i class="fa fa-upload visible-lg"></i>
|
||||
</div>
|
||||
<div class="feature">
|
||||
<span class="context-tooltip" bs-tooltip="tooltip.title" data-container="body" data-placement="right"
|
||||
data-title="Administrators can view and download the full invoice history for their organization">
|
||||
Invoice History
|
||||
</span>
|
||||
<i class="fa fa-calendar visible-lg"></i>
|
||||
</div>
|
||||
<div class="feature">
|
||||
<span class="context-tooltip" bs-tooltip="tooltip.title" data-container="body" data-placement="right"
|
||||
data-title="Grant subsets of users in an organization their own permissions, either on a global basis or a per-repository basis">
|
||||
|
@ -50,16 +57,9 @@
|
|||
</div>
|
||||
<div class="feature">
|
||||
<span class="context-tooltip" bs-tooltip="tooltip.title" data-container="body" data-placement="right"
|
||||
data-title="Administrators can view and download the full invoice history for their organization">
|
||||
Invoice History
|
||||
</span>
|
||||
<i class="fa fa-calendar visible-lg"></i>
|
||||
</div>
|
||||
<div class="feature">
|
||||
<span class="context-tooltip" bs-tooltip="tooltip.title" data-container="body" data-placement="right"
|
||||
data-title="All plans have a 14-day free trial">
|
||||
<span class="hidden-sm-inline">14-Day Free Trial</span>
|
||||
<span class="visible-sm-inline">14-Day Trial</span>
|
||||
data-title="All plans have a free trial">
|
||||
<span class="hidden-sm-inline">Free Trial</span>
|
||||
<span class="visible-sm-inline">Free Trial</span>
|
||||
</span>
|
||||
<i class="fa fa-clock-o visible-lg"></i>
|
||||
</div>
|
||||
|
@ -81,7 +81,7 @@
|
|||
<div class="feature present"></div>
|
||||
<div class="feature present"></div>
|
||||
<div class="feature present"></div>
|
||||
<div class="feature" ng-class="plan.bus_features ? 'present' : ''"></div>
|
||||
<div class="feature present"></div>
|
||||
<div class="feature" ng-class="plan.bus_features ? 'present' : ''"></div>
|
||||
<div class="feature" ng-class="plan.bus_features ? 'present' : ''"></div>
|
||||
<div class="feature present"></div>
|
||||
|
@ -93,10 +93,10 @@
|
|||
<div class="feature present">SSL Encryption</div>
|
||||
<div class="feature present">Robot accounts</div>
|
||||
<div class="feature present">Dockerfile Build</div>
|
||||
<div class="feature present">Invoice History</div>
|
||||
<div class="feature" ng-class="plan.bus_features ? 'present' : 'notpresent'">Teams</div>
|
||||
<div class="feature" ng-class="plan.bus_features ? 'present' : 'notpresent'">Logging</div>
|
||||
<div class="feature" ng-class="plan.bus_features ? 'present' : 'notpresent'">Invoice History</div>
|
||||
<div class="feature present">14-Day Free Trial</div>
|
||||
<div class="feature present">Free Trial</div>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-block" ng-class="plan.bus_features ? 'btn-success' : 'btn-primary'"
|
||||
|
@ -128,11 +128,19 @@
|
|||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>Enterprise</h3>
|
||||
<dt>I work in an enterprise and we need to run Quay.io on our servers. Can I do so?</dt>
|
||||
<dd>Please contact us at our <a href="mailto:support@quay.io">support email address</a> to discuss enterprise plans.</dd>
|
||||
|
||||
<div class="row enterprise-plan">
|
||||
<div class="col-md-6">
|
||||
<h2>Run Quay.io Behind Your Firewall</h2>
|
||||
<div class="plan-combine">
|
||||
<img src="/static/img/quay-logo.png">
|
||||
<span class="plus">+</span>
|
||||
<img src="/static/img/coreos.svg" style="height: 50px">
|
||||
</div>
|
||||
<div>Quay.io has partnered with CoreOS to offer Enterprise Registry, a version
|
||||
of Quay.io that can be hosted behind your firewall. More information
|
||||
can be found on the <a href="https://coreos.com/products/enterprise-registry">CoreOS website</a>.</div>
|
||||
<a href="https://coreos.com/products/enterprise-registry" class="btn btn-default">Learn more about Enterprise Registry</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
<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="#permissions">Permissions</a></li>
|
||||
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#trigger" ng-click="loadTriggers()">Build Triggers</a></li>
|
||||
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#trigger" ng-click="loadTriggers()"
|
||||
quay-require="['BUILD_SUPPORT']">Build Triggers</a></li>
|
||||
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#badge">Status Badge</a></li>
|
||||
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#notification" ng-click="loadNotifications()">Notifications</a></li>
|
||||
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#publicprivate">Public/Private</a></li>
|
||||
|
@ -225,7 +226,7 @@
|
|||
</div>
|
||||
|
||||
<!-- Triggers tab -->
|
||||
<div id="trigger" class="tab-pane">
|
||||
<div id="trigger" class="tab-pane" quay-require="['BUILD_SUPPORT']">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Build Triggers
|
||||
<i class="info-icon fa fa-info-circle" data-placement="left" data-content="Triggers from various services (such as GitHub) which tell the repository to be built and updated."></i>
|
||||
|
@ -377,24 +378,6 @@
|
|||
counter="showNewNotificationCounter"
|
||||
notification-created="handleNotificationCreated(notification)"></div>
|
||||
|
||||
<!-- Modal message dialog -->
|
||||
<div class="modal fade" id="cannotchangeModal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title">Cannot change</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
The selected action could not be performed because you do not have that authority.
|
||||
</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="makepublicModal">
|
||||
<div class="modal-dialog">
|
||||
|
@ -441,26 +424,6 @@
|
|||
</div><!-- /.modal -->
|
||||
|
||||
|
||||
<!-- Modal message dialog -->
|
||||
<div class="modal fade" id="channgechangepermModal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title">Cannot change permissions</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<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>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
|
||||
<!-- Modal message dialog -->
|
||||
<div class="modal fade" id="confirmdeleteModal">
|
||||
<div class="modal-dialog">
|
||||
|
|
|
@ -8,9 +8,6 @@
|
|||
<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="#license">License and Usage</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="javascript:void(0)" data-toggle="tab" data-target="#users" ng-click="loadUsers()">Users</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -19,19 +16,8 @@
|
|||
<!-- Content -->
|
||||
<div class="col-md-10">
|
||||
<div class="tab-content">
|
||||
<!-- License tab -->
|
||||
<div id="license" class="tab-pane active">
|
||||
<div class="quay-spinner 3x" ng-show="usageLoading"></div>
|
||||
<!-- Chart -->
|
||||
<div>
|
||||
<div id="seat-usage-chart" class="usage-chart limit-{{limit}}"></div>
|
||||
<span class="usage-caption" ng-show="chart">Seat Usage</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Users tab -->
|
||||
<div id="users" class="tab-pane">
|
||||
<div id="users" class="tab-pane active">
|
||||
<div class="quay-spinner" ng-show="!users"></div>
|
||||
<div class="alert alert-error" ng-show="usersError">
|
||||
{{ usersError }}
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<li ng-show="hasPaidPlan" quay-require="['BILLING']">
|
||||
<a href="javascript:void(0)" data-toggle="tab" data-target="#billingoptions">Billing Options</a>
|
||||
</li>
|
||||
<li ng-show="hasPaidBusinessPlan" quay-require="['BILLING']">
|
||||
<li ng-show="hasPaidPlan" quay-require="['BILLING']">
|
||||
<a href="javascript:void(0)" data-toggle="tab" data-target="#billing" ng-click="loadInvoices()">Billing History</a>
|
||||
</li>
|
||||
|
||||
|
@ -138,13 +138,14 @@
|
|||
|
||||
<!-- Change password tab -->
|
||||
<div id="password" class="tab-pane">
|
||||
<div class="loading" ng-show="updatingUser">
|
||||
<div class="quay-spinner 3x"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="panel">
|
||||
<div class="panel-title">Change Password</div>
|
||||
|
||||
<div class="loading" ng-show="updatingUser">
|
||||
<div class="quay-spinner 3x"></div>
|
||||
</div>
|
||||
|
||||
<span class="help-block" ng-show="changePasswordSuccess">Password changed successfully</span>
|
||||
|
||||
<div ng-show="!updatingUser" class="panel-body">
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<div class="dropdown" data-placement="top" style="display: inline-block"
|
||||
bs-tooltip=""
|
||||
data-title="{{ runningBuilds.length ? 'Dockerfile Builds Running: ' + (runningBuilds.length) : 'Dockerfile Build' }}"
|
||||
ng-show="repo.can_write || buildHistory.length">
|
||||
quay-show="Features.BUILD_SUPPORT && (repo.can_write || buildHistory.length)">
|
||||
<button class="btn btn-default dropdown-toggle" data-toggle="dropdown">
|
||||
<i class="fa fa-tasks fa-lg"></i>
|
||||
<span class="count" ng-class="runningBuilds.length ? 'visible' : ''"><span>{{ runningBuilds.length ? runningBuilds.length : '' }}</span></span>
|
||||
|
@ -58,16 +58,9 @@
|
|||
<span class="pull-command visible-md-inline">
|
||||
<div class="pull-container" data-title="Pull repository" bs-tooltip="tooltip.title">
|
||||
<div class="input-group">
|
||||
<input id="pull-text" type="text" class="form-control" value="{{ 'docker pull ' + Config.getDomain() + '/' + repo.namespace + '/' + repo.name }}" readonly>
|
||||
<span id="copyClipboard" class="input-group-addon" data-title="Copy to Clipboard" data-clipboard-target="pull-text">
|
||||
<i class="fa fa-copy"></i>
|
||||
</span>
|
||||
<div class="copy-box" hovering-message="true" value="'docker pull ' + Config.getDomain() + '/' + repo.namespace + '/' + repo.name"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="clipboardCopied" class="hovering" style="display: none">
|
||||
Copied to clipboard
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -76,33 +69,43 @@
|
|||
<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_id && !currentImage && !repo.is_building">
|
||||
<div class="empty-message">
|
||||
This repository is empty
|
||||
</div>
|
||||
<!-- Empty messages -->
|
||||
<div ng-if="!currentTag.image_id && !currentImage">
|
||||
<!-- !building && !pushing -->
|
||||
<div class="repo-content" ng-show="!repo.is_building && !isPushing(images)">
|
||||
<div class="empty-message">
|
||||
This repository is empty
|
||||
</div>
|
||||
|
||||
<div class="empty-description" ng-show="repo.can_write">
|
||||
<div class="panel-default">
|
||||
<div class="panel-heading">How to push a new image to this repository:</div>
|
||||
<div class="panel-body">
|
||||
First login to the registry (if you have not done so already):
|
||||
<pre class="command">sudo docker login {{ Config.getDomain() }}</pre>
|
||||
<div class="empty-description" ng-show="repo.can_write">
|
||||
<div class="panel-default">
|
||||
<div class="panel-heading">How to push a new image to this repository:</div>
|
||||
<div class="panel-body">
|
||||
First login to the registry (if you have not done so already):
|
||||
<pre class="command">sudo docker login {{ Config.getDomain() }}</pre>
|
||||
|
||||
Tag an image to this repository:
|
||||
<pre class="command">sudo docker tag <i>0u123imageidgoeshere</i> {{ Config.getDomain() }}/{{repo.namespace}}/{{repo.name}}</pre>
|
||||
Tag an image to this repository:
|
||||
<pre class="command">sudo docker tag <i>0u123imageidgoeshere</i> {{ Config.getDomain() }}/{{repo.namespace}}/{{repo.name}}</pre>
|
||||
|
||||
Push the image to this repository:
|
||||
<pre class="command">sudo docker push {{ Config.getDomain() }}/{{repo.namespace}}/{{repo.name}}</pre>
|
||||
Push the image to this repository:
|
||||
<pre class="command">sudo docker push {{ Config.getDomain() }}/{{repo.namespace}}/{{repo.name}}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- building -->
|
||||
<div class="repo-content" ng-show="repo.is_building">
|
||||
<div class="empty-message">
|
||||
A build is currently processing. If this takes longer than an hour, please <a href="/contact">contact us</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="repo-content" ng-show="!currentTag.image_id && repo.is_building">
|
||||
<div class="empty-message">
|
||||
A build is currently processing. If this takes longer than an hour, please <a href="/contact">contact us</a>
|
||||
<!-- pushing -->
|
||||
<div class="repo-content" ng-show="!repo.is_building && isPushing(images)">
|
||||
<div class="empty-message">
|
||||
A push to this repository is in progress.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -357,7 +360,7 @@
|
|||
<div style="margin: 10px; margin-top: 20px;" ng-show="isAnotherImageTag(toTagImage, tagToCreate)">
|
||||
Note: <span class="label tag label-default">{{ tagToCreate }}</span> is already applied to another image. This will <b>move</b> the tag.
|
||||
</div>
|
||||
<div class="tag-specific-images-view" tag="tagToCreate" repository="repo" images="images"
|
||||
<div class="tag-specific-images-view" tag="tagToCreate" repository="repo" images="images" image-cutoff="toTagImage"
|
||||
style="margin: 10px; margin-top: 20px; margin-bottom: -10px;" ng-show="isAnotherImageTag(toTagImage, tagToCreate)">
|
||||
This will also delete any unattach images and delete the following images:
|
||||
</div>
|
||||
|
@ -388,7 +391,10 @@
|
|||
</span>?
|
||||
</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="modal-body" ng-show="deletingTag">
|
||||
<div class="quay-spinner"></div>
|
||||
</div>
|
||||
<div class="modal-body" ng-show="!deletingTag">
|
||||
Are you sure you want to delete tag
|
||||
<span class="label tag" ng-class="tagToDelete == currentTag.name ? 'label-success' : 'label-default'">
|
||||
{{ tagToDelete }}
|
||||
|
@ -398,7 +404,7 @@
|
|||
The following images and any other images not referenced by a tag will be deleted:
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="modal-footer" ng-show="!deletingTag">
|
||||
<button type="button" class="btn btn-primary" ng-click="deleteTag(tagToDelete)">Delete Tag</button>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
||||
</div>
|
||||
|
|