Added groundwork for the refstack user-interface.
Used a combination of AngularJS and Bootstrap to form a preliminary front-end website for Refstack. Most of the content text can be considered placeholders and is subject to change. Change-Id: Ide82783478d1863052fe54d02ca6ee88113c46b2
This commit is contained in:
parent
649137a0b0
commit
cfe34d9371
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"directory": "app/assets/lib"
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
.tmp
|
||||||
|
AUTHORS
|
||||||
|
ChangeLog
|
||||||
|
build/
|
||||||
|
cover/
|
||||||
|
dist
|
||||||
|
node_modules
|
||||||
|
npm-debug.log
|
||||||
|
app/assets/lib
|
|
@ -0,0 +1,36 @@
|
||||||
|
=======================
|
||||||
|
Refstack User Interface
|
||||||
|
=======================
|
||||||
|
|
||||||
|
User interface for interacting with the Refstack API.
|
||||||
|
|
||||||
|
Setup
|
||||||
|
=====
|
||||||
|
|
||||||
|
You can start a development server by doing the following:
|
||||||
|
|
||||||
|
Install NodeJS and NPM:
|
||||||
|
|
||||||
|
:code:`curl -sL https://deb.nodesource.com/setup | sudo bash -`
|
||||||
|
|
||||||
|
:code:`sudo apt-get install nodejs`
|
||||||
|
|
||||||
|
From the Refstack project root directory, move into the UI folder:
|
||||||
|
|
||||||
|
:code:`cd refstack-ui`
|
||||||
|
|
||||||
|
Install dependencies and start the server:
|
||||||
|
|
||||||
|
:code:`npm start`
|
||||||
|
|
||||||
|
Doing this will automatically perform :code:`npm start` and :code:`bower install`
|
||||||
|
to get all dependencies.
|
||||||
|
|
||||||
|
By default, as noted in package.json, the server will use 0.0.0.0:8080.
|
||||||
|
|
||||||
|
Test
|
||||||
|
====
|
||||||
|
|
||||||
|
To run unit tests, simply perform the following:
|
||||||
|
|
||||||
|
:code:`npm test`
|
|
@ -0,0 +1,30 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/* App Module */
|
||||||
|
|
||||||
|
var refstackApp = angular.module('refstackApp', [
|
||||||
|
'ui.router', 'ui.bootstrap']);
|
||||||
|
|
||||||
|
refstackApp.config(['$stateProvider', '$urlRouterProvider',
|
||||||
|
function($stateProvider, $urlRouterProvider) {
|
||||||
|
$urlRouterProvider.otherwise('/');
|
||||||
|
$stateProvider.
|
||||||
|
state('home', {
|
||||||
|
url: '/',
|
||||||
|
templateUrl: '/components/home/home.html'
|
||||||
|
}).
|
||||||
|
state('about', {
|
||||||
|
url: '/about',
|
||||||
|
templateUrl: '/components/about/about.html'
|
||||||
|
}).
|
||||||
|
state('capabilities', {
|
||||||
|
url: '/capabilities',
|
||||||
|
templateUrl: '/components/capabilities/capabilities.html',
|
||||||
|
controller: 'capabilitiesController'
|
||||||
|
}).
|
||||||
|
state('results', {
|
||||||
|
url: '/results',
|
||||||
|
templateUrl: '/components/results/results.html'
|
||||||
|
})
|
||||||
|
}]);
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
../../../../defcore/2015.03.json
|
|
@ -0,0 +1,130 @@
|
||||||
|
body {
|
||||||
|
background: white;
|
||||||
|
color: black;
|
||||||
|
font-family: 'Helvetica Neue', 'Helvetica', 'Verdana', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
font-size: 3em;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading img {
|
||||||
|
height: 50px;
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.error {
|
||||||
|
background: #FAFF78;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
font-family: 'Futura-CondensedExtraBold', 'Futura', 'Helvetica', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
background: none repeat scroll 0% 0% #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.required {
|
||||||
|
color: #1D6503;
|
||||||
|
}
|
||||||
|
|
||||||
|
.advisory {
|
||||||
|
color: #9F8501;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deprecated {
|
||||||
|
color: #B03838;
|
||||||
|
}
|
||||||
|
|
||||||
|
.removed {
|
||||||
|
color: #801601;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox {
|
||||||
|
word-spacing: 20px;
|
||||||
|
background: #F8F8F8;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.capabilities {
|
||||||
|
color: #4B4B4B;
|
||||||
|
}
|
||||||
|
|
||||||
|
.capabilities a, .criteria a {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.capabilities .capability-list-item {
|
||||||
|
border-bottom: 2px solid #AFAFAF;
|
||||||
|
padding-bottom: .6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.capabilities .capability-name {
|
||||||
|
font-size: 1.3em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
#criteria {
|
||||||
|
color: #4B4B4B;
|
||||||
|
}
|
||||||
|
|
||||||
|
.criterion-name {
|
||||||
|
font-size: 1.1em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-inline li:before {
|
||||||
|
content: '\00BB';
|
||||||
|
}
|
||||||
|
|
||||||
|
.flagged:before {
|
||||||
|
color: #E6A100;
|
||||||
|
content: '\2691';
|
||||||
|
}
|
||||||
|
|
||||||
|
.program-about {
|
||||||
|
font-size: .8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jumbotron .left {
|
||||||
|
width: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container .jumbotron {
|
||||||
|
background: #F6F6F6;
|
||||||
|
border-top: 2px solid #C9C9C9;
|
||||||
|
border-bottom: 2px solid #C9C9C9;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jumbotron .right {
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jumbotron img {
|
||||||
|
width: 70%;
|
||||||
|
height: 70%;
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.4 KiB |
|
@ -0,0 +1,3 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/* Miscellaneous Refstack JavaScript */
|
|
@ -0,0 +1,93 @@
|
||||||
|
<p>
|
||||||
|
<strong>Overview</strong>
|
||||||
|
</p>
|
||||||
|
<p>Refstack intends on being THE source of tools for interoperability testing
|
||||||
|
of OpenStack clouds.</p>
|
||||||
|
<p>Refstack provides users in the OpenStack community with a Tempest wrapper,
|
||||||
|
refstack-client, that helps to verify interoperability of their cloud
|
||||||
|
with other OpenStack clouds. It does so by validating any cloud
|
||||||
|
implementation against the OpenStack Tempest API tests.</p>
|
||||||
|
<p>
|
||||||
|
<strong>Refstack and DefCore</strong> - The prototypical use case for Refstack provides
|
||||||
|
the DefCore Committee the tools for vendors and other users to run API
|
||||||
|
tests against their clouds to provide the DefCore committee with a reliable
|
||||||
|
overview of what APIs and capabilities are being used in the marketplace.
|
||||||
|
This will help to guide the DefCore-defined capabilities and help ensure
|
||||||
|
interoperability across the entire OpenStack ecosystem. It can also
|
||||||
|
be used to validate clouds against existing DefCore capability lists,
|
||||||
|
giving you assurance that your cloud faithfully implements OpenStack
|
||||||
|
standards.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Value Add for Vendors</strong> - Vendors can use Refstack to demonstrate that
|
||||||
|
their distros, and/or their customers' installed clouds remain with OpenStack
|
||||||
|
after their software has been incorporated into the distro or cloud.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Refstack consists of two parts:</strong>
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<dl>
|
||||||
|
<dt>
|
||||||
|
<strong>refstack-api</strong>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
<p>Our API isn't just for us to collect data from private and public cloud
|
||||||
|
vendors. It can be used by vendors in house to compare interoperability
|
||||||
|
data over time.</p>
|
||||||
|
<ul>
|
||||||
|
<li>install docs:
|
||||||
|
<a href="https://github.com/stackforge/refstack/blob/master/doc/refstack.md">doc/refstack.md</a>
|
||||||
|
</li>
|
||||||
|
<li>repository:
|
||||||
|
<a href="http://git.openstack.org/cgit/stackforge/refstack">http://git.openstack.org/cgit/stackforge/refstack</a>
|
||||||
|
</li>
|
||||||
|
<li>storyboard:
|
||||||
|
<a href="https://storyboard.openstack.org/#!/project/700">https://storyboard.openstack.org/#!/project/700</a>
|
||||||
|
</li>
|
||||||
|
<li>reviews:
|
||||||
|
<a href="https://review.openStack.org/#q,status:open+refstack,n,z">https://review.OpenStack.org/#q,status:open+refstack,n,z</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<dl>
|
||||||
|
<dt>
|
||||||
|
<strong>refstack-client</strong>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
<p>refstack-client contains the tools you will need to run the DefCore tests.</p>
|
||||||
|
<ul>
|
||||||
|
<li>repository:
|
||||||
|
<a href="http://git.openstack.org/cgit/stackforge/refstack-client">http://git.openstack.org/cgit/stackforge/refstack-client</a>
|
||||||
|
</li>
|
||||||
|
<li>storyboard:
|
||||||
|
<a href="https://storyboard.openstack.org/#!/project/703">https://storyboard.openstack.org/#!/project/703</a>
|
||||||
|
</li>
|
||||||
|
<li>reviews:
|
||||||
|
<a href="https://review.openstack.org/#q,status:open+refstack-client,n,z">https://review.openstack.org/#q,status:open+refstack-client,n,z</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
<strong>Get involved!</strong>
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>Mailing List:
|
||||||
|
<a href="mailto:fits%40OpenStack.org">fits@OpenStack.org</a>
|
||||||
|
</li>
|
||||||
|
<li>IRC: #refstack on Freenode</li>
|
||||||
|
<li>Dev Meetings: Mondays @ 19:00 UTC in #openstack-meeting-alt on Freenode</li>
|
||||||
|
<li>Web-site:
|
||||||
|
<a href="http://refstack.net">http://refstack.net</a>
|
||||||
|
</li>
|
||||||
|
<li>Wiki:
|
||||||
|
<a href="https://wiki.OpenStack.org/wiki/refstack">https://wiki.OpenStack.org/wiki/refstack</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
|
@ -0,0 +1,71 @@
|
||||||
|
<h3>DefCore Capabilities</h3>
|
||||||
|
<strong>Version:</strong>
|
||||||
|
<select ng-model="version" ng-change="update()">
|
||||||
|
<option value="2015.03">2015.03</option>
|
||||||
|
</select>
|
||||||
|
<br /><br />
|
||||||
|
<strong>Target Program:</strong>
|
||||||
|
<select ng-model="target" >
|
||||||
|
<option value="platform">OpenStack Powered Platform</option>
|
||||||
|
<option value="compute">OpenStack Powered Compute</option>
|
||||||
|
<option value="object">OpenStack Powered Object Storage</option>
|
||||||
|
</select>
|
||||||
|
<span class="program-about"><a target="_blank" href="http://www.openstack.org/brand/interop/">About</a></span>
|
||||||
|
<br /><br />
|
||||||
|
|
||||||
|
<strong>Capability Status:</strong>
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" ng-model="status.required" ng-true-value="'required'" ng-false-value="''">
|
||||||
|
<span class="required">Required</span>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" ng-model="status.advisory" ng-true-value="'advisory'" ng-false-value="''">
|
||||||
|
<span class="advisory">Advisory</span>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" ng-model="status.deprecated" ng-true-value="'deprecated'" ng-false-value="''">
|
||||||
|
<span class="deprecated">Deprecated</span>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" ng-model="status.removed" ng-true-value="'removed'" ng-false-value="''">
|
||||||
|
<span class="removed">Removed</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<p><small>Tests marked with <span class="flagged"></span> are tests flagged by DefCore.</small></p>
|
||||||
|
|
||||||
|
<ol class="capabilities">
|
||||||
|
<li class="capability-list-item" ng-repeat="capability in capabilities.capabilities | arrayConverter | filter:filterProgram | filter:filterStatus">
|
||||||
|
<span class="capability-name">{{capability.name}}</span><br />
|
||||||
|
<em>{{capability.description}}</em><br />
|
||||||
|
Status: <span class="{{capability.status}}">{{capability.status}}</span><br />
|
||||||
|
<a ng-click="hideAchievements = !hideAchievements">Achievements ({{capability.achievements.length}})</a><br />
|
||||||
|
<ol collapse="hideAchievements" class="list-inline">
|
||||||
|
<li ng-repeat="achievement in capability.achievements">
|
||||||
|
{{achievement}}
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<a ng-click="hideTests = !hideTests">Tests ({{capability.tests.length}})</a>
|
||||||
|
<ul collapse="hideTests">
|
||||||
|
<li ng-repeat="test in capability.tests">
|
||||||
|
<span ng-class="{'flagged': capability.flagged.indexOf(test) > -1}"> {{test}}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div class="criteria">
|
||||||
|
<h4><a ng-click="hideCriteria = !hideCriteria">Criteria</a></h4>
|
||||||
|
<div collapse="hideCriteria">
|
||||||
|
<ul>
|
||||||
|
<li ng-repeat="(key, criterion) in capabilities.criteria">
|
||||||
|
<span class="criterion-name">{{criterion.name}}</span><br />
|
||||||
|
<em>{{criterion.Description}}</em><br />
|
||||||
|
Weight: {{criterion.weight}}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br /><br />
|
|
@ -0,0 +1,63 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/* Refstack Capabilities Controller */
|
||||||
|
|
||||||
|
var refstackApp = angular.module('refstackApp');
|
||||||
|
|
||||||
|
refstackApp.controller('capabilitiesController', ['$scope', '$http', function($scope, $http) {
|
||||||
|
$scope.version = '2015.03';
|
||||||
|
$scope.hideAchievements = true;
|
||||||
|
$scope.hideTests = true;
|
||||||
|
$scope.target = 'platform';
|
||||||
|
$scope.status = {
|
||||||
|
required: 'required',
|
||||||
|
advisory: '',
|
||||||
|
deprecated: '',
|
||||||
|
removed: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.update = function() {
|
||||||
|
// Rate-limiting is an issue with this URL. Using a local copy for now.
|
||||||
|
// var content_url = 'https://api.github.com/repos/openstack/defcore/contents/'.concat($scope.version, '.json');
|
||||||
|
var content_url = 'assets/capabilities/'.concat($scope.version, '.json');
|
||||||
|
$http.get(content_url).success(function(data) {
|
||||||
|
//$scope.data = data;
|
||||||
|
//$scope.capabilities = JSON.parse(atob($scope.data.content.replace(/\s/g, '')));
|
||||||
|
$scope.capabilities = data;
|
||||||
|
}).error(function(error) {
|
||||||
|
console.log(error);
|
||||||
|
$scope.capabilities = 'Error retrieving capabilities.';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$scope.update()
|
||||||
|
|
||||||
|
$scope.filterProgram = function(capability){
|
||||||
|
var components = $scope.capabilities.components;
|
||||||
|
if ($scope.target === 'platform') {
|
||||||
|
var platform_components = $scope.capabilities.platform.required;
|
||||||
|
var cap_array = [];
|
||||||
|
// For each component required for the platform program.
|
||||||
|
angular.forEach(platform_components, function(component) {
|
||||||
|
// Get each capability belonging to each status.
|
||||||
|
angular.forEach(components[component], function(capabilities) {
|
||||||
|
cap_array = cap_array.concat(capabilities);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return (cap_array.indexOf(capability.id) > -1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var cap_array = [];
|
||||||
|
angular.forEach(components[$scope.target], function(capabilities) {
|
||||||
|
cap_array = cap_array.concat(capabilities);
|
||||||
|
});
|
||||||
|
return (cap_array.indexOf(capability.id) > -1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.filterStatus = function(capability){
|
||||||
|
return capability.status === $scope.status.required ||
|
||||||
|
capability.status === $scope.status.advisory ||
|
||||||
|
capability.status === $scope.status.deprecated ||
|
||||||
|
capability.status === $scope.status.removed;
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,31 @@
|
||||||
|
<div class="jumbotron">
|
||||||
|
<div class="pull-left left">
|
||||||
|
<h1>OpenStack Interoperability</h1>
|
||||||
|
<p>Refstack is a source of tools for OpenStack interoperability testing.</p>
|
||||||
|
</div>
|
||||||
|
<div class="pull-right right">
|
||||||
|
<img src="assets/img/openstack-logo.png" alt="OpenStack">
|
||||||
|
</div>
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<h4>What is Refstack?</h4>
|
||||||
|
<ul>
|
||||||
|
<li>Toolset for testing interoperability between OpenStack clouds.</li>
|
||||||
|
<li>Database backed website supporting collection and publication of
|
||||||
|
community test results for OpenStack.</li>
|
||||||
|
<li>User interface to display individual test run results.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<h4>OpenStack Marketing Programs</h4>
|
||||||
|
<ul>
|
||||||
|
<li>OpenStack Powered Platform</li>
|
||||||
|
<li>OpenStack Powered Compute</li>
|
||||||
|
<li>OpenStack Powered Object Storage</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1 @@
|
||||||
|
<p>Community results list here.</p>
|
Binary file not shown.
After Width: | Height: | Size: 318 B |
|
@ -0,0 +1,49 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<!--
|
||||||
|
Copyright (c) 2015 IBM Corp.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
not use this file except in compliance with the License. You may obtain
|
||||||
|
a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
License for the specific language governing permissions and limitations
|
||||||
|
under the License.
|
||||||
|
-->
|
||||||
|
<html ng-app="refstackApp">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="description" content="Refstack">
|
||||||
|
<meta name="viewport" content="width=device-width">
|
||||||
|
<title>Refstack</title>
|
||||||
|
|
||||||
|
<link rel="shorcut icon" href="favicon.ico">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="assets/lib/bootstrap/dist/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="assets/css/style.css">
|
||||||
|
|
||||||
|
<script src="assets/lib/angular/angular.js"></script>
|
||||||
|
<script src="assets/lib/angular-ui-router/release/angular-ui-router.js"></script>
|
||||||
|
<script src="assets/lib/angular-bootstrap/ui-bootstrap.min.js"></script>
|
||||||
|
<script src="app.js"></script>
|
||||||
|
<script src="assets/js/refstack.js"></script>
|
||||||
|
|
||||||
|
<!-- Controllers -->
|
||||||
|
<script src="shared/header/headerController.js"></script>
|
||||||
|
<script src="components/capabilities/capabilitiesController.js"></script>
|
||||||
|
|
||||||
|
<!-- Filters -->
|
||||||
|
<script src="shared/filters.js"></script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="container">
|
||||||
|
<header ng-include src="'shared/header/header.html'"></header>
|
||||||
|
|
||||||
|
<div ui-view></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,4 @@
|
||||||
|
# robotstxt.org
|
||||||
|
|
||||||
|
User-agent: *
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/* Refstack Filters */
|
||||||
|
|
||||||
|
var refstackApp = angular.module('refstackApp');
|
||||||
|
|
||||||
|
// Convert an object of objects to an array of objects to use with ng-repeat
|
||||||
|
// filters.
|
||||||
|
refstackApp.filter('arrayConverter', function() {
|
||||||
|
return function(objects) {
|
||||||
|
var array = [];
|
||||||
|
angular.forEach(objects, function(object, key) {
|
||||||
|
object['id'] = key;
|
||||||
|
array.push(object);
|
||||||
|
});
|
||||||
|
return array;
|
||||||
|
};
|
||||||
|
});
|
|
@ -0,0 +1,26 @@
|
||||||
|
<div class="heading"><a ui-sref="home"><img src="assets/img/refstack-logo.png" alt="Refstack"></a>
|
||||||
|
Refstack
|
||||||
|
</div>
|
||||||
|
<nav class="navbar navbar-default" role="navigation" ng-controller="headerController">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<!-- Brand and toggle get grouped for better mobile display -->
|
||||||
|
<div class="navbar-header">
|
||||||
|
<button type="button" class="navbar-toggle collapsed" ng-click="navbarCollapsed = !navbarCollapsed">
|
||||||
|
<span class="sr-only">Toggle navigation</span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="collapse navbar-collapse" id="navbar" collapse="navbarCollapsed">
|
||||||
|
<ul class="nav navbar-nav">
|
||||||
|
<li ng-class="{ active: isActive('/')}"><a ui-sref="home">Home</a></li>
|
||||||
|
<li ng-class="{ active: isActive('/about')}"><a ui-sref="about">About</a></li>
|
||||||
|
<li ng-class="{ active: isActive('/capabilities')}"><a ui-sref="capabilities">DefCore Capabilities</a></li>
|
||||||
|
<li ng-class="{ active: isActive('/results')}"><a ui-sref="results">Community Results</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/* Refstack Header Controller */
|
||||||
|
|
||||||
|
var refstackApp = angular.module('refstackApp')
|
||||||
|
refstackApp.controller('headerController', ['$scope', '$location', function($scope, $location) {
|
||||||
|
$scope.navbarCollapsed = true;
|
||||||
|
$scope.isActive = function(viewLocation) {
|
||||||
|
var path = $location.path().substr(0, viewLocation.length);
|
||||||
|
if (path === viewLocation) {
|
||||||
|
// Make sure "/" only matches when viewLocation is "/".
|
||||||
|
if (!($location.path().substr(0).length > 1 && viewLocation.length === 1 )) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"name": "refstack-ui",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "Refstack user interface",
|
||||||
|
"dependencies": {
|
||||||
|
"angular": "1.3.15",
|
||||||
|
"angular-ui-router": "0.2.13",
|
||||||
|
"angular-resource": "1.3.15",
|
||||||
|
"angular-bootstrap": "0.12.1",
|
||||||
|
"bootstrap": "3.3.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"angular-mocks": "1.3.15"
|
||||||
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"angular": "1.3.15"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"version": "0.0.1",
|
||||||
|
"private": true,
|
||||||
|
"name": "refstack-ui",
|
||||||
|
"description": "A user interface for Refstack",
|
||||||
|
"license": "Apache2",
|
||||||
|
"devDependencies": {
|
||||||
|
"karma": "^0.12.23",
|
||||||
|
"karma-chrome-launcher": "^0.1.5",
|
||||||
|
"karma-jasmine": "^0.2.2",
|
||||||
|
"karma-firefox-launcher": "^0.1.3",
|
||||||
|
"protractor": "~1.0.0",
|
||||||
|
"http-server": "^0.6.1",
|
||||||
|
"tmp": "0.0.23",
|
||||||
|
"bower": "1.3.12",
|
||||||
|
"shelljs": "^0.2.6"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"postinstall": "bower install",
|
||||||
|
|
||||||
|
"prestart": "npm install",
|
||||||
|
"start": "http-server ./app -a 0.0.0.0 -p 8080",
|
||||||
|
|
||||||
|
"pretest": "npm install",
|
||||||
|
"test": "node node_modules/karma/bin/karma start tests/karma.conf.js",
|
||||||
|
"test-single-run": "node node_modules/karma/bin/karma start tests/karma.conf.js --single-run"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
module.exports = function(config){
|
||||||
|
config.set({
|
||||||
|
|
||||||
|
basePath : '../',
|
||||||
|
|
||||||
|
files : [
|
||||||
|
// Angular libraries.
|
||||||
|
'app/assets/lib/angular/angular.js',
|
||||||
|
'app/assets/lib/angular-ui-router/release/angular-ui-router.js',
|
||||||
|
'app/assets/lib/angular-bootstrap/ui-bootstrap.min.js',
|
||||||
|
'app/assets/lib/angular-mocks/angular-mocks.js',
|
||||||
|
|
||||||
|
// JS files.
|
||||||
|
'app/app.js',
|
||||||
|
'app/components/**/*.js',
|
||||||
|
'app/shared/*.js',
|
||||||
|
'app/shared/**/*.js',
|
||||||
|
'app/assets/js/*.js',
|
||||||
|
|
||||||
|
// Test Specs.
|
||||||
|
'tests/unit/*.js'
|
||||||
|
],
|
||||||
|
|
||||||
|
autoWatch : true,
|
||||||
|
|
||||||
|
frameworks: ['jasmine'],
|
||||||
|
|
||||||
|
browsers : ['Firefox'],
|
||||||
|
|
||||||
|
plugins : [
|
||||||
|
'karma-chrome-launcher',
|
||||||
|
'karma-firefox-launcher',
|
||||||
|
'karma-jasmine',
|
||||||
|
],
|
||||||
|
|
||||||
|
junitReporter : {
|
||||||
|
outputFile: 'test_out/unit.xml',
|
||||||
|
suite: 'unit'
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,94 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/* Jasmine specs for Refstack controllers */
|
||||||
|
describe('Refstack controllers', function() {
|
||||||
|
|
||||||
|
describe('headerController', function() {
|
||||||
|
var scope, ctrl, $location;
|
||||||
|
beforeEach(module('refstackApp'));
|
||||||
|
|
||||||
|
beforeEach(inject(function($rootScope, $controller, _$location_) {
|
||||||
|
scope = $rootScope.$new();
|
||||||
|
$location = _$location_;
|
||||||
|
ctrl = $controller('headerController', {$scope: scope});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should set "navbarCollapsed" to true', function() {
|
||||||
|
expect(scope.navbarCollapsed).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have a function to check if the URL path is active', function() {
|
||||||
|
$location.path('/');
|
||||||
|
expect($location.path()).toBe('/');
|
||||||
|
expect(scope.isActive('/')).toBe(true);
|
||||||
|
expect(scope.isActive('/about')).toBe(false);
|
||||||
|
|
||||||
|
$location.path('/results?cpid=123&foo=bar');
|
||||||
|
expect($location.path()).toBe('/results?cpid=123&foo=bar');
|
||||||
|
expect(scope.isActive('/results')).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('capabilitiesController', function() {
|
||||||
|
var scope, ctrl, $httpBackend;
|
||||||
|
beforeEach(module('refstackApp'));
|
||||||
|
|
||||||
|
beforeEach(inject(function(_$httpBackend_, $rootScope, $controller) {
|
||||||
|
$httpBackend = _$httpBackend_;
|
||||||
|
scope = $rootScope.$new();
|
||||||
|
ctrl = $controller('capabilitiesController', {$scope: scope});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should set default states', function() {
|
||||||
|
expect(scope.hideAchievements).toBe(true);
|
||||||
|
expect(scope.hideTests).toBe(true);
|
||||||
|
expect(scope.version).toBe('2015.03');
|
||||||
|
expect(scope.target).toBe('platform');
|
||||||
|
expect(scope.status).toEqual({required: 'required', advisory: '',
|
||||||
|
deprecated: '', removed: ''});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fetch the selected capabilities version', function() {
|
||||||
|
$httpBackend.expectGET('assets/capabilities/2015.03.json').respond({'foo': 'bar'});
|
||||||
|
$httpBackend.flush();
|
||||||
|
expect(scope.capabilities).toEqual({'foo': 'bar'});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have a function to check if a status filter is selected', function() {
|
||||||
|
expect(scope.filterStatus({'status': 'required'})).toBe(true);
|
||||||
|
expect(scope.filterStatus({'status': 'advisory'})).toBe(false);
|
||||||
|
expect(scope.filterStatus({'status': 'deprecated'})).toBe(false);
|
||||||
|
expect(scope.filterStatus({'status': 'removed'})).toBe(false);
|
||||||
|
|
||||||
|
scope.status = {
|
||||||
|
required: 'required',
|
||||||
|
advisory: 'advisory',
|
||||||
|
deprecated: 'deprecated',
|
||||||
|
removed: 'removed'
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(scope.filterStatus({'status': 'required'})).toBe(true);
|
||||||
|
expect(scope.filterStatus({'status': 'advisory'})).toBe(true);
|
||||||
|
expect(scope.filterStatus({'status': 'deprecated'})).toBe(true);
|
||||||
|
expect(scope.filterStatus({'status': 'removed'})).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have a function to check if a capability belongs to a program', function() {
|
||||||
|
scope.capabilities = {'platform': {'required': ['compute']},
|
||||||
|
'components': {
|
||||||
|
'compute': {
|
||||||
|
'required': ['cap_id_1'],
|
||||||
|
'advisory': ['cap_id_2'],
|
||||||
|
'deprecated': ['cap_id_3'],
|
||||||
|
'removed': ['cap_id_4']
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
expect(scope.filterProgram({'id': 'cap_id_1'})).toBe(true);
|
||||||
|
expect(scope.filterProgram({'id': 'cap_id_2'})).toBe(true);
|
||||||
|
expect(scope.filterProgram({'id': 'cap_id_3'})).toBe(true);
|
||||||
|
expect(scope.filterProgram({'id': 'cap_id_4'})).toBe(true);
|
||||||
|
expect(scope.filterProgram({'id': 'cap_id_5'})).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,20 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/* Jasmine specs for Refstack filters */
|
||||||
|
describe('Refstack filters', function() {
|
||||||
|
|
||||||
|
describe('Filter: arrayConverter', function() {
|
||||||
|
var $filter;
|
||||||
|
beforeEach(module('refstackApp'));
|
||||||
|
beforeEach(inject(function(_$filter_) {
|
||||||
|
$filter = _$filter_('arrayConverter');
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should convert dict to array of dict values', function () {
|
||||||
|
var object = { 'id1': {'key1': 'value1'}, 'id2': {'key2': 'value2'}};
|
||||||
|
var expected = [{'key1': 'value1', 'id': 'id1'},
|
||||||
|
{'key2': 'value2', 'id': 'id2'}];
|
||||||
|
expect($filter(object)).toEqual(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue