From 90185508cd24cbc837cba546cad8fca22b8fa124 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Fri, 11 Apr 2014 10:41:42 -0400
Subject: [PATCH] Added breadcrumb to TPS UI.

The TPS UI has been modified to use Backbone.Router to assign a
unique path for each page. This way the browser's Back button will
work properly and the page can be bookmarked.

A home page has been added for the UI. Currently it provide links
to all available pages. In the future it might be changed to
display more useful information.

A breadcrumb has been added to the top of each page to provide
links back to the home page.

Some new font files have been added from PatternFly library.

The EntryWithPropertiesPage has been renamed to ConfigEntryPage.
The Navigation class is no longer used so it has been removed.

Ticket #959
---
 base/server/share/webapps/pki/css/pki-ui.css       |   5 +
 .../webapps/pki/font/OpenSans-Light-webfont.woff   | Bin 0 -> 13972 bytes
 .../pki/font/glyphicons-halflings-regular.woff     | Bin 0 -> 23320 bytes
 base/server/share/webapps/pki/js/pki-ui.js         | 119 +++----
 base/tps-tomcat/shared/webapps/tps/js/activity.js  |  24 +-
 base/tps-tomcat/shared/webapps/tps/js/audit.js     |  82 +++--
 .../shared/webapps/tps/js/authenticator.js         |  25 +-
 base/tps-tomcat/shared/webapps/tps/js/cert.js      |  24 +-
 base/tps-tomcat/shared/webapps/tps/js/config.js    |   2 +-
 .../tps-tomcat/shared/webapps/tps/js/connection.js |  25 +-
 base/tps-tomcat/shared/webapps/tps/js/group.js     |  36 +-
 .../shared/webapps/tps/js/profile-mapping.js       |  25 +-
 base/tps-tomcat/shared/webapps/tps/js/profile.js   |  25 +-
 base/tps-tomcat/shared/webapps/tps/js/selftest.js  |  24 +-
 base/tps-tomcat/shared/webapps/tps/js/token.js     |  64 ++--
 base/tps-tomcat/shared/webapps/tps/js/tps.js       |  90 +++--
 base/tps-tomcat/shared/webapps/tps/js/user.js      |  36 +-
 .../shared/webapps/tps/ui/activities.html          |   7 +-
 .../tps-tomcat/shared/webapps/tps/ui/activity.html |   8 +-
 base/tps-tomcat/shared/webapps/tps/ui/audit.html   |   4 +
 .../shared/webapps/tps/ui/authenticator.html       |   7 +-
 .../shared/webapps/tps/ui/authenticators.html      |   6 +-
 base/tps-tomcat/shared/webapps/tps/ui/cert.html    |   8 +-
 base/tps-tomcat/shared/webapps/tps/ui/certs.html   |   7 +-
 base/tps-tomcat/shared/webapps/tps/ui/config.html  |   6 +-
 .../shared/webapps/tps/ui/connection.html          |   7 +-
 .../shared/webapps/tps/ui/connections.html         |   7 +-
 base/tps-tomcat/shared/webapps/tps/ui/group.html   |   7 +-
 base/tps-tomcat/shared/webapps/tps/ui/groups.html  |   7 +-
 base/tps-tomcat/shared/webapps/tps/ui/home.html    |  58 ++++
 base/tps-tomcat/shared/webapps/tps/ui/index.html   | 361 ++++++++++++++++-----
 .../shared/webapps/tps/ui/profile-mapping.html     |   7 +-
 .../shared/webapps/tps/ui/profile-mappings.html    |   7 +-
 base/tps-tomcat/shared/webapps/tps/ui/profile.html |   7 +-
 .../tps-tomcat/shared/webapps/tps/ui/profiles.html |   7 +-
 .../tps-tomcat/shared/webapps/tps/ui/selftest.html |   7 +-
 .../shared/webapps/tps/ui/selftests.html           |   7 +-
 base/tps-tomcat/shared/webapps/tps/ui/token.html   |   7 +-
 base/tps-tomcat/shared/webapps/tps/ui/tokens.html  |   9 +-
 base/tps-tomcat/shared/webapps/tps/ui/user.html    |   7 +-
 base/tps-tomcat/shared/webapps/tps/ui/users.html   |   7 +-
 41 files changed, 677 insertions(+), 501 deletions(-)
 create mode 100755 base/server/share/webapps/pki/font/OpenSans-Light-webfont.woff
 create mode 100755 base/server/share/webapps/pki/font/glyphicons-halflings-regular.woff
 create mode 100644 base/tps-tomcat/shared/webapps/tps/ui/home.html

diff --git a/base/server/share/webapps/pki/css/pki-ui.css b/base/server/share/webapps/pki/css/pki-ui.css
index 36210154be7b78b652a234ba2ead30d96f5d1727..73d28770416ca21478a7e607e364da37412f6ac6 100644
--- a/base/server/share/webapps/pki/css/pki-ui.css
+++ b/base/server/share/webapps/pki/css/pki-ui.css
@@ -29,6 +29,11 @@
   margin-bottom: 10px;
 }
 
