Merge branch 'quark'
This commit is contained in:
commit
89eb5bdcc5
60 changed files with 637 additions and 133 deletions
|
@ -8,3 +8,6 @@ class BaseComponent(ApplicationSession):
|
|||
self.parent_manager = None
|
||||
self.build_logs = None
|
||||
self.user_files = None
|
||||
|
||||
def kind(self):
|
||||
raise NotImplementedError
|
|
@ -49,6 +49,9 @@ class BuildComponent(BaseComponent):
|
|||
|
||||
BaseComponent.__init__(self, config, **kwargs)
|
||||
|
||||
def kind(self):
|
||||
return 'builder'
|
||||
|
||||
def onConnect(self):
|
||||
self.join(self.builder_realm)
|
||||
|
||||
|
|
|
@ -25,6 +25,9 @@ class DynamicRegistrationComponent(BaseComponent):
|
|||
logger.debug('Registering new build component+worker with realm %s', realm)
|
||||
return realm
|
||||
|
||||
def kind(self):
|
||||
return 'registration'
|
||||
|
||||
|
||||
class EnterpriseManager(BaseManager):
|
||||
""" Build manager implementation for the Enterprise Registry. """
|
||||
|
@ -82,5 +85,7 @@ class EnterpriseManager(BaseManager):
|
|||
if build_component in self.ready_components:
|
||||
self.ready_components.remove(build_component)
|
||||
|
||||
self.unregister_component(build_component)
|
||||
|
||||
def num_workers(self):
|
||||
return len(self.all_components)
|
||||
|
|
|
@ -271,8 +271,6 @@ class EphemeralBuilderManager(BaseManager):
|
|||
|
||||
def build_component_disposed(self, build_component, timed_out):
|
||||
logger.debug('Calling build_component_disposed.')
|
||||
|
||||
# TODO make it so that I don't have to unregister the component if it timed out
|
||||
self.unregister_component(build_component)
|
||||
|
||||
@coroutine
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import logging
|
||||
import trollius
|
||||
import json
|
||||
|
||||
from autobahn.asyncio.wamp import RouterFactory, RouterSessionFactory
|
||||
from autobahn.asyncio.websocket import WampWebSocketServerFactory
|
||||
|
@ -69,7 +70,21 @@ class BuilderServer(object):
|
|||
|
||||
@controller_app.route('/status')
|
||||
def status():
|
||||
return server._current_status
|
||||
metrics = server._queue.get_metrics(require_transaction=False)
|
||||
(running_count, available_not_running_count, available_count) = metrics
|
||||
|
||||
workers = [component for component in server._current_components
|
||||
if component.kind() == 'builder']
|
||||
|
||||
data = {
|
||||
'status': server._current_status,
|
||||
'running_local': server._job_count,
|
||||
'running_total': running_count,
|
||||
'workers': len(workers),
|
||||
'job_total': available_count + running_count
|
||||
}
|
||||
|
||||
return json.dumps(data)
|
||||
|
||||
self._controller_app = controller_app
|
||||
|
||||
|
|
|
@ -170,8 +170,7 @@ def _create_user(username, email):
|
|||
pass
|
||||
|
||||
try:
|
||||
new_user = User.create(username=username, email=email)
|
||||
return new_user
|
||||
return User.create(username=username, email=email)
|
||||
except Exception as ex:
|
||||
raise DataModelException(ex.message)
|
||||
|
||||
|
|
|
@ -6,6 +6,12 @@ from util.morecollections import AttrDict
|
|||
|
||||
MINIMUM_EXTENSION = timedelta(seconds=20)
|
||||
|
||||
class NoopWith:
|
||||
def __enter__(self):
|
||||
pass
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
pass
|
||||
|
||||
class WorkQueue(object):
|
||||
def __init__(self, queue_name, transaction_factory,
|
||||
|
@ -49,21 +55,32 @@ class WorkQueue(object):
|
|||
def _item_by_id_for_update(self, queue_id):
|
||||
return db_for_update(QueueItem.select().where(QueueItem.id == queue_id)).get()
|
||||
|
||||
def update_metrics(self):
|
||||
if self._reporter is None:
|
||||
return
|
||||
|
||||
with self._transaction_factory(db):
|
||||
def get_metrics(self, require_transaction=True):
|
||||
guard = self._transaction_factory(db) if require_transaction else NoopWith()
|
||||
with guard:
|
||||
now = datetime.utcnow()
|
||||
name_match_query = self._name_match_query()
|
||||
|
||||
running_query = self._running_jobs(now, name_match_query)
|
||||
running_count = running_query.distinct().count()
|
||||
|
||||
available_query = self._available_jobs_not_running(now, name_match_query, running_query)
|
||||
available_query = self._available_jobs(now, name_match_query)
|
||||
available_count = available_query.select(QueueItem.queue_name).distinct().count()
|
||||
|
||||
self._reporter(self._currently_processing, running_count, running_count + available_count)
|
||||
available_not_running_query = self._available_jobs_not_running(now, name_match_query,
|
||||
running_query)
|
||||
available_not_running_count = (available_not_running_query.select(QueueItem.queue_name)
|
||||
.distinct().count())
|
||||
|
||||
return (running_count, available_not_running_count, available_count)
|
||||
|
||||
def update_metrics(self):
|
||||
if self._reporter is None:
|
||||
return
|
||||
|
||||
(running_count, available_not_running_count, available_count) = self.get_metrics()
|
||||
self._reporter(self._currently_processing, running_count,
|
||||
running_count + available_not_running_count)
|
||||
|
||||
def put(self, canonical_name_list, message, available_after=0, retries_remaining=5):
|
||||
"""
|
||||
|
|
|
@ -334,7 +334,11 @@ def validate_json_request(schema_name):
|
|||
def wrapped(self, *args, **kwargs):
|
||||
schema = self.schemas[schema_name]
|
||||
try:
|
||||
validate(request.get_json(), schema)
|
||||
json_data = request.get_json()
|
||||
if json_data is None:
|
||||
raise InvalidRequest('Missing JSON body')
|
||||
|
||||
validate(json_data, schema)
|
||||
return func(self, *args, **kwargs)
|
||||
except ValidationError as ex:
|
||||
raise InvalidRequest(ex.message)
|
||||
|
|
|
@ -50,6 +50,7 @@ class SuperUserRegistryStatus(ApiResource):
|
|||
@verify_not_prod
|
||||
def get(self):
|
||||
""" Returns the status of the registry. """
|
||||
|
||||
# If there is no conf/stack volume, then report that status.
|
||||
if not CONFIG_PROVIDER.volume_exists():
|
||||
return {
|
||||
|
|
|
@ -4,13 +4,62 @@ import json
|
|||
from flask import request, Blueprint, abort, Response
|
||||
from flask.ext.login import current_user
|
||||
from auth.auth import require_session_login
|
||||
from app import userevents
|
||||
from endpoints.common import route_show_if
|
||||
from app import app, userevents
|
||||
from auth.permissions import SuperUserPermission
|
||||
|
||||
import features
|
||||
import psutil
|
||||
import time
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
realtime = Blueprint('realtime', __name__)
|
||||
|
||||
|
||||
@realtime.route("/ps")
|
||||
@route_show_if(features.SUPER_USERS)
|
||||
@require_session_login
|
||||
def ps():
|
||||
if not SuperUserPermission().can():
|
||||
abort(403)
|
||||
|
||||
def generator():
|
||||
while True:
|
||||
build_status = {}
|
||||
try:
|
||||
builder_data = app.config['HTTPCLIENT'].get('http://localhost:8686/status', timeout=1)
|
||||
if builder_data.status_code == 200:
|
||||
build_status = json.loads(builder_data.text)
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
data = {
|
||||
'count': {
|
||||
'cpu': psutil.cpu_percent(interval=1, percpu=True),
|
||||
'virtual_mem': psutil.virtual_memory(),
|
||||
'swap_mem': psutil.swap_memory(),
|
||||
'connections': len(psutil.net_connections()),
|
||||
'processes': len(psutil.pids()),
|
||||
'network': psutil.net_io_counters()
|
||||
},
|
||||
'build': build_status
|
||||
}
|
||||
except psutil.AccessDenied:
|
||||
data = {}
|
||||
|
||||
json_string = json.dumps(data)
|
||||
yield 'data: %s\n\n' % json_string
|
||||
time.sleep(1)
|
||||
|
||||
try:
|
||||
return Response(generator(), mimetype="text/event-stream")
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@realtime.route("/user/")
|
||||
@require_session_login
|
||||
def index():
|
||||
|
|
|
@ -6,7 +6,7 @@ LOCAL_DIRECTORY = 'static/ldn/'
|
|||
|
||||
EXTERNAL_JS = [
|
||||
'code.jquery.com/jquery.js',
|
||||
'netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js',
|
||||
'netdna.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js',
|
||||
'ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js',
|
||||
'ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular-route.min.js',
|
||||
'ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular-sanitize.min.js',
|
||||
|
@ -19,7 +19,7 @@ EXTERNAL_JS = [
|
|||
|
||||
EXTERNAL_CSS = [
|
||||
'netdna.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.css',
|
||||
'netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.no-icons.min.css',
|
||||
'netdna.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css',
|
||||
'fonts.googleapis.com/css?family=Source+Sans+Pro:400,700',
|
||||
]
|
||||
|
||||
|
|
|
@ -47,3 +47,4 @@ pyOpenSSL
|
|||
pygpgme
|
||||
cachetools
|
||||
mock
|
||||
psutil
|
|
@ -39,6 +39,7 @@ mixpanel-py==3.2.1
|
|||
mock==1.0.1
|
||||
paramiko==1.15.2
|
||||
peewee==2.4.7
|
||||
psutil==2.2.1
|
||||
psycopg2==2.5.4
|
||||
py-bcrypt==0.4
|
||||
pycrypto==2.6.1
|
||||
|
|
|
@ -702,4 +702,19 @@
|
|||
.co-alert .co-step-bar {
|
||||
float: right;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.realtime-area-chart, .realtime-line-chart {
|
||||
margin: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.rickshaw_graph {
|
||||
overflow: hidden;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
.cor-container {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
|
@ -3,6 +3,10 @@
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
.btn {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
@media (max-width: 410px) {
|
||||
.olrk-normal {
|
||||
display: none;
|
||||
|
@ -159,7 +163,7 @@ nav.navbar-default .navbar-nav>li>a.active {
|
|||
|
||||
.notification-view-element .circle {
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
top: 15px;
|
||||
left: 0px;
|
||||
|
||||
width: 12px;
|
||||
|
@ -179,13 +183,13 @@ nav.navbar-default .navbar-nav>li>a.active {
|
|||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.notification-view-element .container {
|
||||
.notification-view-element .notification-content {
|
||||
padding: 10px;
|
||||
border-radius: 6px;
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.notification-view-element .container:hover {
|
||||
.notification-view-element .notification-content:hover {
|
||||
background: rgba(66, 139, 202, 0.1);
|
||||
}
|
||||
|
||||
|
@ -1140,59 +1144,59 @@ i.toggle-icon:hover {
|
|||
}
|
||||
|
||||
.visible-sm-inline {
|
||||
display: none;
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.visible-md-inline {
|
||||
display: none;
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.hidden-sm-inline {
|
||||
display: inline;
|
||||
display: inline !important;
|
||||
}
|
||||
|
||||
.hidden-xs-inline {
|
||||
display: inline;
|
||||
display: inline !important;
|
||||
}
|
||||
|
||||
@media (min-width: 991px) {
|
||||
.visible-md-inline {
|
||||
display: inline;
|
||||
display: inline !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 991px) and (min-width: 768px) {
|
||||
.visible-sm-inline {
|
||||
display: inline;
|
||||
display: inline !important;
|
||||
}
|
||||
|
||||
.hidden-sm-inline {
|
||||
display: none;
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
.hidden-xs-inline {
|
||||
display: none;
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.visible-xl {
|
||||
display: none;
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.visible-xl-inline {
|
||||
display: none;
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.visible-xl {
|
||||
display: block;
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.visible-xl-inline {
|
||||
display: inline-block;
|
||||
display: inline-block !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1413,6 +1417,10 @@ i.toggle-icon:hover {
|
|||
background: transparent;
|
||||
}
|
||||
|
||||
.jumbotron p {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.jumbotron .disclaimer-link {
|
||||
font-size: .3em;
|
||||
vertical-align: 23px;
|
||||
|
@ -1483,6 +1491,8 @@ i.toggle-icon:hover {
|
|||
|
||||
.landing-content {
|
||||
z-index: 2;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.landing .call-to-action i.fa {
|
||||
|
@ -3762,7 +3772,7 @@ p.editable:hover i {
|
|||
text-align: center;
|
||||
position: relative;
|
||||
color: white;
|
||||
left: -42px;
|
||||
left: -38px;
|
||||
top: -9px;
|
||||
font-weight: bold;
|
||||
font-size: .4em;
|
||||
|
@ -3772,23 +3782,6 @@ p.editable:hover i {
|
|||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.landing .social-alternate {
|
||||
color: #777;
|
||||
font-size: 2em;
|
||||
margin-left: 43px;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
.landing .social-alternate .inner-text {
|
||||
text-align: center;
|
||||
position: relative;
|
||||
color: white;
|
||||
left: -43px;
|
||||
top: -9px;
|
||||
font-weight: bold;
|
||||
font-size: .4em;
|
||||
}
|
||||
|
||||
.contact-options {
|
||||
margin-top: 60px;
|
||||
}
|
||||
|
@ -4972,3 +4965,9 @@ i.slack-icon {
|
|||
left: 16px;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.chart-col h4, .chart-col h5 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<div class="application-manager-element">
|
||||
<div class="quay-spinner" ng-show="loading"></div>
|
||||
|
||||
<div class="container" ng-show="!loading">
|
||||
<div class="cor-container" ng-show="!loading">
|
||||
<div class="side-controls">
|
||||
<span class="popup-input-button" placeholder="'Application Name'" submitted="createApplication(value)">
|
||||
<i class="fa fa-plus"></i> Create New Application
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="config-setup-tool-element">
|
||||
<div class="quay-spinner" ng-if="!config"></div>
|
||||
<div class="cor-loader" ng-if="!config"></div>
|
||||
<div ng-show="config && config['SUPER_USERS']">
|
||||
<form id="configform" name="configform">
|
||||
|
||||
|
@ -289,7 +289,7 @@
|
|||
<div class="description">
|
||||
<p>
|
||||
Authentication for the registry can be handled by either the registry itself or LDAP.
|
||||
External authentication providers (such as Github) can be used on top of this choice.
|
||||
External authentication providers (such as GitHub) can be used on top of this choice.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
@ -339,20 +339,20 @@
|
|||
</div>
|
||||
</div> <!-- /Authentication -->
|
||||
|
||||
<!-- Github Authentication -->
|
||||
<!-- GitHub Authentication -->
|
||||
<div class="co-panel">
|
||||
<div class="co-panel-heading">
|
||||
<i class="fa fa-github"></i> Github (Enterprise) Authentication
|
||||
<i class="fa fa-github"></i> GitHub (Enterprise) Authentication
|
||||
</div>
|
||||
<div class="co-panel-body">
|
||||
<div class="description">
|
||||
<p>
|
||||
If enabled, users can use Github or Github Enterprise to authenticate to the registry.
|
||||
If enabled, users can use GitHub or GitHub Enterprise to authenticate to the registry.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Note:</strong> A registered Github (Enterprise) OAuth application is required.
|
||||
<strong>Note:</strong> A registered GitHub (Enterprise) OAuth application is required.
|
||||
View instructions on how to
|
||||
<a href="https://coreos.com/docs/enterprise-registry/github-auth/" target="_blank">
|
||||
<a href="https://coreos.com/docs/enterprise-registry/github-app/" target="_blank">
|
||||
Create an OAuth Application in GitHub
|
||||
</a>
|
||||
</p>
|
||||
|
@ -360,21 +360,21 @@
|
|||
|
||||
<div class="co-checkbox">
|
||||
<input id="ftghl" type="checkbox" ng-model="config.FEATURE_GITHUB_LOGIN">
|
||||
<label for="ftghl">Enable Github Authentication</label>
|
||||
<label for="ftghl">Enable GitHub Authentication</label>
|
||||
</div>
|
||||
|
||||
<table class="config-table" ng-if="config.FEATURE_GITHUB_LOGIN">
|
||||
<tr>
|
||||
<td>Github:</td>
|
||||
<td>GitHub:</td>
|
||||
<td>
|
||||
<select ng-model="mapped.GITHUB_LOGIN_KIND">
|
||||
<option value="hosted">Github.com</option>
|
||||
<option value="enterprise">Github Enterprise</option>
|
||||
<option value="hosted">GitHub.com</option>
|
||||
<option value="enterprise">GitHub Enterprise</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="mapped.GITHUB_LOGIN_KIND == 'enterprise'">
|
||||
<td>Github Endpoint:</td>
|
||||
<td>GitHub Endpoint:</td>
|
||||
<td>
|
||||
<span class="config-string-field"
|
||||
binding="config.GITHUB_LOGIN_CONFIG.GITHUB_ENDPOINT"
|
||||
|
@ -382,7 +382,7 @@
|
|||
pattern="{{ GITHUB_REGEX }}">
|
||||
</span>
|
||||
<div class="help-text">
|
||||
The Github Enterprise endpoint. Must start with http:// or https://.
|
||||
The GitHub Enterprise endpoint. Must start with http:// or https://.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -402,7 +402,7 @@
|
|||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div> <!-- /Github Authentication -->
|
||||
</div> <!-- /GitHub Authentication -->
|
||||
|
||||
<!-- Google Authentication -->
|
||||
<div class="co-panel">
|
||||
|
@ -471,20 +471,20 @@
|
|||
</div> <!-- /Build Support -->
|
||||
|
||||
|
||||
<!-- Github Trigger -->
|
||||
<!-- GitHub Trigger -->
|
||||
<div class="co-panel" ng-if="config.FEATURE_BUILD_SUPPORT" style="margin-top: 20px;">
|
||||
<div class="co-panel-heading">
|
||||
<i class="fa fa-github"></i> Github (Enterprise) Build Triggers
|
||||
<i class="fa fa-github"></i> GitHub (Enterprise) Build Triggers
|
||||
</div>
|
||||
<div class="co-panel-body">
|
||||
<div class="description">
|
||||
<p>
|
||||
If enabled, users can setup Github or Github Enterprise triggers to invoke Registry builds.
|
||||
If enabled, users can setup GitHub or GitHub Enterprise triggers to invoke Registry builds.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Note:</strong> A registered Github (Enterprise) OAuth application (<strong>separate from Github Authentication</strong>) is required.
|
||||
<strong>Note:</strong> A registered GitHub (Enterprise) OAuth application (<strong>separate from GitHub Authentication</strong>) is required.
|
||||
View instructions on how to
|
||||
<a href="https://coreos.com/docs/enterprise-registry/github-auth/" target="_blank">
|
||||
<a href="https://coreos.com/docs/enterprise-registry/github-app/" target="_blank">
|
||||
Create an OAuth Application in GitHub
|
||||
</a>
|
||||
</p>
|
||||
|
@ -492,21 +492,21 @@
|
|||
|
||||
<div class="co-checkbox">
|
||||
<input id="ftgb" type="checkbox" ng-model="config.FEATURE_GITHUB_BUILD">
|
||||
<label for="ftgb">Enable Github Triggers</label>
|
||||
<label for="ftgb">Enable GitHub Triggers</label>
|
||||
</div>
|
||||
|
||||
<table class="config-table" ng-if="config.FEATURE_GITHUB_BUILD">
|
||||
<tr>
|
||||
<td>Github:</td>
|
||||
<td>GitHub:</td>
|
||||
<td>
|
||||
<select ng-model="mapped.GITHUB_TRIGGER_KIND">
|
||||
<option value="hosted">Github.com</option>
|
||||
<option value="enterprise">Github Enterprise</option>
|
||||
<option value="hosted">GitHub.com</option>
|
||||
<option value="enterprise">GitHub Enterprise</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="mapped.GITHUB_TRIGGER_KIND == 'enterprise'">
|
||||
<td>Github Endpoint:</td>
|
||||
<td>GitHub Endpoint:</td>
|
||||
<td>
|
||||
<span class="config-string-field"
|
||||
binding="config.GITHUB_TRIGGER_CONFIG.GITHUB_ENDPOINT"
|
||||
|
@ -514,7 +514,7 @@
|
|||
pattern="{{ GITHUB_REGEX }}">
|
||||
</span>
|
||||
<div class="help-text">
|
||||
The Github Enterprise endpoint. Must start with http:// or https://.
|
||||
The GitHub Enterprise endpoint. Must start with http:// or https://.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -534,7 +534,7 @@
|
|||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div> <!-- /Github Trigger -->
|
||||
</div> <!-- /GitHub Trigger -->
|
||||
</form>
|
||||
|
||||
<!-- Save Bar -->
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
<div class="co-main-content-panel co-tab-panel co-fx-box-shadow-heavy">
|
||||
<div class="container co-tab-container" ng-transclude></div>
|
||||
<div class="co-tab-container" ng-transclude></div>
|
||||
</div>
|
|
@ -1,8 +1,8 @@
|
|||
<div class="dockerfile-build-form-element">
|
||||
<div class="container" ng-show="building">
|
||||
<div ng-show="building">
|
||||
<div class="quay-spinner"></div>
|
||||
</div>
|
||||
<div class="container" ng-show="uploading">
|
||||
<div ng-show="uploading">
|
||||
<span class="message">Uploading file {{ upload_file }}</span>
|
||||
<div class="progress progress-striped active">
|
||||
<div class="progress-bar" role="progressbar" aria-valuenow="{{ upload_progress }}" aria-valuemin="0" aria-valuemax="100" style="{{ 'width: ' + upload_progress + '%' }}">
|
||||
|
@ -10,7 +10,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container" ng-show="!uploading && !building">
|
||||
<div ng-show="!uploading && !building">
|
||||
<table>
|
||||
<tr>
|
||||
<td style="vertical-align: middle;">Dockerfile or <code>.tar.gz</code> or <code>.zip</code>:</td>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="container loading-status-element">
|
||||
<div class="loading-status-element">
|
||||
<div ng-show="hasError && !loading">
|
||||
<span ng-transclude></span>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div class="logs-view-element">
|
||||
|
||||
<div class="container header">
|
||||
<div class="header">
|
||||
<span class="header-text">
|
||||
<span ng-show="!performer">Usage Logs</span>
|
||||
<span class="entity-reference" entity="performer" ng-show="performer"></span>
|
||||
|
@ -20,9 +20,7 @@
|
|||
</span>
|
||||
</div>
|
||||
|
||||
<div ng-show="loading">
|
||||
<div class="quay-spinner 3x"></div>
|
||||
</div>
|
||||
<div class="cor-loader-inline" ng-show="loading"></div>
|
||||
<div ng-show="!loading">
|
||||
<div id="bar-chart" style="width: 800px; height: 500px;" ng-show="chartVisible">
|
||||
<svg style="width: 800px; height: 500px;"></svg>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="notification-view-element">
|
||||
<div class="container" ng-click="showNotification();">
|
||||
<div class="notification-content" ng-click="showNotification();">
|
||||
<div class="circle" ng-class="getClass(notification)"></div>
|
||||
<div class="message" ng-bind-html="getMessage(notification)"></div>
|
||||
<div class="orginfo" ng-if="notification.organization">
|
||||
|
|
75
static/directives/ps-usage-graph.html
Normal file
75
static/directives/ps-usage-graph.html
Normal file
|
@ -0,0 +1,75 @@
|
|||
<div class="ps-usage-graph-element">
|
||||
<!-- Build Charts -->
|
||||
<div quay-show="Features.BUILD_SUPPORT">
|
||||
<div class="alert alert-warning" ng-if="data.build && data.build.job_total == null">
|
||||
Cannot load build system status. Please restart your container.
|
||||
</div>
|
||||
<div ng-if="data.build && data.build.job_total >= 0">
|
||||
<div class="col-md-6 chart-col">
|
||||
<h4>Build Queue</h4>
|
||||
<h5>
|
||||
Running Jobs: {{ data.build.running_total }} | Total Jobs: {{ data.build.job_total }}
|
||||
</h5>
|
||||
<div class="realtime-area-chart"
|
||||
data="[data.build.job_total, data.build.running_total]"
|
||||
labels="['Queued Build Jobs', 'Running Build Jobs']"
|
||||
colors="['rgb(157, 194, 211)', 'rgb(56, 122, 163)']"
|
||||
counter="counter"
|
||||
minimum="-10"
|
||||
maximum="auto"></div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 chart-col">
|
||||
<h4>Local Build Workers</h4>
|
||||
<h5>
|
||||
Local Workers: {{ data.build.workers }} | Working: {{ data.build.running_local }}
|
||||
</h5>
|
||||
<div class="realtime-area-chart"
|
||||
data="[data.build.job_total, data.build.workers, data.build.running_local]"
|
||||
labels="['Queued Build Jobs', 'Build Workers (local)', 'Running Build Jobs (local)']"
|
||||
colors="['rgb(157, 194, 211)', 'rgb(161, 208, 93)', 'rgb(210, 237, 130)']"
|
||||
counter="counter"
|
||||
minimum="-10"
|
||||
maximum="auto"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CPU, Memory and Network -->
|
||||
<div class="col-md-4 chart-col">
|
||||
<h4>CPU Usage %</h4>
|
||||
<div class="realtime-line-chart" data="data.count.cpu" counter="counter"
|
||||
label-template="CPU #{x} %"
|
||||
minimum="-10" maximum="110"></div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 chart-col">
|
||||
<h4>Process Count</h4>
|
||||
<div class="realtime-line-chart" data="data.count.processes" counter="counter"
|
||||
label-template="Process Count"></div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 chart-col">
|
||||
<h4>Virtual Memory %</h4>
|
||||
<div class="realtime-line-chart" data="data.count.virtual_mem[2]" counter="counter"
|
||||
label-template="Virtual Memory %"
|
||||
minimum="-10" maximum="110"></div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 chart-col">
|
||||
<h4>Swap Memory</h4>
|
||||
<div class="realtime-line-chart" data="data.count.swap_mem[3]" counter="counter"
|
||||
label-template="Swap Memory %"></div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 chart-col">
|
||||
<h4>Network Connections</h4>
|
||||
<div class="realtime-line-chart" data="data.count.connections" counter="counter"
|
||||
label-template="Network Connection Count"></div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 chart-col">
|
||||
<h4>Network Usage (Bytes)</h4>
|
||||
<div class="realtime-line-chart" data="data.count.network" labels="['Bytes In', 'Bytes Out']" counter="counter"></div>
|
||||
</div>
|
||||
</div>
|
6
static/directives/realtime-area-chart.html
Normal file
6
static/directives/realtime-area-chart.html
Normal file
|
@ -0,0 +1,6 @@
|
|||
<div class="realtime-area-chart-element">
|
||||
<div ng-show="counter >= 1">
|
||||
<div class="chart"></div>
|
||||
</div>
|
||||
<div class="cor-loader-inline" ng-if="counter < 1"></div>
|
||||
</div>
|
6
static/directives/realtime-line-chart.html
Normal file
6
static/directives/realtime-line-chart.html
Normal file
|
@ -0,0 +1,6 @@
|
|||
<div class="realtime-line-chart-element">
|
||||
<div ng-show="counter >= 1">
|
||||
<div class="chart"></div>
|
||||
</div>
|
||||
<div class="cor-loader-inline" ng-if="counter < 1"></div>
|
||||
</div>
|
|
@ -2,7 +2,7 @@
|
|||
<div class="quay-spinner" ng-show="loading"></div>
|
||||
<div class="alert alert-info">Robot accounts allow for delegating access in multiple repositories to role-based accounts that you manage</div>
|
||||
|
||||
<div class="container" ng-show="!loading">
|
||||
<div ng-show="!loading">
|
||||
<div class="side-controls">
|
||||
<span class="popup-input-button" pattern="ROBOT_PATTERN" placeholder="'Robot Account Name'"
|
||||
submitted="createRobot(value)">
|
||||
|
|
|
@ -6612,6 +6612,54 @@ quayApp.directive('locationView', function () {
|
|||
});
|
||||
|
||||
|
||||
quayApp.directive('psUsageGraph', function () {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
templateUrl: '/static/directives/ps-usage-graph.html',
|
||||
replace: false,
|
||||
transclude: false,
|
||||
restrict: 'C',
|
||||
scope: {
|
||||
'isEnabled': '=isEnabled'
|
||||
},
|
||||
controller: function($scope, $element) {
|
||||
$scope.counter = -1;
|
||||
$scope.data = null;
|
||||
|
||||
var source = null;
|
||||
|
||||
var connect = function() {
|
||||
if (source) { return; }
|
||||
source = new EventSource('/realtime/ps');
|
||||
source.onmessage = function(e) {
|
||||
$scope.$apply(function() {
|
||||
$scope.counter++;
|
||||
$scope.data = JSON.parse(e.data);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
var disconnect = function() {
|
||||
if (!source) { return; }
|
||||
source.close();
|
||||
source = null;
|
||||
};
|
||||
|
||||
$scope.$watch('isEnabled', function(value) {
|
||||
if (value) {
|
||||
connect();
|
||||
} else {
|
||||
disconnect();
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$on("$destroy", disconnect);
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
});
|
||||
|
||||
|
||||
quayApp.directive('avatar', function () {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
|
|
|
@ -17,6 +17,11 @@ function SuperUserAdminCtrl($scope, $timeout, ApiService, Features, UserService,
|
|||
$scope.pollChannel = null;
|
||||
$scope.logsScrolled = false;
|
||||
$scope.csrf_token = encodeURIComponent(window.__token);
|
||||
$scope.dashboardActive = false;
|
||||
|
||||
$scope.setDashboardActive = function(active) {
|
||||
$scope.dashboardActive = active;
|
||||
};
|
||||
|
||||
$scope.configurationSaved = function() {
|
||||
$scope.requiresRestart = true;
|
||||
|
|
|
@ -205,6 +205,10 @@ angular.module("core-config-setup", ['angularFileUpload'])
|
|||
};
|
||||
|
||||
var getKey = function(config, path) {
|
||||
if (!config) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var parts = path.split('.');
|
||||
var current = config;
|
||||
for (var i = 0; i < parts.length; ++i) {
|
||||
|
@ -303,10 +307,10 @@ angular.module("core-config-setup", ['angularFileUpload'])
|
|||
if (!value) { return; }
|
||||
|
||||
ApiService.scGetConfig().then(function(resp) {
|
||||
$scope.config = resp['config'];
|
||||
$scope.config = resp['config'] || {};
|
||||
initializeMappedLogic($scope.config);
|
||||
$scope.mapped['$hasChanges'] = false;
|
||||
});
|
||||
}, ApiService.errorDisplay('Could not load config'));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -270,9 +270,18 @@ angular.module("core-ui", [])
|
|||
'tabActive': '@tabActive',
|
||||
'tabTitle': '@tabTitle',
|
||||
'tabTarget': '@tabTarget',
|
||||
'tabInit': '&tabInit'
|
||||
'tabInit': '&tabInit',
|
||||
'tabShown': '&tabShown',
|
||||
'tabHidden': '&tabHidden'
|
||||
},
|
||||
controller: function($rootScope, $scope, $element) {
|
||||
$element.find('a[data-toggle="tab"]').on('hidden.bs.tab', function (e) {
|
||||
$scope.tabHidden({});
|
||||
});
|
||||
|
||||
$element.find('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
||||
$scope.tabShown({});
|
||||
});
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
|
@ -297,6 +306,236 @@ angular.module("core-ui", [])
|
|||
return directiveDefinitionObject;
|
||||
})
|
||||
|
||||
.directive('realtimeAreaChart', function () {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
templateUrl: '/static/directives/realtime-area-chart.html',
|
||||
replace: false,
|
||||
transclude: false,
|
||||
restrict: 'C',
|
||||
scope: {
|
||||
'data': '=data',
|
||||
'labels': '=labels',
|
||||
'colors': '=colors',
|
||||
'counter': '=counter'
|
||||
},
|
||||
controller: function($scope, $element) {
|
||||
var graph = null;
|
||||
var series = [];
|
||||
var palette = new Rickshaw.Color.Palette( { scheme: 'spectrum14' } );
|
||||
var colors = $scope.colors || [];
|
||||
|
||||
var setupGraph = function() {
|
||||
for (var i = 0; i < $scope.labels.length; ++i) {
|
||||
series.push({
|
||||
name: $scope.labels[i],
|
||||
color: i >= colors.length ? palette.color(): $scope.colors[i],
|
||||
stroke: 'rgba(0,0,0,0.15)',
|
||||
data: []
|
||||
});
|
||||
}
|
||||
|
||||
var options = {
|
||||
element: $element.find('.chart')[0],
|
||||
renderer: 'area',
|
||||
stroke: true,
|
||||
series: series,
|
||||
min: 0,
|
||||
padding: {
|
||||
'top': 0.3,
|
||||
'left': 0,
|
||||
'right': 0,
|
||||
'bottom': 0.3
|
||||
}
|
||||
};
|
||||
|
||||
if ($scope.minimum != null) {
|
||||
options['min'] = $scope.minimum == 'auto' ? 'auto' : $scope.minimum * 1;
|
||||
} else {
|
||||
options['min'] = 0;
|
||||
}
|
||||
|
||||
if ($scope.maximum != null) {
|
||||
options['max'] = $scope.maximum == 'auto' ? 'auto' : $scope.maximum * 1;
|
||||
}
|
||||
|
||||
graph = new Rickshaw.Graph(options);
|
||||
|
||||
xaxes = new Rickshaw.Graph.Axis.Time({
|
||||
graph: graph,
|
||||
timeFixture: new Rickshaw.Fixtures.Time.Local()
|
||||
});
|
||||
|
||||
yaxes = new Rickshaw.Graph.Axis.Y({
|
||||
graph: graph,
|
||||
tickFormat: Rickshaw.Fixtures.Number.formatKMBT
|
||||
});
|
||||
|
||||
hoverDetail = new Rickshaw.Graph.HoverDetail({
|
||||
graph: graph,
|
||||
xFormatter: function(x) {
|
||||
return new Date(x * 1000).toString();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var refresh = function(data) {
|
||||
if (!data || $scope.counter < 0) { return; }
|
||||
if (!graph) {
|
||||
setupGraph();
|
||||
}
|
||||
|
||||
var timecode = new Date().getTime() / 1000;
|
||||
for (var i = 0; i < $scope.data.length; ++i) {
|
||||
var arr = series[i].data;
|
||||
arr.push(
|
||||
{'x': timecode, 'y': $scope.data[i] }
|
||||
);
|
||||
|
||||
if (arr.length > 10) {
|
||||
series[i].data = arr.slice(arr.length - 10, arr.length);
|
||||
}
|
||||
}
|
||||
|
||||
graph.renderer.unstack = true;
|
||||
graph.update();
|
||||
};
|
||||
|
||||
$scope.$watch('counter', function() {
|
||||
refresh($scope.data_raw);
|
||||
});
|
||||
|
||||
$scope.$watch('data', function(data) {
|
||||
$scope.data_raw = data;
|
||||
refresh($scope.data_raw);
|
||||
});
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
})
|
||||
|
||||
|
||||
.directive('realtimeLineChart', function () {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
templateUrl: '/static/directives/realtime-line-chart.html',
|
||||
replace: false,
|
||||
transclude: false,
|
||||
restrict: 'C',
|
||||
scope: {
|
||||
'data': '=data',
|
||||
'labels': '=labels',
|
||||
'counter': '=counter',
|
||||
'labelTemplate': '@labelTemplate',
|
||||
'minimum': '@minimum',
|
||||
'maximum': '@maximum'
|
||||
},
|
||||
controller: function($scope, $element) {
|
||||
var graph = null;
|
||||
var xaxes = null;
|
||||
var yaxes = null;
|
||||
var hoverDetail = null;
|
||||
var series = [];
|
||||
var counter = 0;
|
||||
var palette = new Rickshaw.Color.Palette( { scheme: 'spectrum14' } );
|
||||
|
||||
var setupGraph = function() {
|
||||
var options = {
|
||||
element: $element.find('.chart')[0],
|
||||
renderer: 'line',
|
||||
series: series,
|
||||
padding: {
|
||||
'top': 0.3,
|
||||
'left': 0,
|
||||
'right': 0,
|
||||
'bottom': 0.3
|
||||
}
|
||||
};
|
||||
|
||||
if ($scope.minimum != null) {
|
||||
options['min'] = $scope.minimum == 'auto' ? 'auto' : $scope.minimum * 1;
|
||||
} else {
|
||||
options['min'] = 0;
|
||||
}
|
||||
|
||||
if ($scope.maximum != null) {
|
||||
options['max'] = $scope.maximum == 'auto' ? 'auto' : $scope.maximum * 1;
|
||||
}
|
||||
|
||||
graph = new Rickshaw.Graph(options);
|
||||
xaxes = new Rickshaw.Graph.Axis.Time({
|
||||
graph: graph,
|
||||
timeFixture: new Rickshaw.Fixtures.Time.Local()
|
||||
});
|
||||
|
||||
yaxes = new Rickshaw.Graph.Axis.Y({
|
||||
graph: graph,
|
||||
tickFormat: Rickshaw.Fixtures.Number.formatKMBT
|
||||
});
|
||||
|
||||
hoverDetail = new Rickshaw.Graph.HoverDetail({
|
||||
graph: graph,
|
||||
xFormatter: function(x) {
|
||||
return new Date(x * 1000).toString();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var refresh = function(data) {
|
||||
if (data == null) { return; }
|
||||
if (!graph) {
|
||||
setupGraph();
|
||||
}
|
||||
|
||||
if (typeof data == 'number') {
|
||||
data = [data];
|
||||
}
|
||||
|
||||
if ($scope.labels) {
|
||||
data = data.slice(0, $scope.labels.length);
|
||||
}
|
||||
|
||||
if (series.length == 0){
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
var title = $scope.labels ? $scope.labels[i] : $scope.labelTemplate.replace('{x}', i + 1);
|
||||
series.push({
|
||||
'color': palette.color(),
|
||||
'data': [],
|
||||
'name': title
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
counter++;
|
||||
var timecode = new Date().getTime() / 1000;
|
||||
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
var arr = series[i].data;
|
||||
arr.push({
|
||||
'x': timecode,
|
||||
'y': data[i]
|
||||
})
|
||||
|
||||
if (arr.length > 10) {
|
||||
series[i].data = arr.slice(arr.length - 10, arr.length);
|
||||
}
|
||||
}
|
||||
|
||||
graph.update();
|
||||
};
|
||||
|
||||
$scope.$watch('counter', function(counter) {
|
||||
refresh($scope.data_raw);
|
||||
});
|
||||
|
||||
$scope.$watch('data', function(data) {
|
||||
$scope.data_raw = data;
|
||||
});
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
})
|
||||
|
||||
.directive('corStepBar', function() {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 4,
|
||||
|
|
1
static/lib/rickshaw.min.css
vendored
Normal file
1
static/lib/rickshaw.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
3
static/lib/rickshaw.min.js
vendored
Normal file
3
static/lib/rickshaw.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -1,4 +1,4 @@
|
|||
<div class="container about-us">
|
||||
<div class="cor-container about-us">
|
||||
<h2>
|
||||
About Us
|
||||
</h2>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<div class="resource-view" resource="repository_build" error-message="'No matching repository build found'"></div>
|
||||
<div class="container repo repo-build" ng-show="accessDenied">
|
||||
<div class="cor-container repo repo-build" ng-show="accessDenied">
|
||||
You do not have permission to view this page
|
||||
</div>
|
||||
<div class="container repo repo-build repo-build-pack" ng-show="repobuild">
|
||||
<div class="cor-container repo repo-build repo-build-pack" ng-show="repobuild">
|
||||
<div class="header row">
|
||||
<a href="{{ '/repository/' + repo.namespace + '/' + repo.name + '/build' }}" class="back"><i class="fa fa-chevron-left"></i></a>
|
||||
<h3>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="confirm-invite">
|
||||
<div class="container signin-container">
|
||||
<div class="cor-container signin-container">
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-sm-offset-3">
|
||||
<div class="user-setup" ng-show="user.anonymous" redirect-url="redirectUrl"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="container">
|
||||
<div class="cor-container">
|
||||
<h2>
|
||||
Contact Us<br>
|
||||
<small>We are here to help!</small>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="container">
|
||||
<div class="cor-container">
|
||||
<h3>Redirecting...</h3>
|
||||
<META http-equiv="refresh" content="0;URL=http://docs.quay.io/solution/getting-started.html">
|
||||
If this page does not redirect, please <a href="http://docs.quay.io/solution/getting-started.html"> click here</a>.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="resource-view" resource="image" error-message="'No image found'">
|
||||
<div class="container repo repo-image-view">
|
||||
<div class="cor-container repo repo-image-view">
|
||||
<div class="header">
|
||||
<a href="{{ '/repository/' + repo.namespace + '/' + repo.name }}" class="back"><i class="fa fa-chevron-left"></i></a>
|
||||
<h3>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<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">
|
||||
<div class="container">
|
||||
<div class="cor-container">
|
||||
<div class="row messages">
|
||||
<div class="col-md-7">
|
||||
<div ng-show="user.anonymous" style="text-align: center">
|
||||
|
@ -54,6 +54,6 @@
|
|||
</div>
|
||||
</div> <!-- col -->
|
||||
</div> <!-- row -->
|
||||
</div> <!-- container -->
|
||||
</div> <!-- cor-container -->
|
||||
</div>
|
||||
</div> <!-- jumbotron -->
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<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">
|
||||
<div class="container">
|
||||
<div class="cor-container">
|
||||
<div class="row messages">
|
||||
<div class="col-md-7">
|
||||
<div ng-show="user.anonymous">
|
||||
|
@ -70,7 +70,7 @@
|
|||
|
||||
<div class="rows" ng-show="user.anonymous">
|
||||
<div class=" shoutout-row landing-section">
|
||||
<div class="container">
|
||||
<div class="cor-container">
|
||||
<div class="row">
|
||||
<div class="col-md-4 shoutout">
|
||||
<i class="fa fa-lock"></i>
|
||||
|
@ -105,7 +105,7 @@
|
|||
|
||||
<div class=" landing-section">
|
||||
<h2>Trusted by companies who use Docker</h2>
|
||||
<div class="container">
|
||||
<div class="cor-container">
|
||||
<div class="row">
|
||||
<div class="trusted-logos">
|
||||
<div class="col-md-3 trusted-logo">
|
||||
|
@ -127,7 +127,7 @@
|
|||
|
||||
<div class="landing-section">
|
||||
<h2>Built with our users in mind</h2>
|
||||
<div class="container">
|
||||
<div class="cor-container">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 feature-shoutout">
|
||||
<img id="screenshot" ng-src="{{ '/static/img/' + currentScreenshot + '.png' }}" class="img-responsive">
|
||||
|
@ -171,7 +171,7 @@
|
|||
|
||||
<div class="landing-section">
|
||||
<h2>Seamlessly integrate into your Docker-based infrastructure</h2>
|
||||
<div class="container">
|
||||
<div class="cor-container">
|
||||
<div class="row testimonial">
|
||||
<div class="message">
|
||||
Quay.io has become an essential part of our infrastructure as we move to Docker-based deploys.
|
||||
|
@ -192,7 +192,7 @@
|
|||
|
||||
<div class="landing-section">
|
||||
<h2>See what other people are saying about Quay.io</h2>
|
||||
<div class="container">
|
||||
<div class="cor-container">
|
||||
<div class="row">
|
||||
<div class="jcarousel-wrapper">
|
||||
<div class="jcarousel">
|
||||
|
@ -263,7 +263,7 @@
|
|||
|
||||
<div class="landing-section">
|
||||
<h2>Start pushing to Quay.io in under a minute</h2>
|
||||
<div class="container">
|
||||
<div class="cor-container">
|
||||
<div class="row landing-action">
|
||||
<a href="/plans" class="btn btn-primary">Start Free Trial</a>
|
||||
</div>
|
||||
|
@ -272,7 +272,7 @@
|
|||
|
||||
</div>
|
||||
|
||||
<div class="container" ng-if="user.anonymous">
|
||||
<div class="cor-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>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
</div>
|
||||
|
||||
<div ng-show="application">
|
||||
<div class="container manage-application">
|
||||
<div class="cor-container manage-application">
|
||||
<!-- Header -->
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div class="quay-spinner"></div>
|
||||
</div>
|
||||
|
||||
<div class="container create-org" ng-show="!creating">
|
||||
<div class="cor-container create-org" ng-show="!creating">
|
||||
|
||||
<div class="row header-row">
|
||||
<div class="col-md-12">
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
<div class="container" ng-show="user.anonymous">
|
||||
<div class="cor-container" ng-show="user.anonymous">
|
||||
<div class="col-sm-6 col-sm-offset-3">
|
||||
<div class="user-setup" redirect-url="'/new/'"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container" ng-show="!user.anonymous && building">
|
||||
<div class="cor-container" ng-show="!user.anonymous && building">
|
||||
<div class="quay-spinner"></div>
|
||||
</div>
|
||||
|
||||
<div class="container" ng-show="!user.anonymous && creating">
|
||||
<div class="cor-container" ng-show="!user.anonymous && creating">
|
||||
<div class="quay-spinner"></div>
|
||||
</div>
|
||||
|
||||
<div class="container new-repo" ng-show="!user.anonymous && !creating && !building">
|
||||
<div class="cor-container new-repo" ng-show="!user.anonymous && !creating && !building">
|
||||
<form method="post" name="newRepoForm" id="newRepoForm" ng-submit="createNewRepo()">
|
||||
|
||||
<!-- Header -->
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="resource-view" resource="orgResource" error-message="'No organization found'"></div>
|
||||
<div class="org-admin container" ng-show="organization">
|
||||
<div class="org-admin cor-container" ng-show="organization">
|
||||
<div class="organization-header" organization="organization" clickable="true"></div>
|
||||
|
||||
<div class="row">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="resource-view" resource="memberResource" error-message="'Member not found'">
|
||||
<div class="org-member-logs container">
|
||||
<div class="org-member-logs cor-container">
|
||||
<div class="organization-header" organization="organization" clickable="true"></div>
|
||||
<div class="logs-view" organization="organization" performer="memberInfo"
|
||||
makevisible="organization && memberInfo && ready"></div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="resource-view" resource="orgResource" error-message="'No matching organization found'">
|
||||
<div class="org-view container">
|
||||
<div class="org-view cor-container">
|
||||
<div class="organization-header" organization="organization">
|
||||
<div class="header-buttons" ng-show="organization.is_admin">
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="container org-list conntent-container">
|
||||
<div class="cor-container org-list conntent-container">
|
||||
<div class="loading" ng-show="!user">
|
||||
<div class="quay-spinner"></div>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="container plans content-container">
|
||||
<div class="cor-container plans content-container">
|
||||
<div class="row plans-list">
|
||||
<div class="col-sm-2">
|
||||
<div class="features-bar hidden-xs">
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<div class="container" ng-show="deleting"><div class="quay-spinner"></div></div>
|
||||
<div class="cor-container" ng-show="deleting"><div class="quay-spinner"></div></div>
|
||||
<div class="resource-view" resource="repository" error-message="'No repository found'"></div>
|
||||
<div class="container repo repo-admin" ng-show="accessDenied">
|
||||
<div class="cor-container repo repo-admin" ng-show="accessDenied">
|
||||
You do not have permission to view this page
|
||||
</div>
|
||||
<div class="container repo repo-admin" ng-show="repo && !deleting">
|
||||
<div class="cor-container repo repo-admin" ng-show="repo && !deleting">
|
||||
<div class="header row">
|
||||
<a href="{{ '/repository/' + repo.namespace + '/' + repo.name }}" class="back"><i class="fa fa-chevron-left"></i></a>
|
||||
<h3>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<div class="resource-view" resource="repository" error-message="'No repository found'"></div>
|
||||
<div class="container repo repo-build" ng-show="accessDenied">
|
||||
<div class="cor-container repo repo-build" ng-show="accessDenied">
|
||||
You do not have permission to view this page
|
||||
</div>
|
||||
<div class="container repo repo-build" ng-show="repo">
|
||||
<div class="cor-container repo repo-build" ng-show="repo">
|
||||
<div class="header row">
|
||||
<a href="{{ '/repository/' + repo.namespace + '/' + repo.name }}" class="back"><i class="fa fa-chevron-left"></i></a>
|
||||
<h3>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="container">
|
||||
<div class="cor-container">
|
||||
<div class="repo-list" ng-show="!user.anonymous">
|
||||
<div ng-class="user.organizations.length ? 'section-header' : ''">
|
||||
<div class="button-bar-right">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="container">
|
||||
<div class="cor-container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h1>Quay.io Security</h1>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="container signin-container">
|
||||
<div class="cor-container signin-container">
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-sm-offset-3">
|
||||
<div class="user-setup" redirect-url="redirectUrl"></div>
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
tab-target="#users" tab-init="loadUsers()">
|
||||
<i class="fa fa-group"></i>
|
||||
</span>
|
||||
<span class="cor-tab" tab-title="Dashboard" tab-target="#dashboard"
|
||||
tab-shown="setDashboardActive(true)" tab-hidden="setDashboardActive(false)">
|
||||
<i class="fa fa-tachometer"></i>
|
||||
</span>
|
||||
<span class="cor-tab" tab-title="Container Usage" tab-target="#usage-counter" tab-init="getUsage()">
|
||||
<i class="fa fa-pie-chart"></i>
|
||||
</span>
|
||||
|
@ -42,6 +46,11 @@
|
|||
configuration-saved="configurationSaved()"></div>
|
||||
</div>
|
||||
|
||||
<!-- Dashboard tab -->
|
||||
<div id="dashboard" class="tab-pane">
|
||||
<div class="ps-usage-graph" is-enabled="dashboardActive"></div>
|
||||
</div>
|
||||
|
||||
<!-- Debugging tab -->
|
||||
<div id="debug" class="tab-pane">
|
||||
<div class="cor-loader" ng-show="!debugServices"></div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="resource-view" resource="orgResource" error-message="'No matching organization'">
|
||||
<div class="team-view container">
|
||||
<div class="team-view cor-container">
|
||||
<div class="organization-header" organization="organization" team-name="teamname">
|
||||
<div ng-show="canEditMembers" class="side-controls">
|
||||
<div class="hidden-xs">
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="cor-container">
|
||||
<div class="tour-content" kind="kind"></div>
|
||||
</div>
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
<div class="container">
|
||||
<div class="cor-container">
|
||||
<div class="angular-tour-ui" tour="tour" inline="true"></div>
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
No matching user found
|
||||
</div>
|
||||
|
||||
<div class="user-admin container" ng-show="!user.anonymous">
|
||||
<div class="user-admin cor-container" ng-show="!user.anonymous">
|
||||
<div class="row">
|
||||
<div class="organization-header-element">
|
||||
<span class="avatar" size="24" hash="user.avatar"></span>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="container">
|
||||
<div class="cor-container">
|
||||
<div ng-show="!user.anonymous && user.verified">
|
||||
<h3>Welcome <b>{{ user.username }}</b>. Your account is fully activated!</h3>
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<div class="container">
|
||||
<div class="alert alert-info" style="padding: 4px;">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input name="showSudo" type="checkbox" ng-model="tour.tourScope.showSudo" style="display: inline-block; margin-left: 0px; margin-right: 10px;">
|
||||
<input name="showSudo" type="checkbox" ng-model="tour.tourScope.showSudo" style="display: inline-block; margin-left: 10px; margin-right: 10px;">
|
||||
<label for="showSudo" style="padding-left: 30px;">
|
||||
My OS requires me to run all <code>docker</code> commands with <code>sudo</code>
|
||||
</label>
|
||||
</div>
|
||||
|
|
Reference in a new issue