Get dashboard working and upgrade bootstrap. Note: the bootstrap fixes will be coming in the followup CL

This commit is contained in:
Joseph Schorr 2015-02-17 19:15:54 -05:00
parent 79f39697fe
commit 524705b88c
18 changed files with 429 additions and 260 deletions

View file

@ -705,5 +705,11 @@
}
.realtime-area-chart, .realtime-line-chart {
display: inline-block;
margin: 10px;
text-align: center;
}
.rickshaw_graph {
overflow: hidden;
padding-bottom: 40px;
}

View file

@ -4972,3 +4972,9 @@ i.slack-icon {
left: 16px;
font-size: 28px;
}
.chart-col h4, .chart-col h5 {
display: block;
text-align: center;
}

View file

@ -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 -->

View file

@ -1,39 +1,75 @@
<div class="ps-usage-graph-element">
<div quay-show="Features.BUILD_SUPPORT" ng-if="data.build && data.build.job_total">
Build Workers:
<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"></div>
<!-- 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="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"></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:
<div class="realtime-line-chart" data="data.count.cpu" counter="counter"
label-template="CPU #{x} %"></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>
Process Count:
<div class="realtime-line-chart" data="data.count.processes" counter="counter"
label-template="Process Count"></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>
Virtual Memory:
<div class="realtime-line-chart" data="data.count.virtual_mem[2]" counter="counter"
label-template="Virtual Memory %"></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>
Swap Memory:
<div class="realtime-line-chart" data="data.count.swap_mem[3]" counter="counter"
label-template="Swap Memory %"></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>
Network Connections:
<div class="realtime-line-chart" data="data.count.connections" counter="counter"
label-template="Network Connection Count"></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>
Network Usage:
<div class="realtime-line-chart" data="data.count.network" labels="['Bytes In', 'Bytes Out']" counter="counter"></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>

View file

@ -1,3 +1,6 @@
<div class="realtime-area-chart-element">
<div class="chart" style="width: 450px; height: 250px;"></div>
<div ng-show="counter >= 1">
<div class="chart"></div>
</div>
<div class="cor-loader-inline" ng-if="counter < 1"></div>
</div>

View file

@ -1,3 +1,6 @@
<div class="realtime-line-chart-element">
<div class="chart" style="width: 450px; height: 250px;"></div>
<div ng-show="counter >= 1">
<div class="chart"></div>
</div>
<div class="cor-loader-inline" ng-if="counter < 1"></div>
</div>

View file

@ -6602,178 +6602,6 @@ quayApp.directive('locationView', function () {
});
quayApp.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: []
});
}
graph = new Rickshaw.Graph( {
element: $element.find('.chart')[0],
renderer: 'area',
stroke: true,
series: series,
min: 0
});
};
var refresh = function(data) {
if (!data || $scope.counter < 0) { return; }
if (!graph) {
setupGraph();
}
for (var i = 0; i < $scope.data.length; ++i) {
series[i].data.push(
{'x': $scope.counter, 'y': $scope.data[i] }
);
}
hoverDetail = new Rickshaw.Graph.HoverDetail({
graph: graph,
xFormatter: function(x) {
return x.toString();
}
});
graph.renderer.unstack = true;
graph.render();
};
$scope.$watch('counter', function() {
refresh($scope.data_raw);
});
$scope.$watch('data', function(data) {
$scope.data_raw = data;
refresh($scope.data_raw);
});
}
};
return directiveDefinitionObject;
});
quayApp.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'
},
controller: function($scope, $element) {
var graph = null;
var hoverDetail = null;
var series = [];
var counter = 0;
var palette = new Rickshaw.Color.Palette( { scheme: 'spectrum14' } );
var setupGraph = function() {
graph = new Rickshaw.Graph({
element: $element.find('.chart')[0],
renderer: 'line',
series: series,
min: 'auto',
padding: {
'top': 0.1,
'left': 0.01,
'right': 0.01,
'bottom': 0.1
}
});
hoverDetail = new Rickshaw.Graph.HoverDetail({
graph: graph,
xFormatter: function(x) {
return x.toString();
}
});
};
var refresh = function(data) {
if (!data) { 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++;
for (var i = 0; i < data.length; ++i) {
var arr = series[i].data;
arr.push({
'x': counter,
'y': data[i]
})
if (arr.length > 10) {
series[i].data = arr.slice(arr.length - 10, arr.length);
}
}
graph.render();
};
$scope.$watch('counter', function(counter) {
refresh($scope.data_raw);
});
$scope.$watch('data', function(data) {
$scope.data_raw = data;
});
}
};
return directiveDefinitionObject;
});
quayApp.directive('psUsageGraph', function () {
var directiveDefinitionObject = {
priority: 0,
@ -6782,18 +6610,40 @@ quayApp.directive('psUsageGraph', function () {
transclude: false,
restrict: 'C',
scope: {
'isEnabled': '=isEnabled'
},
controller: function($scope, $element) {
$scope.counter = -1;
$scope.data = null;
var source = new EventSource('/realtime/ps');
source.onmessage = function(e) {
$scope.$apply(function() {
$scope.counter++;
$scope.data = JSON.parse(e.data);
});
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;

View file

@ -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;

View file

@ -307,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'));
});
}
};

View file

@ -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,

View file

@ -20,7 +20,8 @@
tab-target="#users" tab-init="loadUsers()">
<i class="fa fa-group"></i>
</span>
<span class="cor-tab" tab-title="Dashboard" tab-target="#dashboard">
<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()">
@ -47,7 +48,7 @@
<!-- Dashboard tab -->
<div id="dashboard" class="tab-pane">
<div class="ps-usage-graph" is-enabled="true"></div>
<div class="ps-usage-graph" is-enabled="dashboardActive"></div>
</div>
<!-- Debugging tab -->