+.pki-header .breadcrumb {
+  padding: 0;
+  margin-bottom: 5px;
+}
+
 .pki-title {
   font-family: "Open Sans",sans-serif;
   font-size: 25px;
diff --git a/base/server/share/webapps/pki/font/OpenSans-Light-webfont.woff b/base/server/share/webapps/pki/font/OpenSans-Light-webfont.woff
new file mode 100755
index 0000000000000000000000000000000000000000..99514d1a8ab477afc4b434c0f575318e04c2433a
GIT binary patch
diff --git a/base/server/share/webapps/pki/font/glyphicons-halflings-regular.woff b/base/server/share/webapps/pki/font/glyphicons-halflings-regular.woff
new file mode 100755
index 0000000000000000000000000000000000000000..8c54182aa5d4d1ab3c9171976b615c1dcb1dc187
GIT binary patch
diff --git a/base/server/share/webapps/pki/js/pki-ui.js b/base/server/share/webapps/pki/js/pki-ui.js
index 0800887cbc9faa16833a42d9425aa4c749812576..df6812bf6052dd909347493b0ff640d740614866 100644
--- a/base/server/share/webapps/pki/js/pki-ui.js
+++ b/base/server/share/webapps/pki/js/pki-ui.js
@@ -19,6 +19,36 @@
  * @author Endi S. Dewata
  */
 
+var PKI = {
+    substitute: function(content, map) {
+
+        var newContent = "";
+
+        // substitute ${attribute} with attribute value
+        var pattern = /\${([^}]*)}/;
+
+        while (content.length) {
+            // search for ${attribute} pattern
+            var index = content.search(pattern);
+            if (index < 0) {
+                newContent += content;
+                break;
+            }
+
+            var name = RegExp.$1;
+            var value = map[name];
+
+            // replace pattern occurrence with attribute value
+            newContent += content.substring(0, index) + (value === undefined ? "" : value);
+
+            // process the remaining content
+            content = content.substring(index + name.length + 3);
+        }
+
+        return newContent;
+    }
+};
+
 var Model = Backbone.Model.extend({
     parseResponse: function(response) {
         return response;
@@ -143,57 +173,6 @@ var Page = Backbone.View.extend({
     }
 });
 
-var Navigation = Backbone.View.extend({
-    initialize: function(options) {
-        var self = this;
-        Navigation.__super__.initialize.call(self, options);
-        self.pages = options.pages || {};
-        self.homePage = options.homePage;
-
-        $("li", self.$el).each(function(index) {
-            var li = $(this);
-            var link = $("a", li);
-            var url = link.attr("href");
-            link.click(function(e) {
-                if (url == "#logout") {
-                    if (options.logout) {
-                        options.logout.call(self);
-                    }
-
-                } else if (url.charAt(0) == "#" && url.length > 1) {
-                    // get page name
-                    var name = url.substring(1);
-                    self.load(name);
-                }
-                e.preventDefault();
-            });
-        });
-    },
-    page: function(name, page) {
-        var self = this;
-        self.pages[name] = page;
-    },
-    load: function(name) {
-        var self = this;
-
-        var page = self.pages[name];
-        if (!page) {
-            new ErrorDialog({
-                el: $("#error-dialog"),
-                title: "Error",
-                content: "Invalid page: " + name
-            }).open();
-            return;
-        }
-
-        page.open();
-    },
-    render: function() {
-        var self = this;
-        if (self.homePage) self.load(self.homePage);
-    }
-});
-
 var Dialog = Backbone.View.extend({
     initialize: function(options) {
         var self = this;
@@ -470,17 +449,6 @@ var TableItem = Backbone.View.extend({
         }
 
         td.html(newContent);
-
-        // add link handler
-        $("a", td).click(function(e) {
-            e.preventDefault();
-            self.open(td);
-        });
-    },
-    open: function(td) {
-        var self = this;
-        var column = td.attr("name");
-        self.table.open(self, column);
     }
 });
 
@@ -927,7 +895,10 @@ var EntryPage = Page.extend({
         EntryPage.__super__.initialize.call(self, options);
         self.model = options.model;
         self.mode = options.mode || "view";
+        self.title = options.title;
         self.editable = options.editable || [];
+        self.parentPage = options.parentPage;
+        self.parentHash = options.parentHash;
     },
     load: function() {
         var self = this;
@@ -986,12 +957,19 @@ var EntryPage = Page.extend({
             // Use blank entry.
             self.entry = {};
 
+            // Replace title.
+            self.$("span[name='title']").text(self.title);
+
         } else {
             // Use fetched entry.
             self.entry = _.clone(self.model.attributes);
 
-            // Show entry ID in the title.
-            self.$("span[name='id']").text(self.entry.id);
+            // Update title with entry attributes.
+            self.$("span[name='title']").each(function() {
+                var title = $(this);
+                var text = title.text();
+                title.text(PKI.substitute(text, self.entry));
+            });
 
         }
 
@@ -1036,8 +1014,17 @@ var EntryPage = Page.extend({
     },
     close: function() {
         var self = this;
-        self.mode = "view";
-        self.render();
+
+        if (self.parentHash) {
+            window.location.hash = self.parentHash;
+
+        } else if (self.parentPage) {
+            self.parentPage.open();
+
+        } else {
+            self.mode = "view";
+            self.render();
+        }
     },
     cancel: function() {
         var self = this;
diff --git a/base/tps-tomcat/shared/webapps/tps/js/activity.js b/base/tps-tomcat/shared/webapps/tps/js/activity.js
index 5b636b69e02c3ba0e6785f0c2bd82c76ce8ac5c1..1d029c86e6c96b9371cabdec2c1983ef4e98b0fc 100644
--- a/base/tps-tomcat/shared/webapps/tps/js/activity.js
+++ b/base/tps-tomcat/shared/webapps/tps/js/activity.js
@@ -70,15 +70,6 @@ var ActivityPage = EntryPage.extend({
     initialize: function(options) {
         var self = this;
         ActivityPage.__super__.initialize.call(self, options);
-        self.parentPage = options.parentPage;
-    },
-    close: function() {
-        var self = this;
-        if (self.parentPage) {
-            self.parentPage.open();
-        } else {
-            ActivityPage.__super__.close.call(self);
-        }
     }
 });
 
@@ -86,18 +77,6 @@ var ActivitiesTable = ModelTable.extend({
     initialize: function(options) {
         var self = this;
         ActivitiesTable.__super__.initialize.call(self, options);
-        self.parentPage = options.parentPage;
-    },
-    open: function(item, column) {
-        var self = this;
-
-        var page = new ActivityPage({
-            el: self.parentPage.$el,
-            url: "activity.html",
-            model: self.collection.get(item.entry.id)
-        });
-
-        page.open();
     }
 });
 
@@ -107,8 +86,7 @@ var ActivitiesPage = Page.extend({
 
         var table = new ActivitiesTable({
             el: $("table[name='activities']"),
-            collection: new ActivityCollection(),
-            parentPage: self
+            collection: new ActivityCollection()
         });
 
         table.render();
diff --git a/base/tps-tomcat/shared/webapps/tps/js/audit.js b/base/tps-tomcat/shared/webapps/tps/js/audit.js
index b5de110bac712390c77d04c88cfa74e11286c870..986596e1d0ddee440a5f87f5a6e2a14ff991f5f8 100644
--- a/base/tps-tomcat/shared/webapps/tps/js/audit.js
+++ b/base/tps-tomcat/shared/webapps/tps/js/audit.js
@@ -77,22 +77,56 @@ var AuditTableItem = TableItem.extend({
         var self = this;
         AuditTableItem.__super__.initialize.call(self, options);
     },
-    open: function(td) {
+    renderColumn: function(td, templateTD) {
         var self = this;
 
-        // in view mode all events are read-only
-        if (self.table.mode == "view") {
-            return;
-        }
+        AuditTableItem.__super__.renderColumn.call(self, td, templateTD);
+
+        $("a", td).click(function(e) {
+            e.preventDefault();
+            self.open();
+        });
+    },
+    open: function() {
+        var self = this;
 
-        // mandatory events are read-only
         var value = self.get("value");
-        if (value == "mandatory") {
-            return;
+        var dialog;
+
+        if (self.table.mode == "view" || value == "mandatory") {
+            // In view mode all events are read-only.
+            // Mandatory events are always read-only.
+            dialog = new Dialog({
+                el: self.table.parent.$("#event-dialog"),
+                title: "Event",
+                readonly: ["name", "value"],
+                actions: ["close"]
+            });
+
+        } else if (self.table.mode == "edit" && value != "mandatory") {
+            // Optional events are editable in edit mode.
+            dialog = new Dialog({
+                el: self.table.parent.$("#event-dialog"),
+                title: "Edit Event",
+                readonly: ["name"],
+                actions: ["cancel", "save"]
+            });
+
+            dialog.handler("save", function() {
+
+                // save changes
+                dialog.save();
+                _.extend(self.entry, dialog.entry);
+
+                // redraw table
+                self.table.render();
+                dialog.close();
+            });
         }
 
-        // optional events are editable in edit mode
-        AuditTableItem.__super__.open.call(self, td);
+        dialog.entry = _.clone(self.entry);
+
+        dialog.open();
     }
 });
 
@@ -112,6 +146,9 @@ var AuditPage = EntryPage.extend({
         self.disableLink = $("a[name='disable']", self.menu);
 
         self.enableLink.click(function(e) {
+
+            e.preventDefault();
+
             var message = "Are you sure you want to enable this entry?";
             if (!confirm(message)) return;
             self.model.enable({
@@ -130,6 +167,9 @@ var AuditPage = EntryPage.extend({
         });
 
         self.disableLink.click(function(e) {
+
+            e.preventDefault();
+
             var message = "Are you sure you want to disable this entry?";
             if (!confirm(message)) return;
             self.model.disable({
@@ -147,31 +187,14 @@ var AuditPage = EntryPage.extend({
             });
         });
 
-        var eventDialog = self.$("#event-dialog");
-
-        var eventEditDialog = new Dialog({
-            el: eventDialog,
-            title: "Edit Event",
-            readonly: ["name"],
-            actions: ["cancel", "save"]
-        });
-
-        var eventViewDialog = new Dialog({
-            el: eventDialog,
-            title: "Event",
-            readonly: ["name", "value"],
-            actions: ["close"]
-        });
-
         self.eventsTable = new Table({
             el: self.$("table[name='events']"),
             columnMappings: {
                 id: "name"
             },
-            editDialog: eventEditDialog,
-            viewDialog: eventViewDialog,
             pageSize: 10,
-            tableItem: AuditTableItem
+            tableItem: AuditTableItem,
+            parent: self
         });
     },
     renderContent: function() {
@@ -183,6 +206,7 @@ var AuditPage = EntryPage.extend({
         if (status == "Disabled") {
             self.enableLink.show();
             self.disableLink.hide();
+
         } else if (status == "Enabled") {
             self.enableLink.hide();
             self.disableLink.show();
diff --git a/base/tps-tomcat/shared/webapps/tps/js/authenticator.js b/base/tps-tomcat/shared/webapps/tps/js/authenticator.js
index 1996acb42f1cb4444db2bdd2cd94095a8894c57f..f91cf6bfeb3ad7046710cb227bf8c1a253b55926 100644
--- a/base/tps-tomcat/shared/webapps/tps/js/authenticator.js
+++ b/base/tps-tomcat/shared/webapps/tps/js/authenticator.js
@@ -86,32 +86,11 @@ var AuthenticatorsTable = ModelTable.extend({
     initialize: function(options) {
         var self = this;
         AuthenticatorsTable.__super__.initialize.call(self, options);
-        self.parentPage = options.parentPage;
-    },
-    open: function(item) {
-        var self = this;
-
-        var page = new EntryWithPropertiesPage({
-            el: self.parentPage.$el,
-            url: "authenticator.html",
-            model: self.collection.get(item.entry.id)
-        });
-
-        page.open();
     },
     add: function() {
         var self = this;
 
-        var page = new EntryWithPropertiesPage({
-            el: self.parentPage.$el,
-            url: "authenticator.html",
-            model: new AuthenticatorModel(),
-            mode: "add",
-            editable: ["authenticatorID"],
-            parentPage: self.parentPage
-        });
-
-        page.open();
+        window.location.hash = "#new-authenticator";
     }
 });
 
@@ -122,7 +101,7 @@ var AuthenticatorsPage = Page.extend({
         var table = new AuthenticatorsTable({
             el: $("table[name='authenticators']"),
             collection: new AuthenticatorCollection(),
-            parentPage: self
+            parent: self
         });
 
         table.render();
diff --git a/base/tps-tomcat/shared/webapps/tps/js/cert.js b/base/tps-tomcat/shared/webapps/tps/js/cert.js
index 6754b3b535f6186027851abba7e50419c7d2a618..016b56ee012e4bce98d37106e1e4a8d05e955e22 100644
--- a/base/tps-tomcat/shared/webapps/tps/js/cert.js
+++ b/base/tps-tomcat/shared/webapps/tps/js/cert.js
@@ -76,15 +76,6 @@ var CertificatePage = EntryPage.extend({
     initialize: function(options) {
         var self = this;
         CertificatePage.__super__.initialize.call(self, options);
-        self.parentPage = options.parentPage;
-    },
-    close: function() {
-        var self = this;
-        if (self.parentPage) {
-            self.parentPage.open();
-        } else {
-            CertificatePage.__super__.close.call(self);
-        }
     }
 });
 
@@ -92,18 +83,6 @@ var CertificatesTable = ModelTable.extend({
     initialize: function(options) {
         var self = this;
         CertificatesTable.__super__.initialize.call(self, options);
-        self.parentPage = options.parentPage;
-    },
-    open: function(item, column) {
-        var self = this;
-
-        var page = new CertificatePage({
-            el: self.parentPage.$el,
-            url: "cert.html",
-            model: self.collection.get(item.entry.id)
-        });
-
-        page.open();
     }
 });
 
@@ -113,8 +92,7 @@ var CertificatesPage = Page.extend({
 
         var table = new CertificatesTable({
             el: $("table[name='certificates']"),
-            collection: new CertificateCollection(),
-            parentPage: self
+            collection: new CertificateCollection()
         });
 
         table.render();
diff --git a/base/tps-tomcat/shared/webapps/tps/js/config.js b/base/tps-tomcat/shared/webapps/tps/js/config.js
index cbbd0affb50e72ddcd53ffbe3aae48580ebfe42c..5b651a09d40279eb9d73c9fdf321fea8c67955e4 100644
--- a/base/tps-tomcat/shared/webapps/tps/js/config.js
+++ b/base/tps-tomcat/shared/webapps/tps/js/config.js
@@ -40,7 +40,7 @@ var ConfigModel = Model.extend({
     }
 });
 
-var ConfigPage = EntryWithPropertiesPage.extend({
+var ConfigPage = ConfigEntryPage.extend({
     initialize: function(options) {
         var self = this;
         options.model = new ConfigModel();
diff --git a/base/tps-tomcat/shared/webapps/tps/js/connection.js b/base/tps-tomcat/shared/webapps/tps/js/connection.js
index 771d8f50fc885837f59c08d61cc7909d1902f417..020b9e57b4fe72778cd093b87114aa01a9d60316 100644
--- a/base/tps-tomcat/shared/webapps/tps/js/connection.js
+++ b/base/tps-tomcat/shared/webapps/tps/js/connection.js
@@ -86,32 +86,11 @@ var ConnectionsTable = ModelTable.extend({
     initialize: function(options) {
         var self = this;
         ConnectionsTable.__super__.initialize.call(self, options);
-        self.parentPage = options.parentPage;
-    },
-    open: function(item) {
-        var self = this;
-
-        var page = new EntryWithPropertiesPage({
-            el: self.parentPage.$el,
-            url: "connection.html",
-            model: self.collection.get(item.entry.id)
-        });
-
-        page.open();
     },
     add: function() {
         var self = this;
 
-        var page = new EntryWithPropertiesPage({
-            el: self.parentPage.$el,
-            url: "connection.html",
-            model: new ConnectionModel(),
-            mode: "add",
-            editable: ["connectionID"],
-            parentPage: self.parentPage
-        });
-
-        page.open();
+        window.location.hash = "#new-connection";
     }
 });
 
@@ -122,7 +101,7 @@ var ConnectionsPage = Page.extend({
         var table = new ConnectionsTable({
             el: $("table[name='connections']"),
             collection: new ConnectionCollection(),
-            parentPage: self
+            parent: self
         });
 
         table.render();
diff --git a/base/tps-tomcat/shared/webapps/tps/js/group.js b/base/tps-tomcat/shared/webapps/tps/js/group.js
index 81812b370145af43569111f3e5e83d0783e32f49..71f1e25e8466add92cd7a688edaee58be371d337 100644
--- a/base/tps-tomcat/shared/webapps/tps/js/group.js
+++ b/base/tps-tomcat/shared/webapps/tps/js/group.js
@@ -59,15 +59,6 @@ var GroupPage = EntryPage.extend({
     initialize: function(options) {
         var self = this;
         GroupPage.__super__.initialize.call(self, options);
-        self.parentPage = options.parentPage;
-    },
-    close: function() {
-        var self = this;
-        if (self.parentPage) {
-            self.parentPage.open();
-        } else {
-            GroupPage.__super__.close.call(self);
-        }
     }
 });
 
@@ -75,33 +66,11 @@ var GroupsTable = ModelTable.extend({
     initialize: function(options) {
         var self = this;
         GroupsTable.__super__.initialize.call(self, options);
-        self.parentPage = options.parentPage;
-    },
-    open: function(item, column) {
-        var self = this;
-
-        var page = new GroupPage({
-            el: self.parentPage.$el,
-            url: "group.html",
-            model: self.collection.get(item.entry.id),
-            editable: ["description"]
-        });
-
-        page.open();
     },
     add: function() {
         var self = this;
 
-        var page = new GroupPage({
-            el: self.parentPage.$el,
-            url: "group.html",
-            model: new GroupModel(),
-            mode: "add",
-            editable: ["groupID", "description"],
-            parentPage: self.parentPage
-        });
-
-        page.open();
+        window.location.hash = "#new-group";
     }
 });
 
@@ -111,8 +80,7 @@ var GroupsPage = Page.extend({
 
         var table = new GroupsTable({
             el: $("table[name='groups']"),
-            collection: new GroupCollection(),
-            parentPage: self
+            collection: new GroupCollection()
         });
 
         table.render();
diff --git a/base/tps-tomcat/shared/webapps/tps/js/profile-mapping.js b/base/tps-tomcat/shared/webapps/tps/js/profile-mapping.js
index 26cafdedb53b40aa56e733585b40b0b749c0e73b..54c04256279b5e4fcb92e12cb5cb202644aa62f8 100644
--- a/base/tps-tomcat/shared/webapps/tps/js/profile-mapping.js
+++ b/base/tps-tomcat/shared/webapps/tps/js/profile-mapping.js
@@ -86,32 +86,11 @@ var ProfileMappingsTable = ModelTable.extend({
     initialize: function(options) {
         var self = this;
         ProfileMappingsTable.__super__.initialize.call(self, options);
-        self.parentPage = options.parentPage;
-    },
-    open: function(item) {
-        var self = this;
-
-        var page = new EntryWithPropertiesPage({
-            el: self.parentPage.$el,
-            url: "profile-mapping.html",
-            model: self.collection.get(item.entry.id)
-        });
-
-        page.open();
     },
     add: function() {
         var self = this;
 
-        var page = new EntryWithPropertiesPage({
-            el: self.parentPage.$el,
-            url: "profile-mapping.html",
-            model: new ProfileMappingModel(),
-            mode: "add",
-            editable: ["profileMappingID"],
-            parentPage: self.parentPage
-        });
-
-        page.open();
+        window.location.hash = "#new-profile-mapping";
     }
 });
 
@@ -122,7 +101,7 @@ var ProfileMappingsPage = Page.extend({
         var table = new ProfileMappingsTable({
             el: $("table[name='profile-mappings']"),
             collection: new ProfileMappingCollection(),
-            parentPage: self
+            parent: self
         });
 
         table.render();
diff --git a/base/tps-tomcat/shared/webapps/tps/js/profile.js b/base/tps-tomcat/shared/webapps/tps/js/profile.js
index 17aa2610456a7eef594583f080a845d5085b5c20..0454686a9993560909cd4d350488a2ac823fc769 100644
--- a/base/tps-tomcat/shared/webapps/tps/js/profile.js
+++ b/base/tps-tomcat/shared/webapps/tps/js/profile.js
@@ -86,32 +86,11 @@ var ProfilesTable = ModelTable.extend({
     initialize: function(options) {
         var self = this;
         ProfilesTable.__super__.initialize.call(self, options);
-        self.parentPage = options.parentPage;
-    },
-    open: function(item, column) {
-        var self = this;
-
-        var page = new EntryWithPropertiesPage({
-            el: self.parentPage.$el,
-            url: "profile.html",
-            model: self.collection.get(item.entry.id)
-        });
-
-        page.open();
     },
     add: function() {
         var self = this;
 
-        var page = new EntryWithPropertiesPage({
-            el: self.parentPage.$el,
-            url: "profile.html",
-            model: new ProfileModel(),
-            mode: "add",
-            editable: ["profileID"],
-            parentPage: self.parentPage
-        });
-
-        page.open();
+        window.location.hash = "#new-profile";
     }
 });
 
@@ -122,7 +101,7 @@ var ProfilesPage = Page.extend({
         var table = new ProfilesTable({
             el: $("table[name='profiles']"),
             collection: new ProfileCollection(),
-            parentPage: self
+            parent: self
         });
 
         table.render();
diff --git a/base/tps-tomcat/shared/webapps/tps/js/selftest.js b/base/tps-tomcat/shared/webapps/tps/js/selftest.js
index df8204e716cf252836c0c676ab5395274a84eba5..d2890781760eb856f5684365dc3b7bc243c06302 100644
--- a/base/tps-tomcat/shared/webapps/tps/js/selftest.js
+++ b/base/tps-tomcat/shared/webapps/tps/js/selftest.js
@@ -64,15 +64,6 @@ var SelfTestPage = EntryPage.extend({
     initialize: function(options) {
         var self = this;
         SelfTestPage.__super__.initialize.call(self, options);
-        self.parentPage = options.parentPage;
-    },
-    close: function() {
-        var self = this;
-        if (self.parentPage) {
-            self.parentPage.open();
-        } else {
-            GroupPage.__super__.close.call(self);
-        }
     }
 });
 
@@ -80,18 +71,6 @@ var SelfTestsTable = ModelTable.extend({
     initialize: function(options) {
         var self = this;
         SelfTestsTable.__super__.initialize.call(self, options);
-        self.parentPage = options.parentPage;
-    },
-    open: function(item, column) {
-        var self = this;
-
-        var page = new SelfTestPage({
-            el: self.parentPage.$el,
-            url: "selftest.html",
-            model: self.collection.get(item.entry.id)
-        });
-
-        page.open();
     }
 });
 
@@ -101,8 +80,7 @@ var SelfTestsPage = Page.extend({
 
         var table = new SelfTestsTable({
             el: $("table[name='selftests']"),
-            collection: new SelfTestCollection(),
-            parentPage: self
+            collection: new SelfTestCollection()
         });
 
         table.render();
diff --git a/base/tps-tomcat/shared/webapps/tps/js/token.js b/base/tps-tomcat/shared/webapps/tps/js/token.js
index c3b1f21c62af23fdac483dd0023e78d5198c5b06..085003a1e5905257f47bb4ee54d5010f30e54725 100644
--- a/base/tps-tomcat/shared/webapps/tps/js/token.js
+++ b/base/tps-tomcat/shared/webapps/tps/js/token.js
@@ -101,7 +101,6 @@ var TokenPage = EntryPage.extend({
     initialize: function(options) {
         var self = this;
         TokenPage.__super__.initialize.call(self, options);
-        self.parentPage = options.parentPage;
     },
     setup: function() {
         var self = this;
@@ -112,6 +111,8 @@ var TokenPage = EntryPage.extend({
 
         self.changeStatusLink.click(function(e) {
 
+            e.preventDefault();
+
             var dialog = new Dialog({
                 el: $("#token-status-dialog"),
                 title: "Change Token Status",
@@ -160,40 +161,31 @@ var TokenPage = EntryPage.extend({
         } else {
             self.changeStatusLink.show();
         }
-    },
-    close: function() {
-        var self = this;
-        if (self.parentPage) {
-            self.parentPage.open();
-        } else {
-            TokenPage.__super__.close.call(self);
-        }
     }
 });
 
-var TokensTable = ModelTable.extend({
+var TokenTableItem = TableItem.extend({
     initialize: function(options) {
         var self = this;
-        TokensTable.__super__.initialize.call(self, options);
-        self.parentPage = options.parentPage;
+        TokenTableItem.__super__.initialize.call(self, options);
     },
-    open: function(item, column) {
+    renderColumn: function(td, templateTD) {
         var self = this;
 
-        var model = self.collection.get(item.entry.id);
+        TokenTableItem.__super__.renderColumn.call(self, td, templateTD);
 
-        if (column == "id") {
-            var page = new TokenPage({
-                el: self.parentPage.$el,
-                url: "token.html",
-                model: model,
-                editable: ["userID", "type", "appletID", "keyInfo"]
+        var name = td.attr("name");
+        if (name == "status") {
+            $("a", td).click(function(e) {
+                e.preventDefault();
+                self.editStatus();
             });
-
-            page.open();
-
-            return;
         }
+    },
+    editStatus: function() {
+        var self = this;
+
+        var model = self.table.collection.get(self.entry.id);
 
         var dialog = new Dialog({
             el: $("#token-status-dialog"),
@@ -216,7 +208,7 @@ var TokensTable = ModelTable.extend({
                 model.changeStatus({
                     status: dialog.entry.status,
                     success: function(data, textStatus, jqXHR) {
-                        self.render();
+                        self.table.render();
                     },
                     error: function(jqXHR, textStatus, errorThrow) {
                         new ErrorDialog({
@@ -232,20 +224,19 @@ var TokensTable = ModelTable.extend({
         });
 
         dialog.open();
+    }
+});
+
+var TokensTable = ModelTable.extend({
+    initialize: function(options) {
+        var self = this;
+        options.tableItem = TokenTableItem;
+        TokensTable.__super__.initialize.call(self, options);
     },
     add: function() {
         var self = this;
 
-        var page = new TokenPage({
-            el: self.parentPage.$el,
-            url: "token.html",
-            model: new TokenModel(),
-            mode: "add",
-            editable: ["tokenID", "userID", "type", "appletID", "keyInfo"],
-            parentPage: self.parentPage
-        });
-
-        page.open();
+        window.location.hash = "#new-token";
     }
 });
 
@@ -255,8 +246,7 @@ var TokensPage = Page.extend({
 
         var table = new TokensTable({
             el: $("table[name='tokens']"),
-            collection: new TokenCollection(),
-            parentPage: self
+            collection: new TokenCollection()
         });
 
         table.render();
diff --git a/base/tps-tomcat/shared/webapps/tps/js/tps.js b/base/tps-tomcat/shared/webapps/tps/js/tps.js
index bd18538a4d84defb7ded5e6d89262590ab0212d6..4765337592ff2acebda0fe3f3d54793c56d4c47c 100644
--- a/base/tps-tomcat/shared/webapps/tps/js/tps.js
+++ b/base/tps-tomcat/shared/webapps/tps/js/tps.js
@@ -34,16 +34,54 @@ var PropertiesTableItem = TableItem.extend({
 
         return PropertiesTableItem.__super__.get.call(self, name);
     },
-    open: function(td) {
+    renderColumn: function(td, templateTD) {
         var self = this;
 
-        // in view mode all properties are read-only
+        PropertiesTableItem.__super__.renderColumn.call(self, td, templateTD);
+
+        $("a", td).click(function(e) {
+            e.preventDefault();
+            self.open();
+        });
+    },
+    open: function() {
+        var self = this;
+
+        var dialog;
+
         if (self.table.mode == "view") {
-            return;
+            // In view mode all properties are read-only.
+            dialog = new Dialog({
+                el: self.table.parent.$("#property-dialog"),
+                title: "Property",
+                readonly: ["name", "value"],
+                actions: ["close"]
+            });
+
+        } else {
+            // In edit mode all properties are editable.
+            dialog = new Dialog({
+                el: self.table.parent.$("#property-dialog"),
+                title: "Edit Property",
+                readonly: ["name"],
+                actions: ["cancel", "save"]
+            });
+
+            dialog.handler("save", function() {
+
+                // save changes
+                dialog.save();
+                _.extend(self.entry, dialog.entry);
+
+                // redraw table
+                self.table.render();
+                dialog.close();
+            });
         }
 
-        // in edit mode all properties are editable
-        PropertiesTableItem.__super__.open.call(self, td);
+        dialog.entry = _.clone(self.entry);
+
+        dialog.open();
     }
 });
 
@@ -76,23 +114,25 @@ var PropertiesTable = Table.extend({
     }
 });
 
-var EntryWithPropertiesPage = EntryPage.extend({
+var ConfigEntryPage = EntryPage.extend({
     initialize: function(options) {
         var self = this;
-        EntryWithPropertiesPage.__super__.initialize.call(self, options);
-        self.parentPage = options.parentPage;
+        ConfigEntryPage.__super__.initialize.call(self, options);
         self.tableItem = options.tableItem || PropertiesTableItem;
         self.tableSize = options.tableSize || 10;
     },
     setup: function() {
         var self = this;
 
-        EntryWithPropertiesPage.__super__.setup.call(self);
+        ConfigEntryPage.__super__.setup.call(self);
 
         self.enableLink = $("a[name='enable']", self.menu);
         self.disableLink = $("a[name='disable']", self.menu);
 
         self.enableLink.click(function(e) {
+
+            e.preventDefault();
+
             var message = "Are you sure you want to enable this entry?";
             if (!confirm(message)) return;
             self.model.enable({
@@ -111,6 +151,9 @@ var EntryWithPropertiesPage = EntryPage.extend({
         });
 
         self.disableLink.click(function(e) {
+
+            e.preventDefault();
+
             var message = "Are you sure you want to disable this entry?";
             if (!confirm(message)) return;
             self.model.disable({
@@ -136,20 +179,6 @@ var EntryWithPropertiesPage = EntryPage.extend({
             actions: ["cancel", "add"]
         });
 
-        var editDialog = new Dialog({
-            el: dialog,
-            title: "Edit Property",
-            readonly: ["name"],
-            actions: ["cancel", "save"]
-        });
-
-        var viewDialog = new Dialog({
-            el: dialog,
-            title: "Property",
-            readonly: ["name", "value"],
-            actions: ["close"]
-        });
-
         var table = self.$("table[name='properties']");
         self.addButton = $("button[name='add']", table);
         self.removeButton = $("button[name='remove']", table);
@@ -157,8 +186,6 @@ var EntryWithPropertiesPage = EntryPage.extend({
         self.propertiesTable = new PropertiesTable({
             el: table,
             addDialog: addDialog,
-            editDialog: editDialog,
-            viewDialog: viewDialog,
             tableItem: self.tableItem,
             pageSize: self.tableSize,
             parent: self
@@ -167,12 +194,13 @@ var EntryWithPropertiesPage = EntryPage.extend({
     renderContent: function() {
         var self = this;
 
-        EntryWithPropertiesPage.__super__.renderContent.call(self);
+        ConfigEntryPage.__super__.renderContent.call(self);
 
         var status = self.entry.status;
         if (status == "Disabled") {
             self.enableLink.show();
             self.disableLink.hide();
+
         } else if (status == "Enabled") {
             self.enableLink.hide();
             self.disableLink.show();
@@ -196,16 +224,8 @@ var EntryWithPropertiesPage = EntryPage.extend({
     saveFields: function() {
         var self = this;
 
-        EntryWithPropertiesPage.__super__.saveFields.call(self);
+        ConfigEntryPage.__super__.saveFields.call(self);
 
         self.entry.properties = self.propertiesTable.entries;
-    },
-    close: function() {
-        var self = this;
-        if (self.parentPage) {
-            self.parentPage.open();
-        } else {
-            EntryWithPropertiesPage.__super__.close.call(self);
-        }
     }
 });
diff --git a/base/tps-tomcat/shared/webapps/tps/js/user.js b/base/tps-tomcat/shared/webapps/tps/js/user.js
index 310a49b711625d6adc00bfc0b719df92365362cd..3a29f1dd137afc8f1157b627166c43734185f0bd 100644
--- a/base/tps-tomcat/shared/webapps/tps/js/user.js
+++ b/base/tps-tomcat/shared/webapps/tps/js/user.js
@@ -90,7 +90,6 @@ var UserPage = EntryPage.extend({
     initialize: function(options) {
         var self = this;
         UserPage.__super__.initialize.call(self, options);
-        self.parentPage = options.parentPage;
     },
     loadField: function(input) {
         var self = this;
@@ -122,14 +121,6 @@ var UserPage = EntryPage.extend({
             self.entry.attributes = attributes;
         }
         attributes.tpsProfiles = input.val();
-    },
-    close: function() {
-        var self = this;
-        if (self.parentPage) {
-            self.parentPage.open();
-        } else {
-            UserPage.__super__.close.call(self);
-        }
     }
 });
 
@@ -137,33 +128,11 @@ var UsersTable = ModelTable.extend({
     initialize: function(options) {
         var self = this;
         UsersTable.__super__.initialize.call(self, options);
-        self.parentPage = options.parentPage;
-    },
-    open: function(item, column) {
-        var self = this;
-
-        var page = new UserPage({
-            el: self.parentPage.$el,
-            url: "user.html",
-            model: self.collection.get(item.entry.id),
-            editable: ["fullName", "email", "tpsProfiles"]
-        });
-
-        page.open();
     },
     add: function() {
         var self = this;
 
-        var page = new UserPage({
-            el: self.parentPage.$el,
-            url: "user.html",
-            model: new UserModel(),
-            mode: "add",
-            editable: ["userID", "fullName", "email", "tpsProfiles"],
-            parentPage: self.parentPage
-        });
-
-        page.open();
+        window.location.hash = "#new-user";
     }
 });
 
@@ -173,8 +142,7 @@ var UsersPage = Page.extend({
 
         var table = new UsersTable({
             el: $("table[name='users']"),
-            collection: new UserCollection(),
-            parentPage: self
+            collection: new UserCollection()
         });
 
         table.render();
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/activities.html b/base/tps-tomcat/shared/webapps/tps/ui/activities.html
index 51cc3b105e351e99a9b363854b80fccf4e9a0a66..0762401fd01c35169dc77279ab97a7235e6c03c3 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/activities.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/activities.html
@@ -16,6 +16,11 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li class="active"><strong>Activities</strong></li>
+</ol>
+
 <span class="pki-title">Activities</span>
 </div>
 
@@ -44,7 +49,7 @@
 <tbody>
     <tr>
         <td class="pki-select-column"><input id="activity_select" type="checkbox"><label for="activity_select">&nbsp;</label></td>
-        <td name="id"><a href="/tps/ui/activities/${id}">${id}</a></td>
+        <td name="id"><a href="#activities/${id}">${id}</a></td>
         <td name="tokenID">${tokenID}</td>
         <td name="userID">${userID}</td>
         <td name="ip">${ip}</td>
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/activity.html b/base/tps-tomcat/shared/webapps/tps/ui/activity.html
index 5845d045853542b83250c6fa622351225520b84f..262e00c0829a6a09c56c7eb257849668a6588578 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/activity.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/activity.html
@@ -16,7 +16,13 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
-<span class="pki-title">Activity <span name="id"></span></span>
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li><a href="#activities">Activity</a></li>
+    <li class="active"><strong><span name="title">Activity ${id}</span></strong></li>
+</ol>
+
+<span name="title" class="pki-title">Activity ${id}</span>
 </div>
 
 <div name="activity" class="pki-fields">
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/audit.html b/base/tps-tomcat/shared/webapps/tps/ui/audit.html
index 08c5b49d26d891dd83fb24cdb9b1c81fe8cda98e..3e5662e1653eed713fc519ba4a3590648f0b1547 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/audit.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/audit.html
@@ -16,6 +16,10 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li class="active"><strong>Audit Logging</strong></li>
+</ol>
 
 <span class="pki-title">Audit Logging</span>
 
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/authenticator.html b/base/tps-tomcat/shared/webapps/tps/ui/authenticator.html
index 02a97c233588f25ece616bbda371c0dc7af18f15..866dab10ce77e70eb9c9fcef654dde80bee80294 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/authenticator.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/authenticator.html
@@ -16,8 +16,13 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li><a href="#authenticators">Authentication Sources</a></li>
+    <li class="active"><strong><span name="title">Authentication Source ${id}</span></strong></li>
+</ol>
 
-<span class="pki-title">Authentication Source <span name="id"></span></span>
+<span name="title" class="pki-title">Authentication Source ${id}</span>
 
 <span class="pki-actions">
 
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/authenticators.html b/base/tps-tomcat/shared/webapps/tps/ui/authenticators.html
index 02b6042e7acb9174e3b19af2da1018a554722587..f9b0b0a2836d80e3cb41de37cf0dd8298ecc47ce 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/authenticators.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/authenticators.html
@@ -16,6 +16,10 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li class="active"><strong>Authentication Sources</strong></li>
+</ol>
 <span class="pki-title">Authentication Sources</span>
 </div>
 
@@ -41,7 +45,7 @@
 <tbody>
     <tr>
         <td class="pki-select-column"><input id="authenticator_select" type="checkbox"><label for="authenticator_select">&nbsp;</label></td>
-        <td name="id"><a href="/tps/ui/authenticators/${id}">${id}</a></td>
+        <td name="id"><a href="#authenticators/${id}">${id}</a></td>
         <td name="status">${status}</td>
     </tr>
 </tbody>
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/cert.html b/base/tps-tomcat/shared/webapps/tps/ui/cert.html
index e750527b10bb5d4ab7db32627fe42f418739329e..456f23355777ced687382ab5165ae7c8679fc00c 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/cert.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/cert.html
@@ -16,7 +16,13 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
-<span class="pki-title">Certificate <span name="id"></span></span>
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li><a href="#certs">Certificates</a></li>
+    <li class="active"><strong><span name="title">Certificate ${id}</span></strong></li>
+</ol>
+
+<span name="title" class="pki-title">Certificate ${id}</span>
 </div>
 
 <div name="certificate" class="pki-fields">
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/certs.html b/base/tps-tomcat/shared/webapps/tps/ui/certs.html
index f4b052009a5e961238f902194a17a130549f2efc..a87c2dd3239165c70e28dee1fdc5f0579d2bbb93 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/certs.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/certs.html
@@ -16,6 +16,11 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li class="active"><strong>Certificates</strong></li>
+</ol>
+
 <span class="pki-title">Certificates</span>
 </div>
 
@@ -46,7 +51,7 @@
 <tbody>
     <tr>
         <td class="pki-select-column"><input id="cert_select" type="checkbox"><label for="cert_select">&nbsp;</label></td>
-        <td name="id"><a href="/tps/ui/certs/${id}">${id}</a></td>
+        <td name="id"><a href="#certs/${id}">${id}</a></td>
         <td name="serialNumber">${serialNumber}</td>
         <td name="subject">${subject}</td>
         <td name="tokenID">${tokenID}</td>
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/config.html b/base/tps-tomcat/shared/webapps/tps/ui/config.html
index 79f16dd20964d168fec2728cdeb4eff6a30154ab..3d838bd6f38417875e9dd9394b57b6b22ac8fef3 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/config.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/config.html
@@ -16,8 +16,12 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li class="active"><strong>General Configuration</strong></li>
+</ol>
 
-<span class="pki-title">General</span></span>
+<span class="pki-title">General Configuration</span></span>
 
 <span class="pki-actions">
 
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/connection.html b/base/tps-tomcat/shared/webapps/tps/ui/connection.html
index 29348839681204c8479e7d6eb9f9f694ce67cd92..68a759e9546eb8479495bbd886c2d59cbbd1a247 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/connection.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/connection.html
@@ -16,8 +16,13 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li><a href="#connections">Subsystem Connections</a></li>
+    <li class="active"><strong><span name="title">Subsystem Connection ${id}</span></strong></li>
+</ol>
 
-<span class="pki-title">Subsystem Connection <span name="id"></span></span>
+<span name="title" class="pki-title">Subsystem Connection ${id}</span>
 
 <span class="pki-actions">
 
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/connections.html b/base/tps-tomcat/shared/webapps/tps/ui/connections.html
index 170fcab316ec35bc3e1773628ab1ba70729d1df1..d700e1f3cedb2727d940580e16b3ba34a2b8f70b 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/connections.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/connections.html
@@ -16,6 +16,11 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li class="active"><strong>Subsystem Connections</strong></li>
+</ol>
+
 <span class="pki-title">Subsystem Connections</span>
 </div>
 
@@ -41,7 +46,7 @@
 <tbody>
     <tr>
         <td class="pki-select-column"><input id="connection_select" type="checkbox"><label for="connection_select">&nbsp;</label></td>
-        <td name="id"><a href="/tps/ui/connections/${id}">${id}</a></td>
+        <td name="id"><a href="#connections/${id}">${id}</a></td>
         <td name="status">${status}</td>
     </tr>
 </tbody>
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/group.html b/base/tps-tomcat/shared/webapps/tps/ui/group.html
index a33969185ea4103be36d802d8a3956a9016272ea..9e612c2c6ac8beabc8daa0aa89dec05009d7ec63 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/group.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/group.html
@@ -16,8 +16,13 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li><a href="#groups">Groups</a></li>
+    <li class="active"><strong><span name="title">Group ${id}</span></strong></li>
+</ol>
 
-<span class="pki-title">Group <span name="id"></span></span>
+<span name="title" class="pki-title">Group ${id}</span>
 
 <span class="pki-actions">
 
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/groups.html b/base/tps-tomcat/shared/webapps/tps/ui/groups.html
index 34dacbc9b5b47a94a7599e5d7e7e1eb9700965eb..9f4239db8e50d3db9abd4efe61946a501f2896c3 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/groups.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/groups.html
@@ -16,6 +16,11 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li class="active"><strong>Groups</strong></li>
+</ol>
+
 <span class="pki-title">Groups</span>
 </div>
 
@@ -41,7 +46,7 @@
 <tbody>
     <tr>
         <td class="pki-select-column"><input id="group_select" type="checkbox"><label for="group_select">&nbsp;</label></td>
-        <td name="id"><a href="/tps/ui/groups/${id}">${id}</a></td>
+        <td name="id"><a href="#groups/${id}">${id}</a></td>
         <td name="description">${description}</td>
     </tr>
 </tbody>
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/home.html b/base/tps-tomcat/shared/webapps/tps/ui/home.html
new file mode 100644
index 0000000000000000000000000000000000000000..89fb26061d2d6ab0a12a8c0a4fd4b4b60e8cebf0
--- /dev/null
+++ b/base/tps-tomcat/shared/webapps/tps/ui/home.html
@@ -0,0 +1,58 @@
+<!-- --- BEGIN COPYRIGHT BLOCK ---
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+     the Free Software Foundation; version 2 of the License.
+
+     This program is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+     GNU General Public License for more details.
+
+     You should have received a copy of the GNU General Public License along
+     with this program; if not, write to the Free Software Foundation, Inc.,
+     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+     Copyright (C) 2014 Red Hat, Inc.
+     All rights reserved.
+     --- END COPYRIGHT BLOCK --- -->
+<div class="pki-header">
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+</ol>
+
+<span name="title" class="pki-title">Token Processing Service</span>
+</div>
+
+<div class="panel panel-default">
+    <div class="panel-heading">
+        <h3 class="panel-title">Token Management</h3>
+    </div>
+    <div class="panel-body">
+        <a href="#tokens">Tokens</a><br>
+        <a href="#certs">Certificates</a><br>
+        <a href="#activities">Activities</a><br>
+    </div>
+</div>
+
+<div class="panel panel-default">
+    <div class="panel-heading">
+        <h3 class="panel-title">Account Management</h3>
+    </div>
+    <div class="panel-body">
+        <a href="#users">Users</a><br>
+        <a href="#groups">Groups</a><br>
+    </div>
+</div>
+
+<div class="panel panel-default">
+    <div class="panel-heading">
+        <h3 class="panel-title">System Management</h3>
+    </div>
+    <div class="panel-body">
+        <a href="#config">General Configuration</a><br>
+        <a href="#authenticators">Authentication Sources</a><br>
+        <a href="#connections">Subsystem Connections</a><br>
+        <a href="#audit">Audit Logging</a><br>
+        <a href="#selftests">Self Tests</a><br>
+    </div>
+</div>
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/index.html b/base/tps-tomcat/shared/webapps/tps/ui/index.html
index a0a265a21837d69a15826d3877d431f59a242d0b..77145dfb00c648af31de1d2a865c3df0f817f1ad 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/index.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/index.html
@@ -41,87 +41,283 @@
     <script src="/tps/js/user.js"></script>
     <script>
 $(function() {
-    var account = new Account();
-
-    var navigation = new Navigation({
-        el: $("#navigation"),
-        logout: function() {
-            account.logout({
-                success: function() {
-                    if (window.crypto) window.crypto.logout();
-                    window.location.href = "/tps";
-                },
-                error: function() {
-                    alert("Logout failed");
-                }
-            });
-        },
-        homePage: "tokens"
-    });
 
     var content = $("#content");
 
-    navigation.page("activities", new ActivitiesPage({
-        el: content,
-        url: "activities.html"
-    }));
-
-    navigation.page("audit", new AuditPage({
-        el: content,
-        url: "audit.html"
-    }));
-
-    navigation.page("authenticators", new AuthenticatorsPage({
-        el: content,
-        url: "authenticators.html"
-    }));
-
-    navigation.page("certs", new CertificatesPage({
-        el: content,
-        url: "certs.html"
-    }));
-
-    navigation.page("config", new ConfigPage({
-        el: content,
-        url: "config.html"
-    }));
-
-    navigation.page("connections", new ConnectionsPage({
-        el: content,
-        url: "connections.html"
-    }));
-
-    navigation.page("groups", new GroupsPage({
-        el: content,
-        url: "groups.html"
-    }));
-
-    navigation.page("profiles", new ProfilesPage({
-        el: content,
-        url: "profiles.html"
-    }));
-
-    navigation.page("profileMappings", new ProfileMappingsPage({
-        el: content,
-        url: "profile-mappings.html"
-    }));
-
-    navigation.page("selftests", new SelfTestsPage({
-        el: content,
-        url: "selftests.html"
-    }));
-
-    navigation.page("tokens", new TokensPage({
-        el: content,
-        url: "tokens.html"
-    }));
-
-    navigation.page("users", new UsersPage({
-        el: content,
-        url: "users.html"
-    }));
-
-    navigation.render();
+    var router = new Backbone.Router();
+
+    router.route("", "home", function() {
+        new Page({
+            el: content,
+            url: "home.html"
+        }).open();
+    });
+
+    router.route("activities", "activities", function() {
+        new ActivitiesPage({
+            el: content,
+            url: "activities.html"
+        }).open();
+    });
+
+    router.route("activities/:id", "activity", function(id) {
+        new ActivityPage({
+            el: content,
+            url: "activity.html",
+            model: new ActivityModel({ id: id })
+        }).open();
+    });
+
+    router.route("audit", "audit", function() {
+        new AuditPage({
+            el: content,
+            url: "audit.html"
+        }).open();
+    });
+
+    router.route("authenticators", "authenticators", function() {
+        new AuthenticatorsPage({
+            el: content,
+            url: "authenticators.html"
+        }).open();
+    });
+
+    router.route("authenticators/:id", "authenticator", function(id) {
+        new ConfigEntryPage({
+            el: content,
+            url: "authenticator.html",
+            model: new AuthenticatorModel({ id: id })
+        }).open();
+    });
+
+    router.route("new-authenticator", "new-authenticator", function() {
+        new ConfigEntryPage({
+            el: content,
+            url: "authenticator.html",
+            model: new AuthenticatorModel(),
+            mode: "add",
+            title: "New Authenticator",
+            editable: ["authenticatorID"],
+            parentHash: "#authenticators"
+        }).open();
+    });
+
+    router.route("certs", "certs", function() {
+        new CertificatesPage({
+            el: content,
+            url: "certs.html"
+        }).open();
+    });
+
+    router.route("certs/:id", "cert", function(id) {
+        new CertificatePage({
+            el: content,
+            url: "cert.html",
+            model: new CertificateModel({ id: id })
+        }).open();
+    });
+
+    router.route("config", "config", function() {
+        new ConfigPage({
+            el: content,
+            url: "config.html"
+        }).open();
+    });
+
+    router.route("connections", "connections", function() {
+        new ConnectionsPage({
+            el: content,
+            url: "connections.html"
+        }).open();
+    });
+
+    router.route("connections/:id", "connection", function(id) {
+        new ConfigEntryPage({
+            el: content,
+            url: "connection.html",
+            model: new ConnectionModel({ id: id })
+        }).open();
+    });
+
+    router.route("new-connection", "new-connection", function() {
+        new ConfigEntryPage({
+            el: content,
+            url: "connection.html",
+            model: new ConnectionModel(),
+            mode: "add",
+            title: "New Connection",
+            editable: ["connectionID"],
+            parentHash: "#connections"
+        }).open();
+    });
+
+    router.route("groups", "groups", function() {
+        new GroupsPage({
+            el: content,
+            url: "groups.html"
+        }).open();
+    });
+
+    router.route("groups/:id", "group", function(id) {
+        new GroupPage({
+            el: content,
+            url: "group.html",
+            model: new GroupModel({ id: id }),
+            editable: ["description"]
+        }).open();
+    });
+
+    router.route("new-group", "new-group", function() {
+        new GroupPage({
+            el: content,
+            url: "group.html",
+            model: new GroupModel(),
+            mode: "add",
+            title: "New Group",
+            editable: ["groupID", "description"],
+            parentHash: "#groups"
+        }).open();
+    });
+
+    router.route("profiles", "profiles", function() {
+        new ProfilesPage({
+            el: content,
+            url: "profiles.html"
+        }).open();
+    });
+
+    router.route("profiles/:id", "profile", function(id) {
+        new ConfigEntryPage({
+            el: content,
+            url: "profile.html",
+            model: new ProfileModel({ id: id })
+        }).open();
+    });
+
+    router.route("new-profile", "new-profile", function() {
+        new ConfigEntryPage({
+            el: content,
+            url: "profile.html",
+            model: new ProfileModel(),
+            mode: "add",
+            title: "New Profile",
+            editable: ["profileID"],
+            parentHash: "#profiles"
+        }).open();
+    });
+
+    router.route("profile-mappings", "profile-mappings", function() {
+        new ProfileMappingsPage({
+            el: content,
+            url: "profile-mappings.html"
+        }).open();
+    });
+
+    router.route("profile-mappings/:id", "profile-mapping", function(id) {
+        new ConfigEntryPage({
+            el: content,
+            url: "profile-mapping.html",
+            model: new ProfileMappingModel({ id: id }),
+        }).open();
+    });
+
+    router.route("new-profile-mapping", "new-profile-mapping", function() {
+        new ConfigEntryPage({
+            el: content,
+            url: "profile-mapping.html",
+            model: new ProfileMappingModel(),
+            mode: "add",
+            title: "New Profile Mapping",
+            editable: ["profileMappingID"],
+            parentHash: "#profile-mappings"
+        }).open();
+    });
+
+    router.route("selftests", "selftests", function() {
+        new SelfTestsPage({
+            el: content,
+            url: "selftests.html"
+        }).open();
+    });
+
+    router.route("selftests/:id", "selftest", function(id) {
+        new SelfTestPage({
+            el: content,
+            url: "selftest.html",
+            model: new SelfTestModel({ id: id })
+        }).open();
+    });
+
+    router.route("tokens", "tokens", function() {
+        new TokensPage({
+            el: content,
+            url: "tokens.html"
+        }).open();
+    });
+
+    router.route("tokens/:id", "token", function(id) {
+        new TokenPage({
+            el: content,
+            url: "token.html",
+            model: new TokenModel({ id: id }),
+            editable: ["userID", "type", "appletID", "keyInfo"]
+        }).open();
+    });
+
+    router.route("new-token", "new-token", function() {
+        new TokenPage({
+            el: content,
+            url: "token.html",
+            model: new TokenModel(),
+            mode: "add",
+            title: "New Token",
+            editable: ["tokenID", "userID", "type", "appletID", "keyInfo"],
+            parentHash: "#tokens"
+        }).open();
+    });
+
+    router.route("users", "users", function() {
+        new UsersPage({
+            el: content,
+            url: "users.html"
+        }).open();
+    });
+
+    router.route("users/:id", "user", function(id) {
+        new UserPage({
+            el: content,
+            url: "user.html",
+            model: new UserModel({ id: id }),
+            editable: ["fullName", "email", "tpsProfiles"]
+        }).open();
+    });
+
+    router.route("new-user", "new-user", function() {
+        new UserPage({
+            el: content,
+            url: "user.html",
+            model: new UserModel(),
+            mode: "add",
+            title: "New User",
+            editable: ["userID", "fullName", "email", "tpsProfiles"],
+            parentHash: "#users"
+        }).open();
+    });
+
+    router.route("logout", "logout", function() {
+        var account = new Account();
+        account.logout({
+            success: function() {
+                if (window.crypto) window.crypto.logout();
+                window.location.href = "/tps";
+            },
+            error: function() {
+                alert("Logout failed");
+            }
+        });
+    });
+
+    Backbone.history.start();
 });
     </script>
 </head>
@@ -153,10 +349,10 @@ $(function() {
     </li>
     </ul>
     <ul class="nav navbar-nav navbar-primary">
+    <li><a href="#"><span class="glyphicon glyphicon-home"></span> Home</a></li>
     <li><a href="#tokens">Tokens</a></li>
     <li><a href="#certs">Certificates</a></li>
     <li><a href="#activities">Activities</a></li>
-    <li><a href="#selftests">SelfTests</a></li>
     <li class="dropdown context">
       <a href="#" class="dropdown-toggle" data-toggle="dropdown">
         Accounts
@@ -169,16 +365,17 @@ $(function() {
     </li>
     <li class="dropdown context">
       <a href="#" class="dropdown-toggle" data-toggle="dropdown">
-        Configuration
+        System
         <b class="caret"></b>
       </a>
       <ul class="dropdown-menu">
-        <li><a href="#config">General</a></li>
+        <li><a href="#config">General Configuration</a></li>
         <li><a href="#authenticators">Authentication Sources</a></li>
         <li><a href="#connections">Subsystem Connections</a></li>
         <li><a href="#profiles">Profiles</a></li>
-        <li><a href="#profileMappings">Profile Mappings</a></li>
+        <li><a href="#profile-mappings">Profile Mappings</a></li>
         <li><a href="#audit">Audit Logging</a></li>
+        <li><a href="#selftests">Self Tests</a></li>
       </ul>
     </li>
     </ul>
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/profile-mapping.html b/base/tps-tomcat/shared/webapps/tps/ui/profile-mapping.html
index 15066b052f0b53ca3370c1b1f0c0838e7ca285d9..9f0a214e0103f186a6abe56141ae0c1e69ac95b8 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/profile-mapping.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/profile-mapping.html
@@ -16,8 +16,13 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li><a href="#profile-mappings">Profile Mappings</a></li>
+    <li class="active"><strong><span name="title">Profile Mapping ${id}</span></strong></li>
+</ol>
 
-<span class="pki-title">Profile Mapping <span name="id"></span></span>
+<span name="title" class="pki-title">Profile Mapping ${id}</span>
 
 <span class="pki-actions">
 
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/profile-mappings.html b/base/tps-tomcat/shared/webapps/tps/ui/profile-mappings.html
index fe651f2184da30740f283dc06687ce7b6a1c805c..dc797bc18601fa1d5fb69cbe5cee150a093f0de2 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/profile-mappings.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/profile-mappings.html
@@ -16,6 +16,11 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li class="active"><strong>Profile Mappings</strong></li>
+</ol>
+
 <span class="pki-title">Profile Mappings</span>
 </div>
 
@@ -41,7 +46,7 @@
 <tbody>
     <tr>
         <td class="pki-select-column"><input id="profile_mapping_select" type="checkbox"><label for="profile_mapping_select">&nbsp;</label></td>
-        <td name="id"><a href="/tps/ui/profile-mappings/${id}">${id}</a></td>
+        <td name="id"><a href="#profile-mappings/${id}">${id}</a></td>
         <td name="status">${status}</td>
     </tr>
 </tbody>
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/profile.html b/base/tps-tomcat/shared/webapps/tps/ui/profile.html
index 52c4284f77ecd30d769229c55956a99f38425b70..e41444c9d68367a0feb47d0e78d29150e0c76490 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/profile.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/profile.html
@@ -16,8 +16,13 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li><a href="#profiles">Profiles</a></li>
+    <li class="active"><strong><span name="title">Profile ${id}</span></strong></li>
+</ol>
 
-<span class="pki-title">Profile <span name="id"></span></span>
+<span name="title" class="pki-title">Profile ${id}</span>
 
 <span class="pki-actions">
 
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/profiles.html b/base/tps-tomcat/shared/webapps/tps/ui/profiles.html
index 2bcc3e04c99ab8f1cf0d266c6257583b70f3e6fb..00218e5f7762edda97969b2f79bca2905d5d3523 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/profiles.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/profiles.html
@@ -16,6 +16,11 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li class="active"><strong>Profiles</strong></li>
+</ol>
+
 <span class="pki-title">Profiles</span>
 </div>
 
@@ -41,7 +46,7 @@
 <tbody>
     <tr>
         <td class="pki-select-column"><input id="profile_select" type="checkbox"><label for="profile_select">&nbsp;</label></td>
-        <td name="id"><a href="/tps/ui/profiles/${id}">${id}</a></td>
+        <td name="id"><a href="#profiles/${id}">${id}</a></td>
         <td name="status">${status}</td>
     </tr>
 </tbody>
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/selftest.html b/base/tps-tomcat/shared/webapps/tps/ui/selftest.html
index d61f056aaf5a12e905dc00e727a7ddd004339d01..8a680355a293b689dcac071a80dd2484c4c0e0d2 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/selftest.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/selftest.html
@@ -16,8 +16,13 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li><a href="#selftests">Self Tests</a></li>
+    <li class="active"><strong><span name="title">Self Test ${id}</span></strong></li>
+</ol>
 
-<span class="pki-title">Self Test <span name="id"></span></span>
+<span name="title" class="pki-title">Self Test ${id}</span>
 
 </div>
 
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/selftests.html b/base/tps-tomcat/shared/webapps/tps/ui/selftests.html
index 60796ca602f57ded47d0ddc16f03ada0c99db4d3..2b428e2d202f500b1a69ac6e581166c599a1db0b 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/selftests.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/selftests.html
@@ -16,6 +16,11 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li class="active"><strong>Self Tests</strong></li>
+</ol>
+
 <span class="pki-title">Self Tests</span>
 </div>
 
@@ -42,7 +47,7 @@
 <tbody>
     <tr>
         <td class="pki-select-column"><input id="selftest_select" type="checkbox"><label for="selftest_select">&nbsp;</label></td>
-        <td name="id"><a href="/tps/ui/selftest/${id}">${id}</a></td>
+        <td name="id"><a href="#selftests/${id}">${id}</a></td>
         <td name="enabledAtStartup">${enabledAtStartup}</td>
         <td name="criticalAtStartup">${criticalAtStartup}</td>
         <td name="enabledOnDemand">${enabledOnDemand}</td>
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/token.html b/base/tps-tomcat/shared/webapps/tps/ui/token.html
index 6f869a631c3d640cff840ea89f8f9931e67d26c9..247300af4bbdfcb66b1ef9261b9a1bb8ae459bc1 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/token.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/token.html
@@ -16,8 +16,13 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li><a href="#tokens">Tokens</a></li>
+    <li class="active"><strong><span name="title">Token ${id}</span></strong></li>
+</ol>
 
-<span class="pki-title">Token <span name="id"></span></span>
+<span name="title" class="pki-title">Token ${id}</span>
 
 <span class="pki-actions">
 
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/tokens.html b/base/tps-tomcat/shared/webapps/tps/ui/tokens.html
index 803b391963bc22416e91d0b375094bca1e66a7ae..e5f52105f6681f8cf9e0f6d84c8b688e9faf7148 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/tokens.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/tokens.html
@@ -16,6 +16,11 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li class="active"><strong>Tokens</strong></li>
+</ol>
+
 <span class="pki-title">Tokens</span>
 </div>
 
@@ -47,10 +52,10 @@
 <tbody>
     <tr>
         <td class="pki-select-column"><input id="token_select" type="checkbox"><label for="token_select">&nbsp;</label></td>
-        <td name="id"><a href="/tps/ui/tokens/${id}">${id}</a></td>
+        <td name="id"><a href="#tokens/${id}">${id}</a></td>
         <td name="userID">${userID}</td>
         <td name="type">${type}</td>
-        <td name="status"><a href="/tps/ui/tokens/${id}/status">${statusLabel}</a></td>
+        <td name="status"><a href="#tokens/${id}/status">${statusLabel}</a></td>
         <td name="appletID">${appletID}</td>
         <td name="keyInfo">${keyInfo}</td>
         <td name="created">${createTimestamp}</td>
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/user.html b/base/tps-tomcat/shared/webapps/tps/ui/user.html
index 459f3ee367f2072bafea6bfe3c33d1371a7ca971..8463d0bef18edd2af63ee8bf853834f19adf46b3 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/user.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/user.html
@@ -16,8 +16,13 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li><a href="#users">Users</a></li>
+    <li class="active"><strong><span name="title">User ${id}</span></strong></li>
+</ol>
 
-<span class="pki-title">User <span name="id"></span></span>
+<span name="title" class="pki-title">User ${id}</span>
 
 <span class="pki-actions">
 
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/users.html b/base/tps-tomcat/shared/webapps/tps/ui/users.html
index 9c9450a70b0b7e2a9d33afa70da9865d7ce2c158..18d59c9deef581717f6f27827b314d374adf2841 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/users.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/users.html
@@ -16,6 +16,11 @@
      All rights reserved.
      --- END COPYRIGHT BLOCK --- -->
 <div class="pki-header">
+<ol class="breadcrumb">
+    <li><a href="#">Home</a></li>
+    <li class="active"><strong>Users</strong></li>
+</ol>
+
 <span class="pki-title">Users</span>
 </div>
 
@@ -41,7 +46,7 @@
 <tbody>
     <tr>
         <td class="pki-select-column"><input id="user_select" type="checkbox"><label for="user_select">&nbsp;</label></td>
-        <td name="id"><a href="/tps/ui/users/${id}">${id}</a></td>
+        <td name="id"><a href="#users/${id}">${id}</a></td>
         <td name="fullName">${fullName}</td>
     </tr>
 </tbody>
-- 
1.8.4.2

