diff --git a/guacamole/pom.xml b/guacamole/pom.xml
index ff35797ed..ff75a224e 100644
--- a/guacamole/pom.xml
+++ b/guacamole/pom.xml
@@ -137,7 +137,6 @@
lib/plugins/angular-translate.jslib/plugins/angular-translate-loader-static-files.jslib/plugins/angular-translate-interpolation-messageformat.js
- lib/plugins/modal.min.jslib/blob/blob.jslib/filesaver/filesaver.jslib/messageformat/messageformat.js
diff --git a/guacamole/src/main/webapp/app/manage/controllers/manageSessionsController.js b/guacamole/src/main/webapp/app/manage/controllers/manageSessionsController.js
index 17603e209..aa81a16ff 100644
--- a/guacamole/src/main/webapp/app/manage/controllers/manageSessionsController.js
+++ b/guacamole/src/main/webapp/app/manage/controllers/manageSessionsController.js
@@ -29,6 +29,7 @@ angular.module('manage').controller('manageSessionsController', ['$scope', '$inj
// Required types
var ActiveConnectionWrapper = $injector.get('ActiveConnectionWrapper');
var ConnectionGroup = $injector.get('ConnectionGroup');
+ var FilterPattern = $injector.get('FilterPattern');
var StableSort = $injector.get('StableSort');
// Required services
@@ -54,6 +55,20 @@ angular.module('manage').controller('manageSessionsController', ['$scope', '$inj
*/
$scope.wrappers = null;
+ /**
+ * The filter search string to use to restrict the displayed active sessions
+ *
+ * @type String
+ */
+ $scope.filterSearchString = null;
+
+ /**
+ * The pattern object to use when filtering active sessions.
+ *
+ * @type FilterPattern
+ */
+ $scope.filterPattern = new FilterPattern();
+
/**
* StableSort instance which maintains the sort order of the visible
* connection wrappers.
@@ -67,13 +82,6 @@ angular.module('manage').controller('manageSessionsController', ['$scope', '$inj
'name'
]);
- /**
- * The root connection group of the connection group hierarchy.
- *
- * @type ConnectionGroup
- */
- var rootGroup = null;
-
/**
* All active connections, if known, or null if active connections have not
* yet been loaded.
@@ -83,11 +91,12 @@ angular.module('manage').controller('manageSessionsController', ['$scope', '$inj
var activeConnections = null;
/**
- * Map of all visible connections by object identifier.
+ * Map of all visible connections by object identifier, or null if visible
+ * connections have not yet been loaded.
*
* @type Object.
*/
- var connections = {};
+ var connections = null;
/**
* Map of all currently-selected active connection wrappers by identifier.
@@ -118,7 +127,7 @@ angular.module('manage').controller('manageSessionsController', ['$scope', '$inj
* The connection group whose descendant connections should be added to
* the internal set of connections.
*/
- var addDescendantConnections = function addDescendantConnections(connectionGroup) {
+ var addDescendantConnections = function addDescendantConnections(connectionGroup) {
// Add all child connections
if (connectionGroup.childConnections)
@@ -168,8 +177,8 @@ angular.module('manage').controller('manageSessionsController', ['$scope', '$inj
.success(function connectionGroupReceived(retrievedRootGroup) {
// Load connections from retrieved group tree
- rootGroup = retrievedRootGroup;
- addDescendantConnections(rootGroup);
+ connections = {};
+ addDescendantConnections(retrievedRootGroup);
// Attempt to produce wrapped list of active connections
wrapActiveConnections();
@@ -351,5 +360,10 @@ angular.module('manage').controller('manageSessionsController', ['$scope', '$inj
delete selectedWrappers[wrapper.activeConnection.identifier];
};
+
+ // Recompile the filter pattern when changed
+ $scope.$watch('filterSearchString', function recompilePredicate(searchString) {
+ $scope.filterPattern.compile(searchString);
+ });
}]);
diff --git a/guacamole/src/main/webapp/app/manage/styles/sessions.css b/guacamole/src/main/webapp/app/manage/styles/sessions.css
index 30b486828..0a0fbd8e9 100644
--- a/guacamole/src/main/webapp/app/manage/styles/sessions.css
+++ b/guacamole/src/main/webapp/app/manage/styles/sessions.css
@@ -76,3 +76,12 @@
.manage table.session-list th.sort-primary.sort-descending:after {
background-image: url('images/arrows/up.png');
}
+
+.manage .sessions .filter{
+ background-image: url('images/magnifier.png');
+ background-repeat: no-repeat;
+ background-size: 1.75em;
+ padding-left: 1.75em;
+ width: 100%;
+ max-width: none;
+}
diff --git a/guacamole/src/main/webapp/app/manage/templates/manageSessions.html b/guacamole/src/main/webapp/app/manage/templates/manageSessions.html
index d2b29adc8..26fc52b6c 100644
--- a/guacamole/src/main/webapp/app/manage/templates/manageSessions.html
+++ b/guacamole/src/main/webapp/app/manage/templates/manageSessions.html
@@ -35,6 +35,10 @@ THE SOFTWARE.
+
+
+
+
@@ -78,7 +82,8 @@ THE SOFTWARE.
-
+
\ No newline at end of file
diff --git a/guacamole/src/main/webapp/app/manage/types/FilterPattern.js b/guacamole/src/main/webapp/app/manage/types/FilterPattern.js
new file mode 100644
index 000000000..2aaeddc2e
--- /dev/null
+++ b/guacamole/src/main/webapp/app/manage/types/FilterPattern.js
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 Glyptodon LLC
+ *
+ * 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.
+ */
+
+/**
+ * A service for defining the FilterPattern class.
+ */
+angular.module('manage').factory('FilterPattern', [
+ function defineFilterPattern() {
+
+ /**
+ * Object which handles compilation of filtering predicates as used by
+ * the Angular "filter" filter. Predicates are compiled from a user-
+ * specified search string.
+ *
+ * @constructor
+ */
+ var FilterPattern = function FilterPattern() {
+
+ /**
+ * Reference to this instance.
+ *
+ * @type FilterPattern
+ */
+ var filterPattern = this;
+
+ /**
+ * Filter predicate which simply matches everything. This function
+ * always returns true.
+ *
+ * @returns {Boolean}
+ * true.
+ */
+ var nullPredicate = function nullPredicate() {
+ return true;
+ };
+
+ /**
+ * The current filtering predicate.
+ *
+ * @type Function
+ */
+ this.predicate = nullPredicate;
+
+ /**
+ * Compiles the given pattern string, assigning the resulting filter
+ * predicate. The resulting predicate will accept only objects that
+ * match the given pattern.
+ *
+ * @param {String} pattern
+ * The pattern to compile.
+ */
+ this.compile = function compile(pattern) {
+
+ // If no pattern provided, everything matches
+ if (!pattern) {
+ filterPattern.predicate = nullPredicate;
+ return;
+ }
+
+ // Convert to lower case for case insensitive matching
+ pattern = pattern.toLowerCase();
+
+ // TODONT: Return predicate specific to a type of object this class should know nothing about
+ filterPattern.predicate = function oddlySpecificPredicate(wrapper) {
+
+ // Check to see if the search string matches the connection name
+ if (wrapper.name.toLowerCase().indexOf(pattern) !== -1)
+ return true;
+
+ // Check to see if the search string matches the username
+ if (wrapper.activeConnection.username.toLowerCase().indexOf(pattern) !== -1)
+ return true;
+
+ // Check to see if the search string matches the remote host
+ if (wrapper.activeConnection.remoteHost.toLowerCase().indexOf(pattern) !== -1)
+ return true;
+
+ return false;
+ };
+
+ };
+
+ };
+
+ return FilterPattern;
+
+}]);
\ No newline at end of file
diff --git a/guacamole/src/main/webapp/images/magnifier.png b/guacamole/src/main/webapp/images/magnifier.png
new file mode 100644
index 000000000..15261209e
Binary files /dev/null and b/guacamole/src/main/webapp/images/magnifier.png differ
diff --git a/guacamole/src/main/webapp/translations/en_US.json b/guacamole/src/main/webapp/translations/en_US.json
index 7348958d9..46876aa5b 100644
--- a/guacamole/src/main/webapp/translations/en_US.json
+++ b/guacamole/src/main/webapp/translations/en_US.json
@@ -243,6 +243,8 @@
"DIALOG_HEADER_CONFIRM_DELETE" : "Kill Sessions",
"DIALOG_HEADER_ERROR" : "Error",
+ "FIELD_PLACEHOLDER_FILTER" : "Filter",
+
"HELP_SESSIONS" : "All currently-active Guacamole sessions are listed here. If you wish to kill one or more sessions, check the box next to those sessions and click \"Kill Sessions\". Killing a session will immediately disconnect the user from the associated connection.",
"INFO_NO_SESSIONS" : "No active sessions",