You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jetspeed-dev@portals.apache.org by ta...@apache.org on 2015/02/28 00:34:00 UTC

svn commit: r1662855 [11/12] - in /portals/jetspeed-2/applications/j2-admin/trunk: ./ src/main/java/org/apache/jetspeed/jetapp/ src/main/java/org/apache/jetspeed/jetapp/dto/ src/main/webapp/WEB-INF/ src/main/webapp/jetapp/ src/main/webapp/jetapp/bower_...

Added: portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/BOILERPLATE_LICENSE.md
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/BOILERPLATE_LICENSE.md?rev=1662855&view=auto
==============================================================================
--- portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/BOILERPLATE_LICENSE.md (added)
+++ portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/BOILERPLATE_LICENSE.md Fri Feb 27 23:33:58 2015
@@ -0,0 +1,19 @@
+Copyright (c) HTML5 Boilerplate
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

Added: portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/BOOTSTRAP_LICENSE
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/BOOTSTRAP_LICENSE?rev=1662855&view=auto
==============================================================================
--- portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/BOOTSTRAP_LICENSE (added)
+++ portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/BOOTSTRAP_LICENSE Fri Feb 27 23:33:58 2015
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2011-2015 Twitter, Inc
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

Added: portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/JQUERY_MIT_LICENSE.txt
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/JQUERY_MIT_LICENSE.txt?rev=1662855&view=auto
==============================================================================
--- portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/JQUERY_MIT_LICENSE.txt (added)
+++ portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/JQUERY_MIT_LICENSE.txt Fri Feb 27 23:33:58 2015
@@ -0,0 +1,21 @@
+Copyright 2014 jQuery Foundation and other contributors
+http://jquery.com/
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Added: portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/LODASH_LICENSE
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/LODASH_LICENSE?rev=1662855&view=auto
==============================================================================
--- portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/LODASH_LICENSE (added)
+++ portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/LODASH_LICENSE Fri Feb 27 23:33:58 2015
@@ -0,0 +1,22 @@
+Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+Based on Underscore.js 1.7.0, copyright 2009-2015 Jeremy Ashkenas,
+DocumentCloud and Investigative Reporters & Editors <http://underscorejs.org/>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Added: portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/MIT_LICENSE
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/MIT_LICENSE?rev=1662855&view=auto
==============================================================================
--- portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/MIT_LICENSE (added)
+++ portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/MIT_LICENSE Fri Feb 27 23:33:58 2015
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2010-2015 Google, Inc. http://angularjs.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

Added: portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/MOMENT_LICENSE
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/MOMENT_LICENSE?rev=1662855&view=auto
==============================================================================
--- portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/MOMENT_LICENSE (added)
+++ portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/MOMENT_LICENSE Fri Feb 27 23:33:58 2015
@@ -0,0 +1,22 @@
+Copyright (c) 2011-2014 Tim Wood, Iskren Chernev, Moment.js contributors
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.

Added: portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/NG_GRID_LICENSE.md
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/NG_GRID_LICENSE.md?rev=1662855&view=auto
==============================================================================
--- portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/NG_GRID_LICENSE.md (added)
+++ portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/bower_licenses/NG_GRID_LICENSE.md Fri Feb 27 23:33:58 2015
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2012 the AngularUI Team, http://angular-ui.github.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

Added: portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/j2-admin-skin.css
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/j2-admin-skin.css?rev=1662855&view=auto
==============================================================================
--- portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/j2-admin-skin.css (added)
+++ portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/j2-admin-skin.css Fri Feb 27 23:33:58 2015
@@ -0,0 +1,3 @@
+@import url(styles/ng-grid.min.css);
+@import url(styles/app.css);
+@import url(styles/default.css);
\ No newline at end of file

Added: portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/PortletService.js
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/PortletService.js?rev=1662855&view=auto
==============================================================================
--- portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/PortletService.js (added)
+++ portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/PortletService.js Fri Feb 27 23:33:58 2015
@@ -0,0 +1,34 @@
+var PortletService = function ($http, $q, ServerService) {
+
+    var service = {
+
+        config: {
+            withCredentials: true
+        },
+
+        lookupPreferences: function (url) {
+            var self = this, deferred = $q.defer();
+            $http.get(url, service.config)
+                .success(function success(data, status, headers, config) {
+                    deferred.resolve(data, status);
+                })
+                .error(function error(data, status) {
+                    deferred.reject(data, status);
+                });
+            return deferred.promise;
+        },
+        storePreferences: function (url, prefs) {
+            var self = this, deferred = $q.defer();
+            $http.post(url, prefs, service.config)
+                .success(function success(data, status, headers, config) {
+                    deferred.resolve(data, status);
+                })
+                .error(function error(data, status) {
+                    deferred.reject(data, status);
+                });
+            return deferred.promise;
+        }
+
+    }
+    return service;
+}

Added: portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/RestApiService.js
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/RestApiService.js?rev=1662855&view=auto
==============================================================================
--- portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/RestApiService.js (added)
+++ portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/RestApiService.js Fri Feb 27 23:33:58 2015
@@ -0,0 +1,160 @@
+'use strict';
+
+/* Services */
+
+var RestService = function ($http, $q, ServerService) {
+
+    var service = {
+
+        profiles: [],
+
+        /**
+         * List Profiles via query. The query is specified as an object with the
+         * following fields;
+         *
+         * 'id' : matches profile id
+         * 'title' : contains within title
+         * 'concreteClass' : contains within class name
+         *
+         * Profiles are returned in ascending id order. All matches are
+         * case insensitive.
+         *
+         * @param queryObject optional query object, defaults to {}
+         * @param first optional first data item index, defaults to 0
+         * @param count optional count to return, defaults to user preference
+         * @returns promise rejected or resolved with a wrapped list of Profile objects.
+         */
+        listProfiles: function(queryObject, first, count) {
+            var deferred = $q.defer();
+            var self = this;
+            var url = ServerService.api('/profiler/list');
+            var config = ServerService.apiConfig();
+            config.params = {
+                "type" : "json"
+            };
+            $http.get(url, config)
+                .success(function success(data, status, headers, config) {
+                    deferred.resolve(data, status);
+                })
+                .error(function error(data, status) {
+                    if (status == 404) {
+                        deferred.resolve(data, status);
+                    }
+                    else {
+                        deferred.reject(data, status);
+                    }
+                });
+            return deferred.promise;
+        },
+
+        /**
+         * Lookup a HostIdentity by id or host names. Matches are case insensitive.
+         *
+         * @param id primary key profile id to look up by
+         * @returns promise rejected or resolved with a Profile object.
+         */
+        getProfile: function(id) {
+            var deferred = $q.defer();
+            var url = ServerService.api('/profiler/edit', encodeURIComponent(id));
+            $http.get(url, ServerService.apiConfig())
+                .success(function success(data, status) {
+                    deferred.resolve(data, status);
+                })
+                .error(function error(message, status) {
+                    deferred.reject(message, status);
+                }
+            );
+            return deferred.promise;
+        },
+
+        /**
+         * Delete Profiles
+         *
+         * @param profileIds array of profile ids to delete
+         * @returns promise rejected or resolved
+         */
+        deleteProfiles: function(profileIds) {
+            var deferred = $q.defer();
+            var httpConfig = {
+                method: 'DELETE',
+                url: ServerService.api('/profiler'),
+                headers: {'Content-Type': 'application/json'},
+                data: profileIds
+            };
+            _.merge(httpConfig, ServerService.apiConfig());
+            $http(httpConfig)
+                .success(function success(data, status) {
+                    if (!!data && (data.status === 200)) {
+                        deferred.resolve(undefined, status);
+                    } else {
+                        deferred.reject("Profiles not deleted.", status);
+                    }
+                })
+                .error(function error(message, status) {
+                    deferred.reject(message, status);
+                }
+            );
+            return deferred.promise;
+        },
+
+
+        /**
+         * Create or update Profile. Operation is considered a create if the
+         * profile id is unique and the id is undefined.
+         *
+         * @param profile the Profile record to create or update
+         * @returns promise rejected or resolved with entity string
+         */
+        createOrUpdateProfile: function(profile) {
+            var deferred = $q.defer();
+            var url = ServerService.api('/profiler/update');
+            var config = ServerService.apiConfig();
+            config.params = {
+                "type" : "json"
+            };
+            $http.post(url, profile, ServerService.apiConfig())
+                .success(function success(data, status) {
+                    resolveWithEntityOrRejectWithMessage(deferred, data, status);
+                })
+                .error(function error(message, status) {
+                    deferred.reject(message, status);
+                }
+            );
+            return deferred.promise;
+        }
+    };
+
+    /**
+     * Format Date into SQL string.
+     *
+     * @param date Date instance
+     * @returns formatted SQL string
+     */
+    function formatTimestamp(date) {
+        return date.getFullYear()+'-'+('0'+(date.getMonth()+1)).slice(-2)+'-'+('0'+date.getDate()).slice(-2)+' '+('0'+date.getHours()).slice(-2)+':'+('0'+date.getMinutes()).slice(-2)+':'+('0'+date.getSeconds()).slice(-2);
+    }
+
+    /**
+     * Resolve with entity or reject with message.
+     *
+     * @param deferred deferred prommise
+     * @param data results data
+     * @param status status
+     */
+    function resolveWithEntityOrRejectWithMessage(deferred, data, status) {
+        if (!!data && ((data.successful === 1) || (data.status == 200))) {
+            var entity = ((!!data && !!data.results && data.results.length) ? data.results[0].entity : undefined);
+            deferred.resolve(entity, status);
+        } else {
+            var message = ((!!data && !!data.results && data.results.length) ? data.results[0].message : undefined);
+            deferred.reject(message, status);
+        }
+    }
+
+    return service;
+};
+
+// Demonstrate how to register services
+// In this case it is a simple value service.
+angular.module('myApp.services', []).
+    value('version', '0.1');

