Moved Content Provider View in new xos generator
diff --git a/xos/core/xoslib/dashboards/xosContentProvider.html b/xos/core/xoslib/dashboards/xosContentProvider.html
index 9439fef..22b0620 100644
--- a/xos/core/xoslib/dashboards/xosContentProvider.html
+++ b/xos/core/xoslib/dashboards/xosContentProvider.html
@@ -1,7 +1,14 @@
+<!-- browserSync -->
+
+<!-- inject:css -->
+<link rel="stylesheet" href="/css/dev.css">
+<!-- endinject -->
+
<div ng-app="xos.contentProvider">
- <ng-view></ng-view>
+ <div ui-view></div>
</div>
-<link rel="stylesheet" href="{{ STATIC_URL }}/css/xosLib.css">
-<script src="{{ STATIC_URL }}js/vendor/xosContentProviderVendor.js"></script>
-<script src="{{ STATIC_URL }}js/xosContentProvider.js"></script>
\ No newline at end of file
+
+<!-- inject:js -->
+<script src="/../../static/js/xosContentProvider.js"></script>
+<!-- endinject -->
diff --git a/xos/core/xoslib/ngXosLib/generator-xos/app/templates/package.json b/xos/core/xoslib/ngXosLib/generator-xos/app/templates/package.json
index 63d7678..7a842fe 100644
--- a/xos/core/xoslib/ngXosLib/generator-xos/app/templates/package.json
+++ b/xos/core/xoslib/ngXosLib/generator-xos/app/templates/package.json
@@ -20,6 +20,7 @@
"dependencies": {},
"devDependencies": {
"browser-sync": "^2.9.11",
+ "del": "^2.0.2",
"gulp": "^3.9.0",
"gulp-angular-filesort": "^1.1.1",
"gulp-angular-templatecache": "^1.8.0",
diff --git a/xos/core/xoslib/ngXosViews/contentProvider/.eslintrc b/xos/core/xoslib/ngXosViews/contentProvider/.eslintrc
new file mode 100644
index 0000000..c852748
--- /dev/null
+++ b/xos/core/xoslib/ngXosViews/contentProvider/.eslintrc
@@ -0,0 +1,42 @@
+{
+ "ecmaFeatures": {
+ "blockBindings": true,
+ "forOf": true,
+ "destructuring": true,
+ "arrowFunctions": true,
+ "templateStrings": true
+ },
+ "env": {
+ "browser": true,
+ "node": true,
+ "es6": true
+ },
+ "plugins": [
+ //"angular"
+ ],
+ "rules": {
+ "quotes": [2, "single"],
+ "camelcase": [1, {"properties": "always"}],
+ "no-underscore-dangle": 1,
+ "eqeqeq": [2, "smart"],
+ "no-alert": 1,
+ "key-spacing": [1, { "beforeColon": false, "afterColon": true }],
+ "indent": [2, 2],
+ "no-irregular-whitespace": 1,
+ "eol-last": 0,
+ "max-nested-callbacks": [2, 4],
+ "comma-spacing": [1, {"before": false, "after": true}],
+ "no-trailing-spaces": [1, { skipBlankLines: true }],
+ "no-unused-vars": [1, {"vars": "all", "args": "after-used"}],
+ "new-cap": 0,
+
+ //"angular/ng_module_name": [2, '/^xos\.*[a-z]*$/'],
+ //"angular/ng_controller_name": [2, '/^[a-z].*Ctrl$/'],
+ //"angular/ng_service_name": [2, '/^[A-Z].*Service$/'],
+ //"angular/ng_directive_name": [2, '/^[a-z]+[[A-Z].*]*$/'],
+ //"angular/ng_di": [0, "function or array"]
+ },
+ "globals" :{
+ "angular": true
+ }
+}
\ No newline at end of file
diff --git a/xos/core/xoslib/ngXosViews/contentProvider/bower.json b/xos/core/xoslib/ngXosViews/contentProvider/bower.json
index 96e6da5..9c85e88 100644
--- a/xos/core/xoslib/ngXosViews/contentProvider/bower.json
+++ b/xos/core/xoslib/ngXosViews/contentProvider/bower.json
@@ -14,12 +14,13 @@
"test",
"tests"
],
- "dependencies": {},
+ "dependencies": {
+ },
"devDependencies": {
"jquery": "~2.1.4",
"angular-mocks": "~1.4.7",
"angular": "~1.4.7",
- "angular-route": "~1.4.7",
+ "angular-ui-router": "~0.2.15",
"angular-cookies": "~1.4.7",
"angular-resource": "~1.4.7",
"ng-lodash": "~0.3.0",
diff --git a/xos/core/xoslib/ngXosViews/contentProvider/gulp/build.js b/xos/core/xoslib/ngXosViews/contentProvider/gulp/build.js
index 238001d..a633fbf 100644
--- a/xos/core/xoslib/ngXosViews/contentProvider/gulp/build.js
+++ b/xos/core/xoslib/ngXosViews/contentProvider/gulp/build.js
@@ -1,11 +1,11 @@
'use strict';
// BUILD
-//
+//
// The only purpose of this gulpfile is to build a XOS view and copy the correct files into
// .html => dashboards
// .js (minified and concat) => static/js
-//
+//
// The template are parsed and added to js with angular $templateCache
var gulp = require('gulp');
@@ -13,36 +13,41 @@
var uglify = require('gulp-uglify');
var templateCache = require('gulp-angular-templatecache');
var runSequence = require('run-sequence');
-var minifyHtml = require("gulp-minify-html");
-var concat = require("gulp-concat");
+var concat = require('gulp-concat');
var del = require('del');
var wiredep = require('wiredep');
-var babel = require('gulp-babel');
var angularFilesort = require('gulp-angular-filesort');
var _ = require('lodash');
+var eslint = require('gulp-eslint');
+var inject = require('gulp-inject');
+var rename = require('gulp-rename');
+var replace = require('gulp-replace');
module.exports = function(options){
- // empty the dist folder
+ // delete previous builded file
gulp.task('clean', function(){
- return del([options.dist + '**/*']);
+ return del(
+ [options.dashboards + 'xosContentProvider.html'],
+ {force: true}
+ );
});
// compile and minify scripts
gulp.task('scripts', function() {
return gulp.src([
- options.tmp + '**/*.js'
- ])
- .pipe(ngAnnotate())
- .pipe(angularFilesort())
- .pipe(concat('xosContentProvider.js'))
- .pipe(uglify())
- .pipe(gulp.dest(options.dist));
+ options.tmp + '**/*.js'
+ ])
+ .pipe(ngAnnotate())
+ .pipe(angularFilesort())
+ .pipe(concat('xosContentProvider.js'))
+ .pipe(uglify())
+ .pipe(gulp.dest(options.static + 'js/'));
});
// set templates in cache
gulp.task('templates', function(){
- return gulp.src("./src/templates/*.html")
+ return gulp.src('./src/templates/*.html')
.pipe(templateCache({
module: 'xos.contentProvider',
root: 'templates/'
@@ -50,22 +55,23 @@
.pipe(gulp.dest(options.tmp));
});
- // copy js output to Django Folder
- gulp.task('copyJs', function(){
- return gulp.src('dist/xosContentProvider.js')
- .pipe(gulp.dest(options.static + 'js/'))
- });
-
- // copy vendor js output to Django Folder
- gulp.task('copyVendor', function(){
- return gulp.src(options.dist + 'xosContentProviderVendor.js')
- .pipe(gulp.dest(options.static + 'js/vendor/'));
- });
-
// copy html index to Django Folder
- gulp.task('copyHtml', function(){
- return gulp.src(options.src + 'xosContentProvider.html')
- .pipe(gulp.dest(options.dashboards))
+ gulp.task('copyHtml', ['clean'], function(){
+ return gulp.src(options.src + 'index.html')
+ // remove dev dependencies from html
+ .pipe(replace(/<!-- bower:css -->(\n.*)*\n<!-- endbower --><!-- endcss -->/, ''))
+ .pipe(replace(/<!-- bower:js -->(\n.*)*\n<!-- endbower --><!-- endjs -->/, ''))
+ // injecting minified files
+ .pipe(
+ inject(
+ gulp.src([
+ options.static + 'js/vendor/xosContentProviderVendor.js',
+ options.static + 'js/xosContentProvider.js'
+ ])
+ )
+ )
+ .pipe(rename('xosContentProvider.html'))
+ .pipe(gulp.dest(options.dashboards));
});
// minify vendor js files
@@ -83,26 +89,24 @@
return gulp.src(bowerDeps)
.pipe(concat('xosContentProviderVendor.js'))
.pipe(uglify())
- .pipe(gulp.dest(options.dist));
+ .pipe(gulp.dest(options.static + 'js/vendor/'));
});
- // TODO vendor
- // - define a list of common components (eg: angular, angular-route, ...)
- // - find the difference between local components e common components
- // - minify only the local
- // - unify wiredep, filter and copyVendor task
+ gulp.task('lint', function () {
+ return gulp.src(['src/js/**/*.js'])
+ .pipe(eslint())
+ .pipe(eslint.format())
+ .pipe(eslint.failAfterError());
+ });
gulp.task('build', function() {
runSequence(
- 'clean',
'templates',
'babel',
'scripts',
- 'copyJs',
- 'copyHtml',
'wiredep',
- 'copyVendor',
+ 'copyHtml',
'cleanTmp'
);
});
-}
\ No newline at end of file
+};
\ No newline at end of file
diff --git a/xos/core/xoslib/ngXosViews/contentProvider/gulp/server.js b/xos/core/xoslib/ngXosViews/contentProvider/gulp/server.js
index 907dd19..722eb58 100644
--- a/xos/core/xoslib/ngXosViews/contentProvider/gulp/server.js
+++ b/xos/core/xoslib/ngXosViews/contentProvider/gulp/server.js
@@ -40,10 +40,14 @@
baseDir: options.src,
routes: {
'/api': options.api,
- '/xosHelpers': options.helpers
+ '/xosHelpers/src': options.helpers
},
middleware: function(req, res, next){
- if(req.url.indexOf('no_hyperlinks') !== -1){
+ if(
+ req.url.indexOf('/xos/') !== -1 ||
+ req.url.indexOf('/xoslib/') !== -1 ||
+ req.url.indexOf('/hpcapi/') !== -1
+ ){
proxy.web(req, res);
}
else{
@@ -70,7 +74,7 @@
});
// inject scripts
- gulp.task('inject', ['cleanTmp', 'babel'],function(){
+ gulp.task('injectScript', ['cleanTmp', 'babel'], function(){
return gulp.src(options.src + 'index.html')
.pipe(
inject(
@@ -88,6 +92,20 @@
.pipe(gulp.dest(options.src));
});
+ // inject CSS
+ gulp.task('injectCss', function(){
+ return gulp.src(options.src + 'index.html')
+ .pipe(
+ inject(
+ gulp.src(options.src + 'css/*.css'),
+ {
+ ignorePath: [options.src]
+ }
+ )
+ )
+ .pipe(gulp.dest(options.src));
+ });
+
// inject bower dependencies with wiredep
gulp.task('bower', function () {
return gulp.src(options.src + 'index.html')
@@ -106,8 +124,9 @@
gulp.task('serve', function() {
runSequence(
'bower',
- 'inject',
+ 'injectScript',
+ 'injectCss',
['browser']
);
});
-}
\ No newline at end of file
+};
\ No newline at end of file
diff --git a/xos/core/xoslib/ngXosViews/contentProvider/gulpfile.js b/xos/core/xoslib/ngXosViews/contentProvider/gulpfile.js
index 948a99d..f114774 100644
--- a/xos/core/xoslib/ngXosViews/contentProvider/gulpfile.js
+++ b/xos/core/xoslib/ngXosViews/contentProvider/gulpfile.js
@@ -9,7 +9,7 @@
tmp: 'src/.tmp',
dist: 'dist/',
api: '../../ngXosLib/api/',
- helpers: '../../ngXosLib/xosHelpers/',
+ helpers: '../../ngXosLib/xosHelpers/src/',
static: '../../static/', // this is the django static folder
dashboards: '../../dashboards/' // this is the django html folder
};
diff --git a/xos/core/xoslib/ngXosViews/contentProvider/package.json b/xos/core/xoslib/ngXosViews/contentProvider/package.json
index 9fa9379..80d34f9 100644
--- a/xos/core/xoslib/ngXosViews/contentProvider/package.json
+++ b/xos/core/xoslib/ngXosViews/contentProvider/package.json
@@ -7,7 +7,8 @@
"start": "gulp serve",
"prebuild": "npm install && bower install",
"build": "gulp",
- "test": "karma start"
+ "test": "karma start",
+ "lint": "eslint src/js/"
},
"keywords": [
"XOS",
@@ -27,6 +28,8 @@
"gulp-concat": "^2.6.0",
"gulp-inject": "^3.0.0",
"gulp-minify-html": "^1.0.4",
+ "gulp-rename": "^1.2.2",
+ "gulp-replace": "^0.5.4",
"gulp-uglify": "^1.4.2",
"http-proxy": "^1.12.0",
"proxy-middleware": "^0.15.0",
@@ -34,6 +37,9 @@
"wiredep": "^3.0.0-beta",
"wrench": "^1.5.8",
"gulp-ng-annotate": "^1.1.0",
- "lodash": "^3.10.1"
+ "lodash": "^3.10.1",
+ "eslint": "^1.8.0",
+ "eslint-plugin-angular": "linkmesrl/eslint-plugin-angular",
+ "gulp-eslint": "^1.0.0"
}
}
diff --git a/xos/core/xoslib/ngXosViews/contentProvider/src/css/dev.css b/xos/core/xoslib/ngXosViews/contentProvider/src/css/dev.css
new file mode 100644
index 0000000..af92e84
--- /dev/null
+++ b/xos/core/xoslib/ngXosViews/contentProvider/src/css/dev.css
@@ -0,0 +1,5 @@
+[ng-app]{
+ position: absolute;
+ top: 100px;
+ left: 200px;
+}
\ No newline at end of file
diff --git a/xos/core/xoslib/ngXosViews/contentProvider/src/index.html b/xos/core/xoslib/ngXosViews/contentProvider/src/index.html
index 510f27e..ba0006c 100644
--- a/xos/core/xoslib/ngXosViews/contentProvider/src/index.html
+++ b/xos/core/xoslib/ngXosViews/contentProvider/src/index.html
@@ -1,36 +1,30 @@
<!-- browserSync -->
<!-- bower:css -->
<link rel="stylesheet" href="vendor/bootstrap-css/css/bootstrap.css" />
-<!-- endbower -->
+<!-- endbower --><!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/css/dev.css">
+<!-- endinject -->
-<style>
- .container{
- position: absolute;
- top: 100px;
- left: 200px;
- }
-</style>
-
-<div class="container">
- <div ng-app="xos.contentProvider">
- <ng-view></ng-view>
- </div>
+<div ng-app="xos.contentProvider">
+ <div ui-view></div>
</div>
<!-- bower:js -->
+<script src="vendor/jquery/dist/jquery.js"></script>
<script src="vendor/angular/angular.js"></script>
-<script src="vendor/angular-route/angular-route.js"></script>
+<script src="vendor/angular-mocks/angular-mocks.js"></script>
+<script src="vendor/angular-ui-router/release/angular-ui-router.js"></script>
<script src="vendor/angular-cookies/angular-cookies.js"></script>
<script src="vendor/angular-resource/angular-resource.js"></script>
<script src="vendor/ng-lodash/build/ng-lodash.js"></script>
<script src="vendor/bootstrap-css/js/bootstrap.js"></script>
-<script src="vendor/angular-mocks/angular-mocks.js"></script>
-<script src="vendor/jquery/dist/jquery.js"></script>
-<!-- endbower -->
+<!-- endbower --><!-- endjs -->
<!-- inject:js -->
-<script src="/xosHelpers/xosHelpers.module.js"></script>
-<script src="/xosHelpers/services/noHyperlinks.interceptor.js"></script>
-<script src="/xosHelpers/services/csrfToken.interceptor.js"></script>
+<script src="/xosHelpers/src/xosHelpers.module.js"></script>
+<script src="/xosHelpers/src/services/noHyperlinks.interceptor.js"></script>
+<script src="/xosHelpers/src/services/csrfToken.interceptor.js"></script>
+<script src="/xosHelpers/src/services/api.services.js"></script>
<script src="/api/ng-xoslib.js"></script>
<script src="/api/ng-xos.js"></script>
<script src="/api/ng-hpcapi.js"></script>
diff --git a/xos/core/xoslib/ngXosViews/contentProvider/src/js/main.js b/xos/core/xoslib/ngXosViews/contentProvider/src/js/main.js
index 10fc506..256b95c 100644
--- a/xos/core/xoslib/ngXosViews/contentProvider/src/js/main.js
+++ b/xos/core/xoslib/ngXosViews/contentProvider/src/js/main.js
@@ -9,31 +9,35 @@
angular.module('xos.contentProvider', [
'ngResource',
- 'ngRoute',
'ngCookies',
'ngLodash',
'xos.helpers',
+ 'ui.router',
'xos.xos'
])
-.config(($routeProvider) => {
-
- $routeProvider
- .when('/', {
+.config(($stateProvider, $urlRouterProvider) => {
+ $urlRouterProvider.otherwise('/');
+ $stateProvider
+ .state('list', {
+ url: '/',
template: '<content-provider-list></content-provider-list>',
})
- .when('/contentProvider/:id?', {
+ .state('details', {
+ url: '/contentProvider/:id?',
template: '<content-provider-detail></content-provider-detail>'
})
- .when('/contentProvider/:id/cdn_prefix', {
+ .state('cdn', {
+ url: '/contentProvider/:id/cdn_prefix',
template: '<content-provider-cdn></content-provider-cdn>'
})
- .when('/contentProvider/:id/origin_server', {
+ .state('server', {
+ url: '/contentProvider/:id/origin_server',
template: '<content-provider-server></content-provider-server>'
})
- .when('/contentProvider/:id/users', {
+ .state('users', {
+ url: '/contentProvider/:id/users',
template: '<content-provider-users></content-provider-users>'
- })
- .otherwise('/');
+ });
})
.config(function($httpProvider){
// add X-CSRFToken header for update, create, delete (!GET)
diff --git a/xos/core/xoslib/ngXosViews/contentProvider/src/templates/users-list.tpl.html b/xos/core/xoslib/ngXosViews/contentProvider/src/templates/users-list.tpl.html
new file mode 100644
index 0000000..2983ad0
--- /dev/null
+++ b/xos/core/xoslib/ngXosViews/contentProvider/src/templates/users-list.tpl.html
@@ -0,0 +1,14 @@
+<div class="row">
+ <h1>Users List</h1>
+ <p>This is only an example view.</p>
+</div>
+<div class="row">
+ <div class="span4">Email</div>
+ <div class="span4">First Name</div>
+ <div class="span4">Last Name</div>
+</div>
+<div class="row" ng-repeat="user in vm.users">
+ <div class="span4">{{user.email}}</div>
+ <div class="span4">{{user.firstname}}</div>
+ <div class="span4">{{user.lastname}}</div>
+</div>
\ No newline at end of file
diff --git a/xos/core/xoslib/ngXosViews/contentProvider/src/xosContentProvider.html b/xos/core/xoslib/ngXosViews/contentProvider/src/xosContentProvider.html
deleted file mode 100644
index 9439fef..0000000
--- a/xos/core/xoslib/ngXosViews/contentProvider/src/xosContentProvider.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<div ng-app="xos.contentProvider">
- <ng-view></ng-view>
-</div>
-
-<link rel="stylesheet" href="{{ STATIC_URL }}/css/xosLib.css">
-<script src="{{ STATIC_URL }}js/vendor/xosContentProviderVendor.js"></script>
-<script src="{{ STATIC_URL }}js/xosContentProvider.js"></script>
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xosContentProvider.js b/xos/core/xoslib/static/js/xosContentProvider.js
index 293fa25..5e39995 100644
--- a/xos/core/xoslib/static/js/xosContentProvider.js
+++ b/xos/core/xoslib/static/js/xosContentProvider.js
@@ -1 +1 @@
-"use strict";angular.module("xos.contentProvider",["ngResource","ngRoute","ngCookies","ngLodash","xos.helpers","xos.xos"]).config(["$routeProvider",function(n){n.when("/",{template:"<content-provider-list></content-provider-list>"}).when("/contentProvider/:id?",{template:"<content-provider-detail></content-provider-detail>"}).when("/contentProvider/:id/cdn_prefix",{template:"<content-provider-cdn></content-provider-cdn>"}).when("/contentProvider/:id/origin_server",{template:"<content-provider-server></content-provider-server>"}).when("/contentProvider/:id/users",{template:"<content-provider-users></content-provider-users>"}).otherwise("/")}]).config(["$httpProvider",function(n){n.interceptors.push("SetCSRFToken"),n.interceptors.push("NoHyperlinks")}]).service("ContentProvider",["$resource",function(n){return n("/hpcapi/contentproviders/:id/",{id:"@id"},{update:{method:"PUT"}})}]).service("ServiceProvider",["$resource",function(n){return n("/hpcapi/serviceproviders/:id/",{id:"@id"})}]).service("CdnPrefix",["$resource",function(n){return n("/hpcapi/cdnprefixs/:id/",{id:"@id"})}]).service("OriginServer",["$resource",function(n){return n("/hpcapi/originservers/:id/",{id:"@id"})}]).service("User",["$resource",function(n){return n("/xos/users/:id/",{id:"@id"})}]).directive("cpActions",["ContentProvider","$location",function(n,e){return{restrict:"E",scope:{id:"=id"},bindToController:!0,controllerAs:"vm",templateUrl:"templates/cp_actions.html",controller:function(){this.deleteCp=function(t){n["delete"]({id:t}).$promise.then(function(){e.url("/")})}}}}]).directive("contentProviderList",["ContentProvider","lodash",function(n,e){return{restrict:"E",controllerAs:"vm",scope:{},templateUrl:"templates/cp_list.html",controller:function(){var t=this;n.query().$promise.then(function(n){t.contentProviderList=n})["catch"](function(n){throw new Error(n)}),this.deleteCp=function(s){n["delete"]({id:s}).$promise.then(function(){e.remove(t.contentProviderList,{id:s})})}}}}]).directive("contentProviderDetail",["ContentProvider","ServiceProvider","$routeParams","$location",function(n,e,t,s){return{restrict:"E",controllerAs:"vm",scope:{},templateUrl:"templates/cp_detail.html",controller:function(){this.pageName="detail";var i=this;t.id?n.get({id:t.id}).$promise.then(function(n){i.cp=n})["catch"](function(n){i.result={status:0,msg:n.data.detail}}):i.cp=new n,e.query().$promise.then(function(n){i.sp=n}),this.saveContentProvider=function(n){var e,t=!1;n.id?e=n.$update():(t=!0,n.name=n.humanReadableName,e=n.$save()),e.then(function(n){i.result={status:1,msg:"Content Provider Saved"},t&&s.url("contentProvider/"+n.id+"/")})["catch"](function(n){i.result={status:0,msg:n.data.detail}})}}}}]).directive("contentProviderCdn",["$routeParams","CdnPrefix","ContentProvider","lodash",function(n,e,t,s){return{restrict:"E",controllerAs:"vm",scope:{},templateUrl:"templates/cp_cdn_prefix.html",controller:function(){var i=this;this.pageName="cdn",n.id&&t.get({id:n.id}).$promise.then(function(n){i.cp=n})["catch"](function(n){i.result={status:0,msg:n.data.detail}}),e.query().$promise.then(function(e){i.prf=e,i.cp_prf=s.where(e,{contentProvider:parseInt(n.id)})})["catch"](function(n){i.result={status:0,msg:n.data.detail}}),this.addPrefix=function(t){t.contentProvider=n.id;var s=new e(t);s.$save().then(function(n){i.cp_prf.push(n)})["catch"](function(n){i.result={status:0,msg:n.data.detail}})},this.removePrefix=function(n){n.$delete().then(function(){s.remove(i.cp_prf,n)})["catch"](function(n){i.result={status:0,msg:n.data.detail}})}}}}]).directive("contentProviderServer",["$routeParams","OriginServer","ContentProvider","lodash",function(n,e,t,s){return{restrict:"E",controllerAs:"vm",scope:{},templateUrl:"templates/cp_origin_server.html",controller:function(){this.pageName="server",this.protocols={http:"HTTP",rtmp:"RTMP",rtp:"RTP",shout:"SHOUTcast"};var i=this;n.id&&t.get({id:n.id}).$promise.then(function(n){i.cp=n})["catch"](function(n){i.result={status:0,msg:n.data.detail}}),e.query({contentProvider:n.id}).$promise.then(function(n){i.cp_os=n})["catch"](function(n){i.result={status:0,msg:n.data.detail}}),this.addOrigin=function(t){t.contentProvider=n.id;var s=new e(t);s.$save().then(function(n){i.cp_os.push(n)})["catch"](function(n){i.result={status:0,msg:n.data.detail}})},this.removeOrigin=function(n){n.$delete().then(function(){s.remove(i.cp_os,n)})["catch"](function(n){i.result={status:0,msg:n.data.detail}})}}}}]).directive("contentProviderUsers",["$routeParams","ContentProvider","User","lodash",function(n,e,t,s){return{restrict:"E",controllerAs:"vm",scope:{},templateUrl:"templates/cp_user.html",controller:function(){var i=this;this.pageName="user",this.cp_users=[],n.id&&t.query().$promise.then(function(t){return i.users=t,e.get({id:n.id}).$promise}).then(function(n){return n.users=i.populateUser(n.users,i.users),n}).then(function(n){i.cp=n})["catch"](function(n){i.result={status:0,msg:n.data.detail}}),this.populateUser=function(n,e){for(var t=0;t<n.length;t++)n[t]=s.find(e,{id:n[t]});return n},this.addUserToCp=function(n){i.cp.users.push(n)},this.removeUserFromCp=function(n){s.remove(i.cp.users,n)},this.saveContentProvider=function(n){n.users=s.pluck(n.users,"id"),n.$update().then(function(n){i.cp.users=i.populateUser(n.users,i.users),i.result={status:1,msg:"Content Provider Saved"}})["catch"](function(n){i.result={status:0,msg:n.data.detail}})}}}}]),angular.module("xos.contentProvider").run(["$templateCache",function(n){n.put("templates/cp_actions.html",'<a href="#/" class="btn btn-default">\n <i class="icon icon-arrow-left"></i>Back\n</a>\n<a href="#/contentProvider/" class="btn btn-success">\n <i class="icon icon-plus"></i>Create\n</a>\n<a ng-click="vm.deleteCp(vm.id)" class="btn btn-danger">\n <i class="icon icon-remove"></i>Remove\n</a>'),n.put("templates/cp_cdn_prefix.html",'<div class="row-fluid">\n <div class="span6">\n <h1>{$ vm.cp.humanReadableName $}</h1>\n </div>\n <div class="span6 text-right">\n <cp-actions id="vm.cp.id"></cp-actions>\n </div>\n</div>\n<hr>\n<div class="row-fluid">\n <div class="span2">\n <div ng-include="\'templates/cp_side_nav.html\'"></div>\n </div>\n <div class="span10">\n <div ng-repeat="item in vm.cp_prf" class="well">\n <div class="row-fluid">\n <div class="span4">\n {{item.humanReadableName}}\n </div>\n <div class="span6">\n <!-- TODO show the name instead that id -->\n {{item.defaultOriginServer}}\n </div>\n <div class="span2">\n <a ng-click="vm.removePrefix(item)" class="btn btn-danger pull-right">\n <i class="icon icon-remove"></i>\n </a>\n </div>\n </div>\n </div>\n <hr>\n <form ng-submit="vm.addPrefix(vm.new_prf)">\n <div class="row-fluid">\n <div class="span4">\n <label>Prefix</label>\n <input type="text" ng-model="vm.new_prf.prefix" required style="max-width: 90%">\n </div>\n <div class="span6">\n <label>Default Origin Server</label>\n <select ng-model="vm.new_prf.defaultOriginServer" style="max-width: 100%">\n <option ng-repeat="prf in vm.prf" ng-value="prf.id">{$ prf.humanReadableName $}</option>\n </select>\n </div>\n <div class="span2 text-right">\n <button class="btn btn-success margin-wells">\n <i class="icon icon-plus"></i>\n </button>\n </div>\n </div>\n </form>\n <div class="alert" ng-show="vm.result" ng-class="{\'alert-success\': vm.result.status === 1,\'alert-error\': vm.result.status === 0}">\n {$ vm.result.msg $}\n </div>\n </div>\n</div>'),n.put("templates/cp_detail.html",'<div class="row-fluid">\n <div class="span6">\n <h1>{$ vm.cp.humanReadableName $}</h1>\n </div>\n <div class="span6 text-right">\n <cp-actions id="vm.cp.id"></cp-actions>\n </div>\n</div>\n<hr>\n<div class="row-fluid">\n <div ng-show="vm.cp.id" class="span2">\n <div ng-include="\'templates/cp_side_nav.html\'"></div>\n </div>\n <div ng-class="{span10: vm.cp.id, span12: !vm.cp.id}">\n <!-- TODO hide form on not found -->\n <form ng-submit="vm.saveContentProvider(vm.cp)">\n <fieldset>\n <div class="row-fluid">\n <div class="span6">\n <label>Name:</label>\n <input type="text" ng-model="vm.cp.humanReadableName" required/>\n </div>\n <div class="span6">\n <label class="checkbox">\n <input type="checkbox" ng-model="vm.cp.enabled" /> Enabled\n </label>\n </div>\n </div>\n <div class="row-fluid">\n <div class="span12">\n <label>Description</label>\n <textarea style="width: 100%" ng-model="vm.cp.description"></textarea>\n </div>\n </div>\n <div class="row-fluid">\n <div class="span12">\n <label>Service provider</label>\n <select required ng-model="vm.cp.serviceProvider" ng-options="sp.id as sp.humanReadableName for sp in vm.sp"></select>\n </div>\n </div>\n <div class="row-fluid">\n <div class="span12">\n <button class="btn btn-success">\n <span ng-show="vm.cp.id">Save</span>\n <span ng-show="!vm.cp.id">Create</span>\n </button>\n </div>\n </div>\n </fieldset>\n </form>\n <div class="alert" ng-show="vm.result" ng-class="{\'alert-success\': vm.result.status === 1,\'alert-error\': vm.result.status === 0}">\n {$ vm.result.msg $}\n </div>\n </div>\n</div>'),n.put("templates/cp_list.html",'<table class="table table-striped" ng-show="vm.contentProviderList.length > 0">\n <thead>\n <tr>\n <th>\n Name\n </th>\n <th>Description</th>\n <th>Status</th>\n <th></th>\n </tr>\n </thead>\n <tr ng-repeat="item in vm.contentProviderList">\n <td>\n <a href="#/contentProvider/{$ item.id $}">{$ item.humanReadableName $}</a>\n </td>\n <td>\n {$ item.description $}\n </td>\n <td>\n {$ item.enabled $}\n </td>\n <td class="text-right">\n <a ng-click="vm.deleteCp(item.id)" class="btn btn-danger"><i class="icon icon-remove"></i></a></td>\n </tr>\n</table>\n<div class="alert alert-error" ng-show="vm.contentProviderList.length == 0">\n No Content Provider defined\n</div>\n\n<div class="row">\n <div class="span12 text-right">\n <a class="btn btn-success"href="#/contentProvider/">Create</a>\n </div>\n</div>'),n.put("templates/cp_origin_server.html",'<div class="row-fluid">\n <div class="span6">\n <h1>{$ vm.cp.humanReadableName $}</h1>\n </div>\n <div class="span6 text-right">\n <cp-actions id="vm.cp.id"></cp-actions>\n </div>\n</div>\n<hr>\n<div class="row-fluid">\n <div class="span2">\n <div ng-include="\'templates/cp_side_nav.html\'"></div>\n </div>\n <div class="span10">\n <div ng-repeat="item in vm.cp_os" class="well">\n <div class="row-fluid">\n <div class="span4">\n {{item.humanReadableName}}\n </div>\n <div class="span6">\n <!-- TODO shoe the name instead that url -->\n {{item.defaultOriginServer}}\n </div>\n <div class="span2">\n <a ng-click="vm.removeOrigin(item)" class="btn btn-danger pull-right">\n <i class="icon icon-remove"></i>\n </a>\n </div>\n </div>\n </div>\n <hr>\n <form ng-submit="vm.addOrigin(vm.new_os)">\n <div class="row-fluid">\n <div class="span4">\n <label>Protocol</label>\n <select ng-model="vm.new_os.protocol" ng-options="k as v for (k,v) in vm.protocols" style="max-width: 100%;"></select>\n </div>\n <div class="span6">\n <label>Url</label>\n <input type="text" ng-model="vm.new_os.url" required>\n </div>\n <div class="span2 text-right">\n <button class="btn btn-success margin-wells">\n <i class="icon icon-plus"></i>\n </button>\n </div>\n </div>\n </form>\n <div class="alert" ng-show="vm.result" ng-class="{\'alert-success\': vm.result.status === 1,\'alert-error\': vm.result.status === 0}">\n {$ vm.result.msg $}\n </div>\n </div>\n</div>'),n.put("templates/cp_side_nav.html",'<ul class="nav nav-list">\n <li>\n <a class="btn" ng-class="{\'btn-primary\': vm.pageName == \'detail\'}" href="#/contentProvider/{$ vm.cp.id $}">Details</a>\n </li>\n <li>\n <a class="btn" ng-class="{\'btn-primary\': vm.pageName == \'cdn\'}" href="#/contentProvider/{$ vm.cp.id $}/cdn_prefix">Cdn Prexix</a>\n </li>\n <li>\n <a class="btn" ng-class="{\'btn-primary\': vm.pageName == \'server\'}" href="#/contentProvider/{$ vm.cp.id $}/origin_server">Origin Server</a>\n </li>\n <li>\n <a class="btn" ng-class="{\'btn-primary\': vm.pageName == \'user\'}" href="#/contentProvider/{$ vm.cp.id $}/users">Users</a>\n </li>\n</ul>'),n.put("templates/cp_user.html",'<div class="row-fluid">\n <div class="span6">\n <h1>{$ vm.cp.humanReadableName $}</h1>\n </div>\n <div class="span6 text-right">\n <cp-actions id="vm.cp.id"></cp-actions>\n </div>\n</div>\n<hr>\n<div class="row-fluid">\n <div class="span2">\n <div ng-include="\'templates/cp_side_nav.html\'"></div>\n </div>\n <div class="span10">\n <div ng-repeat="item in vm.cp.users" class="well">\n <div class="row-fluid">\n <div class="span3">\n {{item.firstname}}\n </div>\n <div class="span3">\n {{item.lastname}}\n </div>\n <div class="span4">\n {{item.email}}\n </div>\n <div class="span2">\n <a ng-click="vm.removeUserFromCp(item)" class="btn btn-danger pull-right">\n <i class="icon icon-remove"></i>\n </a>\n </div>\n </div>\n </div>\n <hr>\n <form ng-submit="vm.saveContentProvider(vm.cp)">\n <div class="row-fluid">\n <div class="span8">\n <label>Select user:</label>\n <select ng-model="vm.user" ng-options="u as u.username for u in vm.users" ng-change="vm.addUserToCp(vm.user)"></select>\n </div> \n <div class="span4 text-right">\n <button class="btn btn-success margin-wells">\n Save\n </button>\n </div>\n </div>\n </form>\n <div class="alert" ng-show="vm.result" ng-class="{\'alert-success\': vm.result.status === 1,\'alert-error\': vm.result.status === 0}">\n {$ vm.result.msg $}\n </div>\n </div>\n</div>')}]);
\ No newline at end of file
+"use strict";angular.module("xos.contentProvider",["ngResource","ngCookies","ngLodash","xos.helpers","ui.router","xos.xos"]).config(["$stateProvider","$urlRouterProvider",function(n,e){e.otherwise("/"),n.state("list",{url:"/",template:"<content-provider-list></content-provider-list>"}).state("details",{url:"/contentProvider/:id?",template:"<content-provider-detail></content-provider-detail>"}).state("cdn",{url:"/contentProvider/:id/cdn_prefix",template:"<content-provider-cdn></content-provider-cdn>"}).state("server",{url:"/contentProvider/:id/origin_server",template:"<content-provider-server></content-provider-server>"}).state("users",{url:"/contentProvider/:id/users",template:"<content-provider-users></content-provider-users>"})}]).config(["$httpProvider",function(n){n.interceptors.push("SetCSRFToken"),n.interceptors.push("NoHyperlinks")}]).service("ContentProvider",["$resource",function(n){return n("/hpcapi/contentproviders/:id/",{id:"@id"},{update:{method:"PUT"}})}]).service("ServiceProvider",["$resource",function(n){return n("/hpcapi/serviceproviders/:id/",{id:"@id"})}]).service("CdnPrefix",["$resource",function(n){return n("/hpcapi/cdnprefixs/:id/",{id:"@id"})}]).service("OriginServer",["$resource",function(n){return n("/hpcapi/originservers/:id/",{id:"@id"})}]).service("User",["$resource",function(n){return n("/xos/users/:id/",{id:"@id"})}]).directive("cpActions",["ContentProvider","$location",function(n,e){return{restrict:"E",scope:{id:"=id"},bindToController:!0,controllerAs:"vm",templateUrl:"templates/cp_actions.html",controller:function(){this.deleteCp=function(t){n["delete"]({id:t}).$promise.then(function(){e.url("/")})}}}}]).directive("contentProviderList",["ContentProvider","lodash",function(n,e){return{restrict:"E",controllerAs:"vm",scope:{},templateUrl:"templates/cp_list.html",controller:function(){var t=this;n.query().$promise.then(function(n){t.contentProviderList=n})["catch"](function(n){throw new Error(n)}),this.deleteCp=function(s){n["delete"]({id:s}).$promise.then(function(){e.remove(t.contentProviderList,{id:s})})}}}}]).directive("contentProviderDetail",["ContentProvider","ServiceProvider","$routeParams","$location",function(n,e,t,s){return{restrict:"E",controllerAs:"vm",scope:{},templateUrl:"templates/cp_detail.html",controller:function(){this.pageName="detail";var i=this;t.id?n.get({id:t.id}).$promise.then(function(n){i.cp=n})["catch"](function(n){i.result={status:0,msg:n.data.detail}}):i.cp=new n,e.query().$promise.then(function(n){i.sp=n}),this.saveContentProvider=function(n){var e,t=!1;n.id?e=n.$update():(t=!0,n.name=n.humanReadableName,e=n.$save()),e.then(function(n){i.result={status:1,msg:"Content Provider Saved"},t&&s.url("contentProvider/"+n.id+"/")})["catch"](function(n){i.result={status:0,msg:n.data.detail}})}}}}]).directive("contentProviderCdn",["$routeParams","CdnPrefix","ContentProvider","lodash",function(n,e,t,s){return{restrict:"E",controllerAs:"vm",scope:{},templateUrl:"templates/cp_cdn_prefix.html",controller:function(){var i=this;this.pageName="cdn",n.id&&t.get({id:n.id}).$promise.then(function(n){i.cp=n})["catch"](function(n){i.result={status:0,msg:n.data.detail}}),e.query().$promise.then(function(e){i.prf=e,i.cp_prf=s.where(e,{contentProvider:parseInt(n.id)})})["catch"](function(n){i.result={status:0,msg:n.data.detail}}),this.addPrefix=function(t){t.contentProvider=n.id;var s=new e(t);s.$save().then(function(n){i.cp_prf.push(n)})["catch"](function(n){i.result={status:0,msg:n.data.detail}})},this.removePrefix=function(n){n.$delete().then(function(){s.remove(i.cp_prf,n)})["catch"](function(n){i.result={status:0,msg:n.data.detail}})}}}}]).directive("contentProviderServer",["$routeParams","OriginServer","ContentProvider","lodash",function(n,e,t,s){return{restrict:"E",controllerAs:"vm",scope:{},templateUrl:"templates/cp_origin_server.html",controller:function(){this.pageName="server",this.protocols={http:"HTTP",rtmp:"RTMP",rtp:"RTP",shout:"SHOUTcast"};var i=this;n.id&&t.get({id:n.id}).$promise.then(function(n){i.cp=n})["catch"](function(n){i.result={status:0,msg:n.data.detail}}),e.query({contentProvider:n.id}).$promise.then(function(n){i.cp_os=n})["catch"](function(n){i.result={status:0,msg:n.data.detail}}),this.addOrigin=function(t){t.contentProvider=n.id;var s=new e(t);s.$save().then(function(n){i.cp_os.push(n)})["catch"](function(n){i.result={status:0,msg:n.data.detail}})},this.removeOrigin=function(n){n.$delete().then(function(){s.remove(i.cp_os,n)})["catch"](function(n){i.result={status:0,msg:n.data.detail}})}}}}]).directive("contentProviderUsers",["$routeParams","ContentProvider","User","lodash",function(n,e,t,s){return{restrict:"E",controllerAs:"vm",scope:{},templateUrl:"templates/cp_user.html",controller:function(){var i=this;this.pageName="user",this.cp_users=[],n.id&&t.query().$promise.then(function(t){return i.users=t,e.get({id:n.id}).$promise}).then(function(n){return n.users=i.populateUser(n.users,i.users),n}).then(function(n){i.cp=n})["catch"](function(n){i.result={status:0,msg:n.data.detail}}),this.populateUser=function(n,e){for(var t=0;t<n.length;t++)n[t]=s.find(e,{id:n[t]});return n},this.addUserToCp=function(n){i.cp.users.push(n)},this.removeUserFromCp=function(n){s.remove(i.cp.users,n)},this.saveContentProvider=function(n){n.users=s.pluck(n.users,"id"),n.$update().then(function(n){i.cp.users=i.populateUser(n.users,i.users),i.result={status:1,msg:"Content Provider Saved"}})["catch"](function(n){i.result={status:0,msg:n.data.detail}})}}}}]),angular.module("xos.contentProvider").run(["$templateCache",function(n){n.put("templates/cp_actions.html",'<a href="#/" class="btn btn-default">\n <i class="icon icon-arrow-left"></i>Back\n</a>\n<a href="#/contentProvider/" class="btn btn-success">\n <i class="icon icon-plus"></i>Create\n</a>\n<a ng-click="vm.deleteCp(vm.id)" class="btn btn-danger">\n <i class="icon icon-remove"></i>Remove\n</a>'),n.put("templates/cp_cdn_prefix.html",'<div class="row-fluid">\n <div class="span6">\n <h1>{$ vm.cp.humanReadableName $}</h1>\n </div>\n <div class="span6 text-right">\n <cp-actions id="vm.cp.id"></cp-actions>\n </div>\n</div>\n<hr>\n<div class="row-fluid">\n <div class="span2">\n <div ng-include="\'templates/cp_side_nav.html\'"></div>\n </div>\n <div class="span10">\n <div ng-repeat="item in vm.cp_prf" class="well">\n <div class="row-fluid">\n <div class="span4">\n {{item.humanReadableName}}\n </div>\n <div class="span6">\n <!-- TODO show the name instead that id -->\n {{item.defaultOriginServer}}\n </div>\n <div class="span2">\n <a ng-click="vm.removePrefix(item)" class="btn btn-danger pull-right">\n <i class="icon icon-remove"></i>\n </a>\n </div>\n </div>\n </div>\n <hr>\n <form ng-submit="vm.addPrefix(vm.new_prf)">\n <div class="row-fluid">\n <div class="span4">\n <label>Prefix</label>\n <input type="text" ng-model="vm.new_prf.prefix" required style="max-width: 90%">\n </div>\n <div class="span6">\n <label>Default Origin Server</label>\n <select ng-model="vm.new_prf.defaultOriginServer" style="max-width: 100%">\n <option ng-repeat="prf in vm.prf" ng-value="prf.id">{$ prf.humanReadableName $}</option>\n </select>\n </div>\n <div class="span2 text-right">\n <button class="btn btn-success margin-wells">\n <i class="icon icon-plus"></i>\n </button>\n </div>\n </div>\n </form>\n <div class="alert" ng-show="vm.result" ng-class="{\'alert-success\': vm.result.status === 1,\'alert-error\': vm.result.status === 0}">\n {$ vm.result.msg $}\n </div>\n </div>\n</div>'),n.put("templates/cp_detail.html",'<div class="row-fluid">\n <div class="span6">\n <h1>{$ vm.cp.humanReadableName $}</h1>\n </div>\n <div class="span6 text-right">\n <cp-actions id="vm.cp.id"></cp-actions>\n </div>\n</div>\n<hr>\n<div class="row-fluid">\n <div ng-show="vm.cp.id" class="span2">\n <div ng-include="\'templates/cp_side_nav.html\'"></div>\n </div>\n <div ng-class="{span10: vm.cp.id, span12: !vm.cp.id}">\n <!-- TODO hide form on not found -->\n <form ng-submit="vm.saveContentProvider(vm.cp)">\n <fieldset>\n <div class="row-fluid">\n <div class="span6">\n <label>Name:</label>\n <input type="text" ng-model="vm.cp.humanReadableName" required/>\n </div>\n <div class="span6">\n <label class="checkbox">\n <input type="checkbox" ng-model="vm.cp.enabled" /> Enabled\n </label>\n </div>\n </div>\n <div class="row-fluid">\n <div class="span12">\n <label>Description</label>\n <textarea style="width: 100%" ng-model="vm.cp.description"></textarea>\n </div>\n </div>\n <div class="row-fluid">\n <div class="span12">\n <label>Service provider</label>\n <select required ng-model="vm.cp.serviceProvider" ng-options="sp.id as sp.humanReadableName for sp in vm.sp"></select>\n </div>\n </div>\n <div class="row-fluid">\n <div class="span12">\n <button class="btn btn-success">\n <span ng-show="vm.cp.id">Save</span>\n <span ng-show="!vm.cp.id">Create</span>\n </button>\n </div>\n </div>\n </fieldset>\n </form>\n <div class="alert" ng-show="vm.result" ng-class="{\'alert-success\': vm.result.status === 1,\'alert-error\': vm.result.status === 0}">\n {$ vm.result.msg $}\n </div>\n </div>\n</div>'),n.put("templates/cp_list.html",'<table class="table table-striped" ng-show="vm.contentProviderList.length > 0">\n <thead>\n <tr>\n <th>\n Name\n </th>\n <th>Description</th>\n <th>Status</th>\n <th></th>\n </tr>\n </thead>\n <tr ng-repeat="item in vm.contentProviderList">\n <td>\n <a href="#/contentProvider/{$ item.id $}">{$ item.humanReadableName $}</a>\n </td>\n <td>\n {$ item.description $}\n </td>\n <td>\n {$ item.enabled $}\n </td>\n <td class="text-right">\n <a ng-click="vm.deleteCp(item.id)" class="btn btn-danger"><i class="icon icon-remove"></i></a></td>\n </tr>\n</table>\n<div class="alert alert-error" ng-show="vm.contentProviderList.length == 0">\n No Content Provider defined\n</div>\n\n<div class="row">\n <div class="span12 text-right">\n <a class="btn btn-success"href="#/contentProvider/">Create</a>\n </div>\n</div>'),n.put("templates/cp_origin_server.html",'<div class="row-fluid">\n <div class="span6">\n <h1>{$ vm.cp.humanReadableName $}</h1>\n </div>\n <div class="span6 text-right">\n <cp-actions id="vm.cp.id"></cp-actions>\n </div>\n</div>\n<hr>\n<div class="row-fluid">\n <div class="span2">\n <div ng-include="\'templates/cp_side_nav.html\'"></div>\n </div>\n <div class="span10">\n <div ng-repeat="item in vm.cp_os" class="well">\n <div class="row-fluid">\n <div class="span4">\n {{item.humanReadableName}}\n </div>\n <div class="span6">\n <!-- TODO shoe the name instead that url -->\n {{item.defaultOriginServer}}\n </div>\n <div class="span2">\n <a ng-click="vm.removeOrigin(item)" class="btn btn-danger pull-right">\n <i class="icon icon-remove"></i>\n </a>\n </div>\n </div>\n </div>\n <hr>\n <form ng-submit="vm.addOrigin(vm.new_os)">\n <div class="row-fluid">\n <div class="span4">\n <label>Protocol</label>\n <select ng-model="vm.new_os.protocol" ng-options="k as v for (k,v) in vm.protocols" style="max-width: 100%;"></select>\n </div>\n <div class="span6">\n <label>Url</label>\n <input type="text" ng-model="vm.new_os.url" required>\n </div>\n <div class="span2 text-right">\n <button class="btn btn-success margin-wells">\n <i class="icon icon-plus"></i>\n </button>\n </div>\n </div>\n </form>\n <div class="alert" ng-show="vm.result" ng-class="{\'alert-success\': vm.result.status === 1,\'alert-error\': vm.result.status === 0}">\n {$ vm.result.msg $}\n </div>\n </div>\n</div>'),n.put("templates/cp_side_nav.html",'<ul class="nav nav-list">\n <li>\n <a class="btn" ng-class="{\'btn-primary\': vm.pageName == \'detail\'}" href="#/contentProvider/{$ vm.cp.id $}">Details</a>\n </li>\n <li>\n <a class="btn" ng-class="{\'btn-primary\': vm.pageName == \'cdn\'}" href="#/contentProvider/{$ vm.cp.id $}/cdn_prefix">Cdn Prexix</a>\n </li>\n <li>\n <a class="btn" ng-class="{\'btn-primary\': vm.pageName == \'server\'}" href="#/contentProvider/{$ vm.cp.id $}/origin_server">Origin Server</a>\n </li>\n <li>\n <a class="btn" ng-class="{\'btn-primary\': vm.pageName == \'user\'}" href="#/contentProvider/{$ vm.cp.id $}/users">Users</a>\n </li>\n</ul>'),n.put("templates/cp_user.html",'<div class="row-fluid">\n <div class="span6">\n <h1>{$ vm.cp.humanReadableName $}</h1>\n </div>\n <div class="span6 text-right">\n <cp-actions id="vm.cp.id"></cp-actions>\n </div>\n</div>\n<hr>\n<div class="row-fluid">\n <div class="span2">\n <div ng-include="\'templates/cp_side_nav.html\'"></div>\n </div>\n <div class="span10">\n <div ng-repeat="item in vm.cp.users" class="well">\n <div class="row-fluid">\n <div class="span3">\n {{item.firstname}}\n </div>\n <div class="span3">\n {{item.lastname}}\n </div>\n <div class="span4">\n {{item.email}}\n </div>\n <div class="span2">\n <a ng-click="vm.removeUserFromCp(item)" class="btn btn-danger pull-right">\n <i class="icon icon-remove"></i>\n </a>\n </div>\n </div>\n </div>\n <hr>\n <form ng-submit="vm.saveContentProvider(vm.cp)">\n <div class="row-fluid">\n <div class="span8">\n <label>Select user:</label>\n <select ng-model="vm.user" ng-options="u as u.username for u in vm.users" ng-change="vm.addUserToCp(vm.user)"></select>\n </div> \n <div class="span4 text-right">\n <button class="btn btn-success margin-wells">\n Save\n </button>\n </div>\n </div>\n </form>\n <div class="alert" ng-show="vm.result" ng-class="{\'alert-success\': vm.result.status === 1,\'alert-error\': vm.result.status === 0}">\n {$ vm.result.msg $}\n </div>\n </div>\n</div>'),n.put("templates/users-list.tpl.html",'<div class="row">\n <h1>Users List</h1>\n <p>This is only an example view.</p>\n</div>\n<div class="row">\n <div class="span4">Email</div>\n <div class="span4">First Name</div>\n <div class="span4">Last Name</div>\n</div> \n<div class="row" ng-repeat="user in vm.users">\n <div class="span4">{{user.email}}</div>\n <div class="span4">{{user.firstname}}</div>\n <div class="span4">{{user.lastname}}</div>\n</div> ')}]);
\ No newline at end of file
diff --git a/xos/templates/admin/dashboard/customize.html b/xos/templates/admin/dashboard/customize.html
index eb92b21..e9ef6d8 100644
--- a/xos/templates/admin/dashboard/customize.html
+++ b/xos/templates/admin/dashboard/customize.html
@@ -1,5 +1,8 @@
<div class="row-fluid">
<div class="span12 text-right">
+ <a href="core/dashboardview/" class="btn btn-default">
+ <i class="icon icon-pencil"></i> Manage
+ </a>
<a href="core/dashboardview/add/" class="btn btn-success">
<i class="icon icon-plus"></i> Add
</a>