Added: portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/ServerService.js
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/ServerService.js?rev=1662855&view=auto
==============================================================================
--- portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/ServerService.js (added)
+++ portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/ServerService.js Fri Feb 27 23:33:58 2015
@@ -0,0 +1,96 @@
+/* jshint indent:false, unused:false */
+/* jshint -W087 */
+/* global appConfig:true, _:true */
+'use strict';
+
+var ServerService = function ($cookies) {
+
+    var apiHttpConfig = {
+        // override this setting with request URL parsing
+        rootPath : "http://localhost:8080/jetspeed/services",
+        withCredentials: false,
+        withToken: false,
+        headers: {
+            'JETAPP-API-TOKEN': '6CB95F7FFA7B4B0ABF92216D822E4ECD',
+            'JETAPP-APP-NAME' : 'j2-admin'
+        }
+    }
+
+    var PATH_SEPARATOR = "/";
+    var PORT_SEPARATOR = ":";
+
+    function endsWith(str, suffix) {
+        return str.indexOf(suffix, str.length - suffix.length) !== -1;
+    }
+
+    function startsWith(str, prefix) {
+        return str.indexOf(prefix) === 0;
+    }
+
+    function getContextPath() {
+        return window.location.pathname.substring(0, window.location.pathname.indexOf("/",2));
+    }
+
+    function concatenatePaths(base, path) {
+        var result = "";
+        if (base === null) base = "";
+        if (path === null) path = "";
+        result = result + base;
+        if (endsWith(base, PATH_SEPARATOR)) {
+            if (startsWith(path, PATH_SEPARATOR)) {
+                result = result + path.substring(1);
+            }
+            else
+                result = result + path;
+        }
+        else {
+            if (startsWith(path, PATH_SEPARATOR) || startsWith(path, PORT_SEPARATOR))
+                result = result + path;
+            else {
+                result = result  + PATH_SEPARATOR;
+                result = result + path;
+            }
+        }
+        return result;
+    }
+
+
+    return {
+        api: function (endPoint, pathParam, pathParam2, pathParam3, pathParam4) {
+            var url = window.location.origin + getContextPath() + '/services' + endPoint;
+            if (apiHttpConfig.withToken) {
+                var token = $cookies.JetAppToken;
+                if (!_.isUndefined(token)) {
+                    apiHttpConfig.headers['JETAPP-API-TOKEN'] = token;
+                }
+                var root = angular.fromJson($cookies.JetAppRestService);
+                var url = "";
+                if (!_.isUndefined(root)) {
+                    apiHttpConfig.headers.rootPath = root;
+                    url = concatenatePaths(root, endPoint);
+                }
+                else {
+                    url = window.location.origin + '/jetspeed/services' + endPoint;
+                }
+            }
+            if (pathParam !== undefined) {
+                url += '/' + pathParam;
+            }
+            if (pathParam2 !== undefined) {
+                url += '/' + pathParam2;
+            }
+            if (pathParam3 !== undefined) {
+                url += '/' + pathParam3;
+            }
+            if (pathParam4 !== undefined) {
+                url += '/' + pathParam4;
+            }
+            return url;
+        },
+
+        apiConfig: function () {
+            return _.clone(apiHttpConfig);
+        }
+    }
+};
+

Added: portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/TextMessages.js
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/TextMessages.js?rev=1662855&view=auto
==============================================================================
--- portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/TextMessages.js (added)
+++ portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/TextMessages.js Fri Feb 27 23:33:58 2015
@@ -0,0 +1,35 @@
+var TextMessages = function () {
+
+    var service = {
+
+        messages_en: {
+            notFound: 'Message not found',
+            serverFailure:
+                'We\'re sorry, but we had trouble contacting our Monitor server. Please contact support for further assistance. Message: %s status: %s',
+            serverSuccess: 'Server is up and running',
+            serverFailed: 'Bad status. Status: %s',
+            prefsUpdated: 'Your preferences have been updated.'
+        },
+
+        get: function (key, etc) {
+            // TODO: localize
+            var message = service.messages_en[key];
+            if (message === undefined)
+                return service.messages_en['notFound'];
+            if (arguments.length <= 1)
+                return message;
+            var args = Array.prototype.slice.call(arguments, 1);
+            args.unshift(message);
+            return service.sprintf.apply(service, args);
+        },
+
+        sprintf: function(format, etc) {
+            var arg = arguments;
+            var i = 1;
+            return format.replace(/%((%)|s)/g, function (m) { return m[2] || arg[i++] })
+        }
+
+    }
+
+    return service;
+}

Added: portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/controllers.js
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/controllers.js?rev=1662855&view=auto
==============================================================================
--- portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/controllers.js (added)
+++ portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/controllers.js Fri Feb 27 23:33:58 2015
@@ -0,0 +1,439 @@
+'use strict';
+
+/* Controllers: */
+angular.module('j2admin.controllers', [])
+    .controller('ProfilerController', function ($scope, $q, $interval, $log, $modal, DataService, TextMessages, PortletService) {
+        $scope.columnDefs = [
+            {
+                field: 'id', displayName: 'ID', width: '20%',
+                cellTemplate: '<div ng-click="editProfile(row.rowIndex)"><div class="ngCellText">{{row.getProperty(col.field)}}</div></div>'
+            },
+            {
+                field: 'title', displayName: 'Profile Name', width: '50%',
+                cellTemplate: '<div ng-click="editProfile(row.rowIndex)"><div class="ngCellText">{{row.getProperty(col.field)}}</div></div>'
+            },
+            {
+                field: 'concreteClass', displayName: 'Class', width: '30%',
+                cellTemplate: '<div ng-click="editProfile(row.rowIndex)"><div class="ngCellText">{{row.getProperty(col.field)}}</div></div>'
+            }
+        ];
+
+        $scope.filters = {
+            term: ''
+        };
+
+        var searchTimeout = null;
+        $scope.perPage = 10;
+        $scope.page = 0;
+        $scope.maxPage = 0;
+        $scope.currentIndex = -1;
+
+        $scope.options = {
+            showSelectionCheckbox: true,
+            selectWithCheckboxOnly: true,
+            selectedItems: [],
+            data: 'profiles',
+            columnDefs: 'columnDefs',
+            plugins: [new ngGridFlexibleHeightPlugin()]
+        };
+        $scope.initialized = false;
+
+        $scope.alerts = [];
+
+        $scope.closeAlert = function (index) {
+            $scope.alerts = [];
+        };
+
+        $scope.addFailureAlert = function (errorMessage, status) {
+            $scope.alerts.length = 0;
+            var statusMsg = (status === undefined) ? "none" : status;
+            $scope.alerts.push({type: 'danger', msg: TextMessages.get('serverFailure', errorMessage, statusMsg)});
+        };
+
+        // ---- init function
+        $scope.init = function (readResourceURL) {
+
+            $scope.readResourceURL = readResourceURL;
+            PortletService.lookupPreferences(readResourceURL).then(
+                function success(prefs, status) {
+                    $scope.prefs = prefs;
+                    $scope.perPage = prefs.rowsPerPage;
+                    // $scope.columnDefs[1].displayName = (!!~prefs.service.indexOf('cpu')) ? "CPU %" : "Memory %";
+                    $scope.getData();
+
+                    if ($scope.initialized == false) {
+                        //$interval(refresh, $scope.prefs.refreshSeconds * 1000);
+                    }
+
+                    $scope.initialized = true;
+                },
+                function error(msg, status) {
+                    console.log(msg);
+                    $scope.addFailureAlert(msg, status);
+                }
+            );
+        }; // end init
+
+        // -- retrieve a page of profiles
+        $scope.getData = function () {
+            var filters = {};
+
+            if ($scope.filters.term.length) {
+                filters.id = $scope.filters.term;
+                filters.title = $scope.filters.term;
+                filters.concreteClass = $scope.filters.term;
+            }
+
+            DataService.listProfiles(filters, $scope.page * $scope.perPage, $scope.perPage).then(
+                function success(profiles, status) {
+                    $scope.profilesAll = profiles.records;
+                    $scope.maxPage = Math.floor($scope.profilesAll.length / $scope.perPage);
+                    $scope.getPage();
+                },
+                function error(msg, status) {
+                    console.log(msg);
+                    $scope.addFailureAlert(msg, status);
+                }
+            )
+        }; // end getPage
+
+        $scope.getPage = function () {
+            var intermediary = _.filter($scope.profilesAll, function(profile) {
+                return ((profile.id.indexOf($scope.filters.term) !== -1) ||
+                (profile.title.indexOf($scope.filters.term) !== -1) ||
+                (profile.concreteClass.indexOf($scope.filters.term) !== -1))
+            });
+
+            $scope.profiles = intermediary.slice($scope.page * $scope.perPage, ($scope.page + 1) * $scope.perPage);
+
+            if (!$scope.$$phase) {
+                $scope.$apply();
+            }
+        };
+
+        // -- get previous page
+        $scope.getNextPage = function () {
+            $scope.page++;
+
+            $scope.getPage();
+        };
+
+        // -- get next page
+        $scope.getPrevPage = function () {
+            $scope.page--;
+
+            if($scope.page < 0) {
+                $scope.page = 0;
+            }
+
+            $scope.getPage();
+        };
+
+        // -- perform search
+        $scope.search = function() {
+            if(searchTimeout) {
+                clearTimeout(searchTimeout);
+            }
+
+            searchTimeout = setTimeout(function() {
+                    $scope.page = 0;
+                    $scope.getPage();
+                },
+                500);
+        };
+
+        var activeDialog = null;
+
+        // -- add or edit profile
+        $scope.editProfile = function(index) {
+            $scope.currentIndex = index;
+
+            if(activeDialog) {
+                return;
+            }
+
+            var modalInstance = $modal.open({
+                // TODO: get context
+                templateUrl: '/j2-admin/jetapp/views/modals/profile-detail.html',
+                controller: ProfileDetailsInstanceController,
+                backdrop: false,
+                resolve: {
+                    DataService: function() { return DataService; },
+                    profile: function() { return (typeof index === 'undefined') ? null : $scope.profiles[index]; },
+                    parentScope: function() { return $scope; },
+                    existing: function() { return (typeof index !== 'undefined'); },
+                    existingIds: function() { return _.pluck($scope.profilesAll, "id"); }
+                }
+            });
+
+            activeDialog = modalInstance;
+
+            modalInstance.result.then(function () {
+                activeDialog = null;
+                $scope.getData();
+            }, function () {
+                activeDialog = null;
+                $log.info('Modal dismissed at: ' + new Date());
+            });
+        };
+
+        $scope.deleteHosts = function() {
+            var modalInstance = $modal.open({
+                // TODO: get context
+                templateUrl: '/j2-admin/jetapp/views/modals/profiles-delete.html',
+                controller: DeleteProfilesInstanceController,
+                resolve: {
+                    DataService: function() { return DataService; },
+                    selectedItems: function() { return $scope.options.selectedItems; }
+                }
+            });
+
+            modalInstance.result.then(function () {
+                $scope.options.selectedItems = [];
+                $scope.getData();
+            }, function () {
+                $log.info('Modal dismissed at: ' + new Date());
+            });
+        };
+    }
+)
+    .controller('ProfilerEditController', function ($scope, DataService, PortletService) {
+        $scope.master = {};
+
+        $scope.init = function (readResourceURL, writeResourceURL, renderURL) {
+            $scope.readResourceURL = readResourceURL;
+            $scope.writeResourceURL = writeResourceURL;
+            $scope.renderURL = renderURL;
+            PortletService.lookupPreferences(readResourceURL).then(
+                function success(prefs, status) {
+                    $scope.prefs = prefs;
+                    $scope.master = angular.copy(prefs);
+                    //$scope.profileEditForm.$setPristine();
+                },
+                function error(msg, status) {
+                    console.log(msg);
+                    $scope.addFailureAlert(msg, status);
+                }
+            )
+        };
+
+        $scope.update = function (prefs) {
+            PortletService.storePreferences($scope.writeResourceURL, prefs).then(
+                function success(result, status) {
+                    //window.location = $scope.renderURL;
+                },
+                function error(msg, status) {
+                    console.log(msg);
+                    $scope.addFailureAlert(msg, status);
+                }
+            )
+        };
+
+        $scope.reset = function () {
+            $scope.prefs = angular.copy($scope.master);
+        };
+
+        $scope.clear = function () {
+            $scope.master = {};
+            $scope.prefs = {};
+            $scope.profileEditForm.$setPristine();
+        };
+
+        $scope.isUnchanged = function (prefs) {
+            return angular.equals(prefs, $scope.master);
+        };
+
+        $scope.alerts = [
+        ];
+
+        $scope.closeAlert = function (index) {
+            $scope.alerts = [];
+        };
+
+        $scope.addFailureAlert = function (errorMessage, status) {
+            $scope.alerts.length = 0;
+            var statusMsg = (status === undefined) ? "none" : status;
+            $scope.alerts.push({type: 'danger', msg: TextMessages.get('serverFailure', errorMessage, statusMsg) });
+        };
+
+        $scope.addSuccessAlert = function () {
+            $scope.alerts.length = 0;
+            $scope.alerts.push({type: 'success', msg: TextMessages.get('PrefsUpdated') });
+        };
+
+        $scope.reset();
+    });
+
+var CriteriaDetailsInstanceController = function ($scope, $modalInstance, criteria) {
+
+    $scope.criteria = criteria || {
+        name: '',
+        value: '',
+        resolverType: '',
+        fallback: -1,
+        order: 0
+    };
+
+    $scope.add = function() {
+        $modalInstance.close($scope.criteria);
+    };
+
+    $scope.close = function() {
+        $modalInstance.dismiss();
+    };
+};
+CriteriaDetailsInstanceController.$inject = ['$scope', '$modalInstance', 'criteria'];
+
+/**
+ * Profile Instance Controller for modal dialog of editing of profile form
+ *
+ * @param $scope
+ * @param $modalInstance
+ * @param DataService
+ * @param profile
+ * @param parentScope
+ * @constructor
+ */
+var ProfileDetailsInstanceController = function ($scope, $modal, $modalInstance, $log, DataService, profile, parentScope, existing, existingIds) {
+
+    $scope.profile = profile || {
+        id: '',
+        title: '',
+        concreteClass: '',
+        criteria: []
+    };
+
+    $scope.existing = existing;
+    $scope.existingIds = existingIds;
+
+    if (profile != null) {
+        DataService.getProfile(profile.id).then(
+            function success(result) {
+                $scope.profile = result;
+            },
+            function error(message) {
+                console.log(message);
+                $scope.addFailureAlert(message);
+            });
+    }
+
+    parentScope.$watch('currentIndex', function(newIndex) {
+        if(typeof(newIndex) != 'undefined') {
+            $scope.profile = parentScope.profiles[newIndex];
+        }
+    });
+
+    $scope.isUniqueId = function() {
+        return ($scope.existingIds.indexOf($scope.profile.id) === -1);
+    };
+
+    $scope.isValidTitle = function() {
+        var hostNameRegEx = /^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$/;
+        return true;
+        //return ipaddr.isValid($scope.hostIdentity.hostName) || hostNameRegEx.test($scope.hostIdentity.hostName);
+    };
+
+    $scope.alerts = [];
+
+    $scope.hasAlias = function(alias) {
+        return ($scope.hostIdentity.hostNames.indexOf(alias) !== -1);
+    };
+
+    //$scope.addAlias = function(alias) {
+    //    $scope.hostIdentity.hostNames.push('');
+    //};
+    //
+    //$scope.removeAlias = function(index) {
+    //    $scope.hostIdentity.hostNames.splice(index, 1);
+    //};
+
+    $scope.add = function() {
+        //var names = $scope.hostIdentity.hostNames;
+        //
+        //for(var i = 0; i < names.length; i++) {
+        //    if(!names[i].length) {
+        //        names.splice(i, 1);
+        //        i--;
+        //    }
+        //}
+
+        DataService.createOrUpdateProfile($scope.profile).then(
+            function success(entity) {
+                $modalInstance.close();
+            },
+            function error(message) {
+                if(message.indexOf('ConstraintViolationException') != -1) {
+                    message = 'This profile is likely to exist already - please choose another name.';
+                }
+
+                console.log(message);
+                $scope.addFailureAlert(message);
+            });
+    };
+
+    $scope.addCriteria = function(index) {
+        var modalInstance = $modal.open({
+            // TODO: get context
+            templateUrl: '/j2-admin/jetapp/views/modals/criteria-detail.html',
+            controller: CriteriaDetailsInstanceController,
+            backdrop: false,
+            resolve: {
+                criteria: function() { return $scope.profile.criteria[index] || {}; }
+            }
+        });
+
+        modalInstance.result.then(function (retCriteria) {
+            if(typeof index !== 'undefined') {
+                $scope.profile.criteria[index] = retCriteria;
+            }
+            else {
+                $scope.profile.criteria.push(retCriteria);
+            }
+        }, function () {
+            $log.info('Modal dismissed at: ' + new Date());
+        });
+    };
+
+    $scope.removeCriteria = function(index) {
+        $scope.profile.criteria.splice(index, 1);
+    };
+
+    $scope.close = function() {
+        $modalInstance.dismiss();
+    };
+
+    $scope.addFailureAlert = function(message) {
+        $scope.alerts.length = 0;
+        $scope.alerts.push({type: 'danger', msg: message});
+    };
+
+    $scope.closeAlert = function(index) {
+        $scope.alerts.splice(index, 1);
+    };
+};
+ProfileDetailsInstanceController.$inject = ['$scope', '$modal', '$modalInstance', '$log', 'DataService', 'profile', 'parentScope', 'existing', 'existingIds'];
+
+var DeleteProfilesInstanceController = function ($scope, $modalInstance, DataService, selectedItems) {
+
+    $scope.deleteItems = function() {
+        var ids = [];
+
+        for(var i = 0, iLimit = selectedItems.length; i < iLimit; i++) {
+            ids.push(selectedItems[i].id);
+        }
+
+        DataService.deleteProfiles(ids).then(
+            function success(data) {
+                $modalInstance.close();
+            },
+            function failures(message, status) {
+                $scope.addFailureAlert(message);
+            });
+    };
+
+    $scope.close = function() {
+        $modalInstance.dismiss();
+    };
+};
+DeleteProfilesInstanceController.$inject = ['$scope', '$modalInstance', 'DataService', 'selectedItems'];
+

Added: portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/directives.js
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/directives.js?rev=1662855&view=auto
==============================================================================
--- portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/directives.js (added)
+++ portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/directives.js Fri Feb 27 23:33:58 2015
@@ -0,0 +1,272 @@
+'use strict';
+
+/* Directives: */
+angular.module('j2admin.directives', [])
+    .directive('gwpStatusIcon', ['$timeout', function ($timeout) {
+        return {
+            restrict: 'A',
+            link : function(scope, element, attrs){
+                var self = $(element);
+
+                $timeout(function() {
+                    if(self.hasClass('status-yellow')) {
+                        self.append('<div class="glyphicon glyphicon-warning-sign"></div>');
+                    }
+                });
+            }
+        }
+    }])
+    .directive('gwpStatusHover', ['DataService', function (DataService) {
+        return {
+            restrict: 'A',
+            link : function(scope, element, attrs) {
+                var self = $(element),
+                    item = scope.item,
+                    body = $(document.body);
+
+                self.hover(function() {
+                        $('#infohover').remove();
+
+                        var position = self.offset();
+
+                        DataService.getEventsByHost(item.hostName)
+                            .then(function(data) {
+                                var events = data,
+                                    highAlerts = [1, 2, 3], avgAlerts = [1, 2, 3], lowAlerts = [1, 2, 3];
+
+                                for(var i = 0, iLimit = events.length; i < iLimit; i++) {
+                                    var event = events[i];
+
+                                    switch(event.monitorStatus) {
+                                        case 'SCHEDULED CRITICAL':
+                                        case 'SCHEDULED DOWN':
+                                        case 'UNREACHABLE':
+                                        case 'UNSCHEDULED DOWN':
+                                        case 'UNSCHEDULED CRITICAL':
+                                        case 'ACKNOWLEDGEMENT (CRITICAL)':
+                                        case 'ACKNOWLEDGEMENT (DOWN)':
+                                        case 'ACKNOWLEDGEMENT (UNREACHABLE)':
+                                        case 'CRITICAL':
+                                        case 'DOWN':
+                                            highAlerts.push(event);
+                                            break;
+
+                                        case 'WARNING':
+                                        case 'ACKNOWLEDGEMENT (WARNING)':
+                                        case 'ACKNOWLEDGEMENT (MAINTENANCE)':
+                                        case 'MAINTENANCE':
+                                            avgAlerts.push(event);
+                                            break;
+
+                                        case 'UP':
+                                        case 'OK':
+                                        case 'ACKNOWLEDGEMENT (UP)':
+                                        case 'ACKNOWLEDGEMENT (OK)':
+                                        case 'UNKNOWN':
+                                        case 'PENDING':
+                                        case 'ACKNOWLEDGEMENT (UNKNOWN)':
+                                        case 'ACKNOWLEDGEMENT (PENDING)':
+                                        case 'SUSPENDED':
+                                        default:
+                                            lowAlerts.push(event);
+                                            break;
+                                    }
+                                }
+
+                                var alertHtml = '';
+
+                                if(highAlerts.length || avgAlerts.length || lowAlerts.length) {
+                                    alertHtml = '<hr />';
+
+                                    if(highAlerts.length) {
+                                        alertHtml += '<h4><img class="icon icon-alert" src="/portal-groundwork-base/app/images/status/host-red.gif" />Critical alerts (' + highAlerts.length + ')</h4>';
+                                        /*
+                                         for(i = 0, iLimit = highAlerts.length; i < iLimit; i++) {
+                                         alertHtml += '<p>' + highAlerts[i].textMessage + '</p>';
+                                         }
+                                         */
+                                        if(avgAlerts.length || lowAlerts.length) {
+                                            alertHtml += '<hr />';
+                                        }
+                                    }
+
+                                    if(avgAlerts.length) {
+                                        alertHtml += '<h4><img class="icon" src="/portal-groundwork-base/app/images/status/host-yellow.gif" />Warning alerts (' + avgAlerts.length + ')</h4>';
+                                        /*
+                                         for(i = 0, iLimit = avgAlerts.length; i < iLimit; i++) {
+                                         alertHtml += '<p>' + avgAlerts[i].textMessage + '</p>';
+                                         }
+                                         */
+                                        if(lowAlerts.length) {
+                                            alertHtml += '<hr />';
+                                        }
+                                    }
+
+                                    if(lowAlerts.length) {
+                                        alertHtml += '<h4><img class="icon" src="/portal-groundwork-base/app/images/status/host-green.gif" />Info alerts (' + lowAlerts.length + ')</h4>';
+                                        /*
+                                         for(i = 0, iLimit = lowAlerts.length; i < iLimit; i++) {
+                                         alertHtml += '<p>' + lowAlerts[i].textMessage + '</p>';
+                                         }
+                                         */
+                                    }
+                                }
+
+                                $('#infohover').remove();
+
+                                var bodyWidth = body.width();
+                                var infoHover = $('<div id="infohover"><h3>' + item.hostName + '</h3><p class="timestamp">' + moment(item.lastCheckTime).format('dddd, MMMM Do YYYY, h:mm:ss a') + '</p>' + alertHtml + '</div>');
+                                body.append(infoHover);
+
+                                var left = position.left + self.outerWidth()  / 1.5;
+
+                                if((left + infoHover.width()) > bodyWidth) {
+                                    left = position.left + self.outerWidth() / 3 - infoHover.width();
+                                }
+
+                                infoHover.css({
+                                    top:  position.top  + self.outerHeight() / 1.5,
+                                    left: left
+                                });
+                            },
+                            function() {
+                            });
+                    },
+                    function() {
+                        $('#infohover').remove();
+                    });
+                    
+                    self.closest('tab-content').hover(function() {}, function() {
+                        $('#infohover').remove();
+                    });
+            }
+        }
+    }])
+    .directive('gwpEventHover', ['DataService', function (DataService) {
+        return {
+            restrict: 'A',
+            link : function(scope, element, attrs){
+                var self = $(element),
+                    event = scope.event,
+                    body = $(document.body);
+
+                self.hover(function() {
+                        $('#eventhover').remove();
+
+                        var position = self.offset();
+
+                        var eventHover = $('<div id="eventhover"><p>Updated ' + event.lastDate.format('dddd, MMMM Do YYYY, h:mm:ss a') + ', click to view this alert.</p><p>' + event.event.textMessage + '</p></div>');
+
+                        body.append(eventHover);
+
+                        eventHover.css({
+                            top:  position.top  + self.outerHeight(),
+                            left: position.left + 100
+                        });
+                    },
+                    function() {
+                        $('#eventhover').remove();
+                    });
+            }
+        }
+    }])
+    .directive('gwpDatepicker', function () {
+        return {
+            restrict: 'A',
+            link : function(scope, element, attrs){
+                var self = $(element), path = attrs.gwpDatepicker.split('.');
+
+                self.Zebra_DatePicker({format: 'Y-m-d', onSelect: function(e) {
+                    var variable = scope;
+
+                    for(var i = 0, iLimit = path.length; i < iLimit; i++) {
+                        variable = variable[path[i]];
+                    }
+
+                    variable = e;
+                    scope.getPage();
+                }});
+            }
+        }
+    })
+    .directive('gwpSlidingDialog', function () {
+        return {
+            restrict: 'A',
+            link : function(scope, element, attrs){
+                var self = $(element), dialog = self.closest('.modal');
+                dialog.addClass('slide-from-right');
+
+                var baseGrid = $('#grid.base-grid');
+                if(baseGrid.length) {
+                    var top = baseGrid.offset().top;
+
+                    dialog.css('margin-top', top + 'px');
+                }
+            }
+        }
+    })
+    .directive('gwpAutofocus', function () {
+        return {
+            restrict: 'A',
+            link : function(scope, element, attrs){
+                var self = $(element), dialog = self.closest('.modal');
+
+                dialog.on('shown.bs.modal', function () {
+                    setTimeout(function() {
+                        element.focus();
+                    },
+                    100);
+                });
+
+                setTimeout(function() {
+                    element.focus();
+                },
+                100);
+            }
+        }
+    })
+    .directive('gwpNoSpaces', function () {
+        return {
+            restrict: 'A',
+            link : function(scope, element, attrs){
+                var self = $(element);
+
+                self.on('keypress', function(e) {
+                    if(e.which === 32) {
+                        if(e.preventDefault) {
+                            e.preventDefault();
+                        }
+
+                        return false;
+                    }
+                });
+
+                self.on('paste', function () {
+                    setTimeout(function () {
+                        var text = self.val().replace(/\s/g, "");
+
+                        self.val(text);
+                    },
+                    100);
+                });
+            }
+        }
+    })
+    .directive('gwpFitGrid', ['$timeout', function ($timeout) {
+        return {
+            restrict: 'A',
+            link : function(scope, element, attrs){
+                var container = $(element);
+
+                $timeout(function() {
+                    var nav = container.find('.audit-nav-container'),
+                        grid = container.find('.panel-grid'),
+                        viewport = grid.find('.ngViewport');
+
+                    grid.css({height: (container.height() - nav.height()) + 'px'});
+                    viewport.css({height: (container.height() - nav.height() - grid.find('.ngHeaderContainer').height()) + 'px'});
+                });
+            }
+        }
+    }]);
+

Added: portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/filters.js
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/filters.js?rev=1662855&view=auto
==============================================================================
--- portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/filters.js (added)
+++ portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/scripts/filters.js Fri Feb 27 23:33:58 2015
@@ -0,0 +1,10 @@
+'use strict';
+
+/* Filters */
+
+angular.module('j2admin.filters', []).
+  filter('interpolate', ['version', function(version) {
+    return function(text) {
+      return String(text).replace(/\%VERSION\%/mg, version);
+    };
+  }]);

Added: portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/styles/app.css
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/styles/app.css?rev=1662855&view=auto
==============================================================================
--- portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/styles/app.css (added)
+++ portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/styles/app.css Fri Feb 27 23:33:58 2015
@@ -0,0 +1,293 @@
+/* custom inclusion of right, left and below tabs */
+a.ItemIcon.DefaultPageIcon {
+    color: black !important;
+    font-family: Helvetica, Arial, sans-serif;
+    font-size: 11px;
+}
+
+.UINavigationPortlet .UITab a.TabIcon {
+    color: black ;
+    text-decoration: none ;
+}
+
+.UINavigationPortlet .NormalNavigationTab a.TabIcon {
+    color: #fff;
+}
+
+.TabIcon {
+    font-size: 11px !important;
+    font-family: sans-serif !important;
+}
+.FL {
+    font-size: 11px !important;
+    font-family: sans-serif !important;
+}
+.Selected {
+    font-size: 11px !important;
+    font-family: sans-serif !important;
+}
+
+.tabs-below > .nav-tabs,
+.tabs-right > .nav-tabs,
+.tabs-left > .nav-tabs {
+    border-bottom: 0;
+}
+
+.tab-content > .tab-pane,
+.pill-content > .pill-pane {
+    display: none;
+}
+
+.tab-content > .active,
+.pill-content > .active {
+    display: block;
+}
+
+.tabs-below > .nav-tabs {
+    border-top: 1px solid #ddd;
+}
+
+.tabs-below > .nav-tabs > li {
+    margin-top: -1px;
+    margin-bottom: 0;
+}
+
+.tabs-below > .nav-tabs > li > a {
+    -webkit-border-radius: 0 0 4px 4px;
+    -moz-border-radius: 0 0 4px 4px;
+    border-radius: 0 0 4px 4px;
+}
+
+.tabs-below > .nav-tabs > li > a:hover,
+.tabs-below > .nav-tabs > li > a:focus {
+    border-top-color: #ddd;
+    border-bottom-color: transparent;
+}
+
+.tabs-below > .nav-tabs > .active > a,
+.tabs-below > .nav-tabs > .active > a:hover,
+.tabs-below > .nav-tabs > .active > a:focus {
+    border-color: transparent #ddd #ddd #ddd;
+}
+
+.tab-icon {
+    max-height: 2em;
+    margin-right: 1.5em;
+}
+
+.tab-name {
+    margin-top: 1em;
+}
+
+.tab-pane {
+    border-left: 1px solid #ddd;
+    border-right: 1px solid #ddd;
+    border-bottom: 1px solid #ddd;
+    padding: 1em;
+    height: 500px;
+    max-height: 500px;
+    overflow-x: hidden;
+    overflow-y: auto
+text-align: center;
+}
+
+.icon-list {
+    list-style-type: none;
+    margin: 0;
+    padding: 0;
+}
+
+.icon-list:after {
+    clear: both;
+}
+
+.icon-list .icon-list-item {
+    float: left;
+    position: relative;
+    margin: 0 0 4px 0;
+    width: 72px;
+    height: 72px;
+    text-align: center;
+    padding: 8px;
+}
+
+.icon-list .icon-list-item .status {
+    position: absolute;
+    top: 0px;
+    right: 3px;
+}
+
+.icon-list .icon-list-item .status-red {
+    color: red;
+}
+
+.icon-list .icon-list-item .status-yellow {
+    color: #7F6A00;
+}
+
+.icon-list .icon-list-item div.img-container {
+    padding: 10px;
+    max-width: 100px;
+    border: 1px solid lightgrey;
+}
+
+.icon-list .icon-list-item div.img-container img {
+    max-width: 100%;
+}
+
+.icon-list .icon-list-item p.name {
+    margin-top: 1px;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    font-size: 7pt;
+}
+
+.no-margin {
+    margin: 0;
+}
+
+.no-padding {
+    padding: 0 !important;
+}
+
+.audit-nav-container form {
+    padding: 0;
+}
+
+.panel.no-border {
+    border: 0;
+}
+
+.Zebra_DatePicker_Icon_Wrapper {
+    float: none !important;
+}
+
+#audit-next[disabled] {
+    color: #999;
+}
+
+#infohover {
+    position: absolute;
+    top: 0;
+    left: 0;
+    padding: .5em;
+    background: white;
+    border: 1px solid lightgrey;
+    width: 300px;
+    min-height: 100px;
+    max-height: 500px;
+    overflow-x: hidden;
+    overflow-y: auto;
+    text-align: left;
+    z-index: 1;
+}
+
+#infohover h3 {
+    padding-top: 0;
+    margin-top: 0;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    overflow: hidden;
+    width: 270px;
+    font-size: 1.6em;
+    display: block;
+    text-decoration: none !important;
+}
+
+#infohover .timestamp {
+    font-size: 1.2em;
+}
+
+#infohover h4 {
+    font-size: 1em;
+}
+
+#infohover h4 .icon {
+    position: relative;
+    top: -1px;
+    margin-right: .7em;
+}
+
+#infohover h4 .icon.icon-alert {
+    top: -3px;
+}
+
+#infohover hr {
+    padding: 0;
+    margin: 1em;
+    color: grey;
+    border-top: 1px solid grey;
+}
+
+.alert {
+    color: red;
+    padding-bottom: 0;
+    margin-bottom: 0;
+    text-shadow: 0 0 0;
+    box-shadow: none;
+}
+
+table.filter-table, table.filter-table-2 {
+    margin: .5em .25em 1em .25em;
+}
+
+table.filter-table td {
+    padding: .5em 1em;
+}
+
+table.filter-table td label, table.filter-table-2 td label {
+    margin-bottom: 3px;
+}
+
+table.filter-table td input, table.filter-table-2 td input {
+    width: 100%;
+    padding: 5px;
+    height: 25px;
+}
+
+table.filter-table td .btn, table.filter-table-2 td .btn {
+    padding: 2px 5px;
+    font-size: 1.2em;
+}
+
+.audit-nav-container {
+    position: relative;
+}
+
+.audit-nav-top {
+    position: absolute;
+    bottom: 20px;
+    right: 10px;
+}
+
+input#host-identities-search {
+    padding: 7px;
+    height: 26px;
+}
+
+input.error {
+    color: red;
+    background-color: #FFE9E8;
+    border-color: red;
+}
+
+.margin-bottom10 {
+    margin-bottom: 10px;
+}
+
+.modal.fade.slide-from-right {
+    margin: 0;
+}
+
+.modal.fade.slide-from-right:not(.in) .modal-dialog {
+    -webkit-transform: translate3d(25%, 0, 0);
+    transform: translate3d(25%, 0, 0);
+}
+
+.modal.fade.slide-from-right.in .modal-dialog {
+    margin: 0px 10% 0px auto;
+}
+.ngViewport {
+    min-height: 50px;
+}
\ No newline at end of file

Added: portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/styles/default.css
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/styles/default.css?rev=1662855&view=auto
==============================================================================
--- portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/styles/default.css (added)
+++ portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/styles/default.css Fri Feb 27 23:33:58 2015
@@ -0,0 +1,102 @@
+/*
+
+    Zebra_DatePicker: a lightweight jQuery date picker plugin
+
+    Default theme
+
+    copyright (c) 2011 - 2014 Stefan Gabos
+    http://stefangabos.ro/jquery/zebra-datepicker/
+
+*/
+
+.Zebra_DatePicker *,
+.Zebra_DatePicker *:after,
+.Zebra_DatePicker *:before  { -moz-box-sizing: content-box !important; -webkit-box-sizing: content-box !important; box-sizing: content-box !important }
+
+.Zebra_DatePicker           { position: absolute; background: #666; border: 3px solid #666; z-index: 100; font-family: Tahoma, Arial, Helvetica, sans-serif; font-size: 13px; }
+
+.Zebra_DatePicker *         { margin: 0; padding: 0; color: #000; background: transparent; border: none }
+
+/* = GLOBALS
+----------------------------------------------------------------------------------------------------------------------*/
+.Zebra_DatePicker table                      { border-collapse: collapse; border-spacing: 0; width: auto; table-layout: auto; }
+
+.Zebra_DatePicker td,
+.Zebra_DatePicker th                         { text-align: center; padding: 5px 0 }
+
+.Zebra_DatePicker td                         { cursor: pointer }
+
+.Zebra_DatePicker .dp_daypicker,
+.Zebra_DatePicker .dp_monthpicker,
+.Zebra_DatePicker .dp_yearpicker             { margin-top: 3px }
+
+.Zebra_DatePicker .dp_daypicker td,
+.Zebra_DatePicker .dp_daypicker th,
+.Zebra_DatePicker .dp_monthpicker td,
+.Zebra_DatePicker .dp_yearpicker td         { background: #E8E8E8; width: 30px; border: 1px solid #7BACD2 }
+
+.Zebra_DatePicker,
+.Zebra_DatePicker .dp_header .dp_hover,
+.Zebra_DatePicker .dp_footer .dp_hover { -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px }
+
+/* = VISIBLE/HIDDEN STATES (USE TRANSITIONS FOR EFFECTS)
+----------------------------------------------------------------------------------------------------------------------*/
+.Zebra_DatePicker.dp_visible               { display: block; visibility: visible; filter: alpha(opacity=100); -khtml-opacity: 1; -moz-opacity: 1; opacity: 1; transition: opacity 0.2s ease-in-out }
+.Zebra_DatePicker.dp_hidden                { display: none; visibility: hidden; filter: alpha(opacity=0); -khtml-opacity: 0; -moz-opacity: 0; opacity: 0 }
+
+/* = HEADER
+----------------------------------------------------------------------------------------------------------------------*/
+.Zebra_DatePicker .dp_header td             { color: #FFF }
+
+.Zebra_DatePicker .dp_header .dp_previous,
+.Zebra_DatePicker .dp_header .dp_next       { width: 30px }
+
+.Zebra_DatePicker .dp_header .dp_caption    { font-weight: bold }
+.Zebra_DatePicker .dp_header .dp_hover      { background: #222; color: #FFF }
+
+/* = DATEPICKER
+----------------------------------------------------------------------------------------------------------------------*/
+.Zebra_DatePicker .dp_daypicker th              { background: #FFCC33 }
+.Zebra_DatePicker td.dp_not_in_month            { background: #F3F3F3; color: #CDCDCD; cursor: default }
+.Zebra_DatePicker td.dp_not_in_month_selectable { background: #F3F3F3; color: #CDCDCD; cursor: pointer }
+.Zebra_DatePicker td.dp_weekend                 { background: #D8D8D8 }
+.Zebra_DatePicker td.dp_weekend_disabled        { color: #CCC; cursor: default }
+.Zebra_DatePicker td.dp_selected                { background: #5A4B4B; color: #FFF !important }
+.Zebra_DatePicker td.dp_week_number             { background: #FFCC33; color: #555; cursor: text; font-style: italic }
+
+/* = MONTHPICKER
+----------------------------------------------------------------------------------------------------------------------*/
+.Zebra_DatePicker .dp_monthpicker td    { width: 33% }
+
+/* = YEARPICKER
+----------------------------------------------------------------------------------------------------------------------*/
+.Zebra_DatePicker .dp_yearpicker td     { width: 33% }
+
+/* = FOOTER
+----------------------------------------------------------------------------------------------------------------------*/
+.Zebra_DatePicker .dp_footer            { margin-top: 3px }
+.Zebra_DatePicker .dp_footer .dp_hover  { background: #222; color: #FFF }
+
+/* = SELECT CURRENT DAY
+----------------------------------------------------------------------------------------------------------------------*/
+.Zebra_DatePicker .dp_today { color: #FFF; padding: 3px }
+
+/* = CLEAR DATE
+----------------------------------------------------------------------------------------------------------------------*/
+.Zebra_DatePicker .dp_clear { color: #FFF; padding: 3px }
+
+/* = SOME MORE GLOBALS (MUST BE LAST IN ORDER TO OVERWRITE PREVIOUS PROPERTIES)
+----------------------------------------------------------------------------------------------------------------------*/
+.Zebra_DatePicker td.dp_current             { color: #C40000 }
+.Zebra_DatePicker td.dp_disabled_current    { color: #E38585 }
+.Zebra_DatePicker td.dp_disabled            { background: #F3F3F3; color: #CDCDCD; cursor: default }
+.Zebra_DatePicker td.dp_hover               { background: #482424; color: #FFF }
+
+/* = ICON
+----------------------------------------------------------------------------------------------------------------------*/
+button.Zebra_DatePicker_Icon                { display: block; position: absolute; width: 16px; height: 16px; background: url('calendar.png') no-repeat left top; text-indent: -9000px; border: none; cursor: pointer; padding: 0; line-height: 0; vertical-align: top }
+button.Zebra_DatePicker_Icon_Disabled       { background-image: url('calendar-disabled.png') }
+
+/* don't set vertical margins! */
+button.Zebra_DatePicker_Icon                { margin: 0 0 0 3px }
+button.Zebra_DatePicker_Icon_Inside         { margin: 0 3px 0 0 }
\ No newline at end of file

Added: portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/styles/ng-grid.min.css
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/styles/ng-grid.min.css?rev=1662855&view=auto
==============================================================================
--- portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/styles/ng-grid.min.css (added)
+++ portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/styles/ng-grid.min.css Fri Feb 27 23:33:58 2015
@@ -0,0 +1 @@
+.ngGrid{background-color:#fdfdfd}.ngGrid input[type="checkbox"]{margin:0;padding:0}.ngGrid input{vertical-align:top}.ngGrid.unselectable{-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-o-user-select:none;user-select:none}.ngViewport{overflow:auto;min-height:20px}.ngViewport:focus{outline:0}.ngCanvas{position:relative}.ngVerticalBar{position:absolute;right:0;width:0}.ngVerticalBarVisible{width:1px;background-color:#d4d4d4}#testDataLength{position:absolute;top:0;right:0;z-index:-100000}.ngHeaderContainer{position:relative;overflow:hidden;font-weight:bold;background-color:inherit}.ngHeaderCell{position:absolute;top:0;bottom:0;background-color:inherit}.ngHeaderCell.pinned{z-index:1}.ngHeaderSortColumn{position:absolute;overflow:hidden}.ngTopPanel{position:relative;z-index:1;background-color:#eaeaea;border-bottom:1px solid #d4d4d4}.ngSortButtonDown{position:absolute;top:3px;left:0;right:0;margin-left:auto;margin-right:auto;border-color:gray transparent;border-styl
 e:solid;border-width:0 5px 5px 5px;height:0;width:0}.ngNoSort{cursor:default}.ngHeaderButton{position:absolute;right:2px;top:8px;-moz-border-radius:50%;-webkit-border-radius:50%;border-radius:50%;width:14px;height:14px;z-index:1;background-color:#9fbbb4;cursor:pointer}.ngSortButtonUp{position:absolute;top:3px;left:0;right:0;margin-left:auto;margin-right:auto;border-color:gray transparent;border-style:solid;border-width:5px 5px 0 5px;height:0;width:0}.ngHeaderScroller{position:absolute;background-color:inherit}.ngSortPriority{position:absolute;top:-5px;left:1px;font-size:6pt;font-weight:bold}.ngHeaderGrip{cursor:col-resize;width:10px;right:-5px;top:0;height:100%;position:absolute;background-color:transparent}.ngHeaderText{padding:5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden}.ngHeaderButtonArrow{position:absolute;top:4px;left:3px;width:0;
 height:0;border-style:solid;border-width:6.5px 4.5px 0 4.5px;border-color:#4d4d4d transparent transparent transparent}.ngPinnedIcon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTAw9HKhAAAAmElEQVQoU33PQapBURjA8UtkwJuaWYGSgfQWYBMvczPmTCzAAGVuaA228BZhRCkDGSmE31FucuRfvzq3vr5zT/JSjSU7DsypEPXDkDVn2hSIytJhw4kWGaLCxgHh2gt/RBuLzNhz5caWPjnSqqw4EraFfwznf8qklWjwy4IRTerkiQoPGtPl40OehcEJvcfXl8LglLfBJLkDcMgbgHlHhK8AAAAASUVORK5CYII=);background-repeat:no-repeat;position:absolute;right:5px;top:5px;height:10px;width:10px}.ngUnPinnedIcon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTAw9HKhAAAAlElEQVQoU33PPQrCQBRF4fFnI2KfZVi5ARvdgo1l6mwmkCJVOgluwd5OwUoDtnoOxAei8cLXTN7cvEl/skCNDCMPfsUPO5zQwOHIDEvYtMURHe6wOVLgigvOePRyeDkyR4ln7wZ//7XfFBu8B2
 3+aDJjrHGAwza7hjtHJvDmHg7b7Bru7AMjK7Rw2ObBVHDY5oGk9AKQNB2zy8MBTgAAAABJRU5ErkJggg==);background-repeat:no-repeat;position:absolute;height:10px;width:10px;right:5px;top:5px}.ngColMenu{right:2px;padding:5px;top:25px;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;background-color:#bdd0cb;position:absolute;border:2px solid #d4d4d4;z-index:1}.ngColListCheckbox{position:relative;right:3px;top:4px}.ngColList{list-style-type:none;margin-top:2px;margin-left:8px}.ngColListItem{white-space:nowrap}.ngMenuText{position:relative;top:2px;left:2px}.ngGroupPanel{background-color:#eaeaea;overflow:hidden;border-bottom:1px solid #d4d4d4}.ngGroupPanelDescription{margin-top:5px;margin-left:5px}.ngGroupList{list-style-type:none;margin:0;padding:0}.ngAggHeader{position:absolute;border:0}.ngGroupElement{float:left;height:100%;width:100%}.ngGroupIcon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAANCAYAAACZ3F9/AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADs
 MAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAEFJREFUKFNjoAhISkr+h2J5JDZODNXGwGBsbPwfhIGAA8bGh6HaGBiAGhxAGJmND4M1gQCSM0adCsVQbcPcqQwMALWDGyDvWPefAAAAAElFTkSuQmCC);background-repeat:no-repeat;height:15px;width:15px;position:absolute;right:-2px;top:2px}.ngGroupedByIcon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAANCAYAAACZ3F9/AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAElJREFUKFNjoAhISkr+R8LyaHwMDNXGwGBsbPwfhoGAA5mPDUO1oWpE52PDYE0gALTFAYbR+dgwWBMIoPlh1I9ADNU2NPzIwAAAFQYI9E4OLvEAAAAASUVORK5CYII=);background-repeat:no-repeat;height:15px;width:15px;position:absolute;right:-2px;top:2px}.ngGroupName{background-color:#fdfdfd;border:1px solid #d4d4d4;padding:3px 10px;float:left;margin-left:0;margin-top:2px;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;font-weight:bold}.ngGroupArrow{width:0;height:0;border-top:6px solid transparent;border-bottom:6
 px solid transparent;border-left:6px solid black;margin-top:10px;margin-left:5px;margin-right:5px;float:right}.ngGroupingNumber{position:absolute;right:-10px;top:-2px}.ngAggArrowCollapsed{position:absolute;left:8px;bottom:10px;width:0;height:0;border-style:solid;border-width:5px 0 5px 8.7px;border-color:transparent transparent transparent #000}.ngGroupItem{float:left}.ngGroupItem:first-child{margin-left:2px}.ngRemoveGroup{width:5px;-moz-opacity:.4;opacity:.4;margin-top:-1px;margin-left:5px}.ngRemoveGroup:hover{color:black;text-decoration:none;cursor:pointer;-moz-opacity:.7;opacity:.7}.ngAggArrowExpanded{position:absolute;left:8px;bottom:10px;width:0;height:0;border-style:solid;border-width:0 0 9px 9px;border-color:transparent transparent #000 transparent}.ngAggregate{position:absolute;background-color:#c9dde1;border-bottom:1px solid beige;overflow:hidden;top:0;bottom:0;right:-1px;left:0}.ngAggregateText{position:absolute;left:27px;top:5px;line-height:20px;white-space:nowrap}.ngRow{p
 osition:absolute;border-bottom:1px solid #d4d4d4}.ngRow.odd{background-color:#fdfdfd}.ngRow.even{background-color:#f3f3f3}.ngRow.selected{background-color:#c9dde1}.ngCell{overflow:hidden;position:absolute;top:0;bottom:0;background-color:inherit}.ngCell.pinned{z-index:1}.ngCellText{padding:5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden}.ngSelectionCell{margin-top:9px;margin-left:6px}.ngSelectionHeader{position:absolute;top:11px;left:6px}.ngCellElement:focus{outline:0;background-color:#b3c4c7}.ngRow.canSelect{cursor:pointer}.ngSelectionCheckbox{margin-top:9px;margin-left:6px}.ngFooterPanel{background-color:#eaeaea;padding:0;border-top:1px solid #d4d4d4;position:relative}.nglabel{display:block;float:left;font-weight:bold;padding-right:5px}.ngTotalSelectContainer{float:left;margin:5px;margin-top:7px}.ngFooterSelectedItems{padding:2px}.ngFoote
 rTotalItems.ngnoMultiSelect{padding:0!important}.ngGridMaxPagesNumber{vertical-align:middle}.ngPagerFirstBar{width:10px;border-left:2px solid #4d4d4d;margin-top:-6px;height:12px;margin-left:-3px}.ngPagerButton{height:25px;min-width:26px}.ngPagerFirstTriangle{width:0;height:0;border-style:solid;border-width:5px 8.7px 5px 0;border-color:transparent #4d4d4d transparent transparent;margin-left:2px}.ngPagerNextTriangle{margin-left:1px}.ngPagerPrevTriangle{margin-left:0}.ngPagerLastTriangle{width:0;height:0;border-style:solid;border-width:5px 0 5px 8.7px;border-color:transparent transparent transparent #4d4d4d;margin-left:-1px}.ngPagerLastBar{width:10px;border-left:2px solid #4d4d4d;margin-top:-6px;height:12px;margin-left:1px}.ngFooterTotalItems{padding:2px}
\ No newline at end of file

Added: portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/views/modals/criteria-detail.html
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/views/modals/criteria-detail.html?rev=1662855&view=auto
==============================================================================
--- portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/views/modals/criteria-detail.html (added)
+++ portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/views/modals/criteria-detail.html Fri Feb 27 23:33:58 2015
@@ -0,0 +1,80 @@
+<div class="modal-header" gwp-sliding-dialog>
+    <button type="button" class="close" aria-hidden="true" ng-click="close()">&times;</button>
+    <h4 class="modal-title" ng-show="!criteria.name">New Criteria<span ng-show="criteria.name.length">: {{criteria.name}}</span></h4>
+    <h4 class="modal-title" ng-show="criteria.name">Criteria Detail: <span>{{criteria.name}}</span></h4>
+</div>
+<form role="form" novalidate class="form-horizontal css-form">
+    <div class="modal-body">
+        <div class="form-group">
+            <label for="criteria-name" class="col-sm-2 control-label">Name</label>
+            <div class="col-md-10 col-sm-10">
+                <input type="text" id="criteria-name" class="form-control" ng-model="criteria.name" gwp-autofocus gwp-no-spaces />
+                <span id="helpBlockID" class="help-block">Enter a unique name for this criteria</span>
+            </div>
+        </div>
+
+        <div class="form-group">
+            <label for="criteria-value" class="col-sm-2 control-label">Value</label>
+            <div class="col-md-10 col-sm-10">
+                <input type="text" id="criteria-value" class="form-control" ng-model="criteria.value" />
+            </div>
+        </div>
+
+        <div class="form-group">
+            <label for="criteria-resolver" class="col-sm-2 control-label">Resolver Type</label>
+            <div class="col-md-10 col-sm-10">
+                <select id="criteria-resolver" class="form-control" ng-model="criteria.resolverType">
+                    <option value="request">request</option>
+                    <option value="session">session</option>
+                    <option value="request.session">request.session</option>
+                    <option value="hard.coded">hard.coded</option>
+                    <option value="group.role.user">group.role.user</option>
+                    <option value="user">user</option>
+                    <option value="group">group</option>
+                    <option value="role">role</option>
+                    <option value="mediatype">mediatype</option>
+                    <option value="country">country</option>
+                    <option value="language">language</option>
+                    <option value="roles">roles</option>
+                    <option value="path">path</option>
+                    <option value="page">page</option>
+                    <option value="path.session">path.session</option>
+                    <option value="user.attribute">user.attribute</option>
+                    <option value="navigation">navigation</option>
+                    <option value="ip">ip</option>
+                    <option value="hostname">hostname</option>
+                </select>
+            </div>
+        </div>
+
+        <div class="form-group">
+            <label for="criteria-fallback" class="col-sm-2 control-label">Fallback Type</label>
+            <div class="col-md-10 col-sm-10">
+                <select id="criteria-fallback" class="form-control" ng-model="criteria.fallback">
+                    <option value="1">Continue</option>
+                    <option value="0">Stop</option>
+                    <option value="2">Loop</option>
+                </select>
+            </div>
+        </div>
+
+        <div class="form-group">
+            <label for="criteria-order" class="col-sm-2 control-label">Order</label>
+            <div class="col-md-10 col-sm-10">
+                <input type="number" id="criteria-order" class="form-control" ng-model="criteria.order" />
+            </div>
+        </div>
+
+        <div class="form-group">
+            <div class="col-md-10 col-sm-10 padding-left0">
+                <alert ng-repeat="alert in alerts" type="alert.type" close="closeAlert($index)"><strong>{{alert.msg}}</strong></alert>
+            </div>
+            <br />
+        </div>
+    </div>
+    <div class="modal-footer">
+        <button class="btn btn-default" ng-click="close()">Cancel</button>
+        <input type="submit" class="btn btn-primary" ng-click="add()" ng-disabled="!criteria.name.length || !criteria.resolverType.length || (criteria.fallback === -1)" ng-show="!criteria.name" value="Add"/>
+        <input type="submit" class="btn btn-primary" ng-click="add()" ng-disabled="!criteria.name.length || !criteria.resolverType.length || (criteria.fallback === -1)" ng-show="criteria.name" value="Update"/>
+    </div>
+</form>

Added: portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/views/modals/profile-detail.html
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/views/modals/profile-detail.html?rev=1662855&view=auto
==============================================================================
--- portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/views/modals/profile-detail.html (added)
+++ portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/views/modals/profile-detail.html Fri Feb 27 23:33:58 2015
@@ -0,0 +1,72 @@
+<div class="modal-header" gwp-sliding-dialog>
+    <button type="button" class="close" aria-hidden="true" ng-click="close()">&times;</button>
+    <h4 class="modal-title" ng-show="!profile.id">New Profile<span ng-show="profile.id.length">: {{profile.id}}</span></h4>
+    <h4 class="modal-title" ng-show="profile.id">Profile Detail: <span>{{profile.id}}</span></h4>
+</div>
+<form role="form" novalidate class="form-horizontal css-form">
+    <div class="modal-body">
+        <div class="form-group">
+            <label for="profile-id" class="col-sm-2 control-label">Profile ID</label>
+            <div class="col-md-10 col-sm-10">
+                <input type="text" id="profile-id" class="form-control" placeholder="new-profile-id" ng-model="profile.id" ng-class="{error: !isValidTitle()}" ng-disabled="existing" gwp-autofocus gwp-no-spaces />
+                <span id="helpBlockID" class="help-block" ng-show="!existing">Enter a unique ID for this Profile</span>
+            </div>
+        </div>
+
+        <div class="form-group">
+            <label for="profile-title" class="col-sm-2 control-label">Description</label>
+            <div class="col-md-10 col-sm-10">
+                <input type="text" id="profile-title" class="form-control" placeholder="new-profile-title" ng-model="profile.title" ng-class="{error: !isValidTitle()}" />
+                <span id="helpBlockTitle" class="help-block">Enter a description of this Profile</span>
+            </div>
+        </div>
+        <div class="form-group">
+            <label for="profile-class" class="col-sm-2 control-label">Java Class</label>
+            <div class="col-md-10 col-sm-10">
+                <select id="profile-class" class="form-control" placeholder="new-profile-class" ng-required ng-model="profile.concreteClass">
+                    <option value="org.apache.jetspeed.profiler.rules.impl.StandardProfilingRule">Standard</option>
+                    <option value="org.apache.jetspeed.profiler.rules.impl.RoleFallbackProfilingRule">Fallback</option>
+                </select>
+            </div>
+        </div>
+        <div class="form-group">
+            <label for="profile-class" class="col-sm-2 control-label">Criteria<br /><button type="button" class="btn btn-success btn-xs" ng-click="addCriteria()">add</button></label>
+            <div class="col-md-10 col-sm-10">
+                <span ng-show="!profile.criteria.length"><br />None</span>
+                <table ng-show="profile.criteria.length" class="table">
+                    <thead>
+                    <tr>
+                        <th>Name</th>
+                        <th>Value</th>
+                        <th>Resolver Type</th>
+                        <th>Fallback Type</th>
+                        <th>Order</th>
+                        <th></th>
+                    </tr>
+                    </thead>
+                    <tbody>
+                    <tr ng-repeat="criteria in profile.criteria" ng-click="addCriteria($index)">
+                        <td ng-bind="criteria.name"></td>
+                        <td ng-bind="criteria.value"></td>
+                        <td ng-bind="criteria.resolverType"></td>
+                        <td ng-bind="criteria.fallback"></td>
+                        <td ng-bind="criteria.order"></td>
+                        <td><button type="button" class="btn btn-danger btn-sm" ng-click="removeCriteria($index)">-</button></td>
+                    </tr>
+                    </tbody>
+                </table>
+            </div>
+        </div>
+        <div class="form-group">
+            <div class="col-md-10 col-sm-10 padding-left0">
+                <alert ng-repeat="alert in alerts" type="alert.type" close="closeAlert($index)"><strong>{{alert.msg}}</strong></alert>
+            </div>
+            <br />
+        </div>
+    </div>
+    <div class="modal-footer">
+        <button class="btn btn-default" ng-click="close()">Cancel</button>
+        <input type="submit" class="btn btn-primary" ng-click="add()" ng-disabled="!profile.id.length || !profile.concreteClass.length || !isValidTitle() || !isUniqueId()" ng-show="!existing" value="Add"/>
+        <input type="submit" class="btn btn-primary" ng-click="add()" ng-disabled="!profile.id.length || !profile.concreteClass.length || !isValidTitle()" ng-show="existing" value="Update"/>
+    </div>
+</form>

Added: portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/views/modals/profiles-delete.html
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/views/modals/profiles-delete.html?rev=1662855&view=auto
==============================================================================
--- portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/views/modals/profiles-delete.html (added)
+++ portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/jetapp/views/modals/profiles-delete.html Fri Feb 27 23:33:58 2015
@@ -0,0 +1,20 @@
+<div class="modal-header">
+    <button type="button" class="close" aria-hidden="true" ng-click="close()">&times;</button>
+    <h4 class="modal-title">Delete Profiles</h4>
+</div>
+<form role="form" novalidate class="css-form">
+    <div class="modal-body">
+        <p class="text-danger">Are you sure you want to delete all the selected profiles?</p>
+        <p class="text-danger">This cannot be undone.</p>
+        <div class="form-group">
+            <div>
+                <alert ng-repeat="alert in alerts" type="alert.type" close="closeAlert($index)"><strong>{{alert.msg}}</strong></alert>
+            </div>
+            <br />
+        </div>
+    </div>
+    <div class="modal-footer">
+        <button class="btn btn-default" ng-click="close()">Cancel</button>
+        <button type="submit" class="btn btn-primary" ng-click="deleteItems()">Delete</button>
+    </div>
+</form>
\ No newline at end of file



---------------------------------------------------------------------
To unsubscribe, e-mail: jetspeed-dev-unsubscribe@portals.apache.org
For additional commands, e-mail: jetspeed-dev-help@portals.apache.org