diff --git a/webgui/js/app/windows/AdminGroups.js b/webgui/js/app/windows/AdminGroups.js
new file mode 100644
index 0000000000000000000000000000000000000000..13f4decb1fca5ff2c65c9c421318ba8739093108
--- /dev/null
+++ b/webgui/js/app/windows/AdminGroups.js
@@ -0,0 +1,444 @@
+
+
+function showAdminGroupWindow() {
+
+	var AdminGroupWindow = new Ext.ux.GenericGridWindow(
+		// Window config
+		{
+			title: "Groups",
+			
+			width: 600,
+			height: 335,
+		
+			minWidth: 600,
+			minHeight: 335,
+		},
+		// Grid config
+		{
+			// Inline toolbars
+			tbar: [
+				{
+					text:'Add',
+					tooltip:'Add group',
+					iconCls:'add',
+					handler: function() {
+						showAdminGroupEditWindow();
+					}
+				}, 
+				'-', 
+				{
+					text:'Remove',
+					tooltip:'Remove group',
+					iconCls:'remove',
+					handler: function() {
+						var selectedItem = AdminGroupWindow.getComponent('gridpanel').getSelectionModel().getSelected();
+						// Check if we have selected item
+						if (selectedItem) {
+							// If so display window
+							showAdminGroupRemoveWindow(WiSPUserWindow,selectedItem.data.ID);
+						} else {
+							AdminGroupWindow.getEl().mask();
+
+							// Display error
+							Ext.Msg.show({
+								title: "Nothing selected",
+								msg: "No group selected",
+								icon: Ext.MessageBox.ERROR,
+								buttons: Ext.Msg.CANCEL,
+								modal: false,
+								fn: function() {
+									AdminGroupWindow.getEl().unmask();
+								}
+							});
+						}
+					}
+				},
+				'-',
+				{
+					text:'Attributes',
+					tooltip:'Group attributes',
+					iconCls:'logs',
+					handler: function() {
+						var selectedItem = AdminGroupWindow.getComponent('gridpanel').getSelectionModel().getSelected();
+						// Check if we have selected item
+						if (selectedItem) {
+							// If so display window
+							showAdminGroupAttributesWindow(selectedItem.data.ID);
+						} else {
+							AdminGroupWindow.getEl().mask();
+
+							// Display error
+							Ext.Msg.show({
+								title: "Nothing selected",
+								msg: "No group selected",
+								icon: Ext.MessageBox.ERROR,
+								buttons: Ext.Msg.CANCEL,
+								modal: false,
+								fn: function() {
+									AdminGroupWindow.getEl().unmask();
+								}
+							});
+						}
+					}
+				},
+				'-',
+				{
+					text:'Members',
+					tooltip:'Group members',
+					iconCls:'topups',
+					handler: function() {
+						var selectedItem = AdminGroupWindow.getComponent('gridpanel').getSelectionModel().getSelected();
+						// Check if we have selected item
+						if (selectedItem) {
+							// If so display window
+							showAdminGroupMembersWindow(selectedItem.data.ID);
+						} else {
+							AdminGroupWindow.getEl().mask();
+
+							// Display error
+							Ext.Msg.show({
+								title: "Nothing selected",
+								msg: "No group selected",
+								icon: Ext.MessageBox.ERROR,
+								buttons: Ext.Msg.CANCEL,
+								modal: false,
+								fn: function() {
+									AdminGroupWindow.getEl().unmask();
+								}
+							});
+						}
+					}
+				}
+			],
+			// Column model
+			colModel: new Ext.grid.ColumnModel([
+				{
+					id: 'ID',
+					header: "ID",
+					sortable: true,
+					dataIndex: 'ID'
+				},
+				{
+					header: "Name",
+					sortable: true,
+					dataIndex: 'Name'
+				},
+				{
+					header: "Priority",
+					sortable: true,
+					dataIndex: 'Priority'
+				},
+				{
+					header: "Disabled",
+					sortable: true,
+					dataIndex: 'Disabled'
+				},
+				{
+					header: "Comment",
+					sortable: true,
+					dataIndex: 'Comment'
+				}
+			]),
+			autoExpandColumn: 'Name'
+		},
+		// Store config
+		{
+			baseParams: {
+				SOAPUsername: globalConfig.soap.username,
+				SOAPPassword: globalConfig.soap.password,
+				SOAPAuthType: globalConfig.soap.authtype,
+				SOAPModule: 'AdminGroups',
+				SOAPFunction: 'getAdminGroups',
+				SOAPParams: '__null,__search'
+			}
+		},
+		// Filter config
+		{
+			filters: [
+				{type: 'numeric',  dataIndex: 'ID'},
+				{type: 'string',  dataIndex: 'Name'},
+				{type: 'numeric',  dataIndex: 'Priority'},
+				{type: 'boolean',  dataIndex: 'Disabled'},
+				{type: 'string', dataIndex: 'Comment'}
+			]
+		}
+	);
+
+	AdminGroupWindow.show();
+}
+
+
+// Display edit/add form
+function showAdminGroupEditWindow(id) {
+
+	var submitAjaxConfig;
+	var editMode;
+
+
+	// We doing an update
+	if (id) {
+		submitAjaxConfig = {
+			ID: id,
+			SOAPFunction: 'updateAdminGroup',
+			SOAPParams: 
+				'0:ID,'+
+				'0:UsageCap,'+
+				'0:AgentRef,'+
+				'0:AgentDisabled:boolean'
+		};
+		editMode = true;
+
+	// We doing an Add
+	} else {
+		submitAjaxConfig = {
+			SOAPFunction: 'createAdminGroup',
+			SOAPParams: 
+				'0:AgentID,'+
+				'0:GroupName,'+
+				'0:UsageCap,'+
+				'0:AgentRef,'+
+				'0:AgentDisabled:boolean'
+		};
+		editMode = false;
+	}
+	
+	// Service store
+	var serviceStore = new Ext.ux.JsonStore({
+		ID: id,
+		sortInfo: { field: "Name", direction: "ASC" },
+		baseParams: {
+			SOAPGroupname: globalConfig.soap.username,
+			SOAPPassword: globalConfig.soap.password,
+			SOAPAuthType: globalConfig.soap.authtype,
+			SOAPModule: 'AdminGroups',
+			SOAPFunction: 'getClasses',
+			AgentID: 1,
+			SOAPParams: '0:AgentID,__search'
+		}
+	});
+
+	// Create window
+	var wispGroupFormWindow = new Ext.ux.GenericFormWindow(
+		// Window config
+		{
+			title: "Group Information",
+
+			width: 475,
+			height: 260,
+
+			minWidth: 475,
+			minHeight: 260
+		},
+		// Form panel config
+		{
+			labelWidth: 85,
+			baseParams: {
+				SOAPGroupname: globalConfig.soap.username,
+				SOAPPassword: globalConfig.soap.password,
+				SOAPAuthType: globalConfig.soap.authtype,
+				SOAPModule: 'AdminGroups'
+			},
+			items: [
+				{
+					fieldLabel: 'Groupname',
+					name: 'Groupname',
+					vtype: 'usernamePart',
+					maskRe: usernamePartRe,
+					allowBlank: false,
+					
+					disabled: editMode
+				},
+
+				{
+					xtype: 'combo',
+
+					// We use an ID so we can get the box later
+					id: 'agent_combobox',
+
+					fieldLabel: 'Agent',
+					name: 'Agent',
+					allowBlank: false,
+					width: 225,
+
+					store: new Ext.ux.JsonStore({
+						ID: id,
+						sortInfo: { field: "Name", direction: "ASC" },
+						baseParams: {
+							SOAPGroupname: globalConfig.soap.username,
+							SOAPPassword: globalConfig.soap.password,
+							SOAPAuthType: globalConfig.soap.authtype,
+							SOAPModule: 'Agents',
+							SOAPFunction: 'getAgents',
+							SOAPParams: '__search'
+						}
+					}),
+					displayField: 'Name',
+					valueField: 'ID',
+					hiddenName: 'AgentID',
+
+					forceSelection: false,
+					triggerAction: 'all',
+					editable: false,
+
+					disabled: editMode
+				},
+
+				{
+					xtype: 'combo',
+
+					// We use an ID so we can get the box later
+					id: 'service_combobox',
+
+					fieldLabel: 'Service',
+					name: 'Service',
+					allowBlank: false,
+					width: 340,
+
+					store: serviceStore,
+
+					displayField: 'Service',
+					valueField: 'ID',
+					hiddenName: 'ClassID',
+
+					forceSelection: false,
+					triggerAction: 'all',
+					editable: false,
+
+					disabled: true
+				},
+
+				{
+					fieldLabel: 'Usage Cap',
+					name: 'UsageCap',
+				},
+
+				{
+					fieldLabel: 'Agent Ref',
+					name: 'AgentRef'
+				},
+
+				{
+					xtype: 'checkbox',
+					fieldLabel: 'Disabled',
+					name: 'AgentDisabled'
+				}/*,
+				{
+					xtype: 'tabpanel',
+					plain: 'true',
+					deferredRender: false, // Load all panels!
+					activeTab: 0,
+					height: 100,
+					defaults: {
+						layout: 'form',
+						bodyStyle: 'padding: 10px;'
+					},
+					
+					items: [
+						{
+							title: 'Policy Settings',
+							layout: 'form',
+							defaultType: 'textfield',
+							items: [
+								{
+									fieldLabel: 'Transport Policy',
+									name: 'Policy',
+									vtype: 'number',
+									value: '1'
+								}
+							]
+						}
+					]
+				}*/
+			],
+		},
+		// Submit button config
+		submitAjaxConfig
+	);
+
+	// Events
+	if (!id) {
+		wispGroupFormWindow.findById('agent_combobox').on({
+			select: {
+				fn: function() {
+					var tb = this.ownerCt.findById('service_combobox');
+
+					if (this.getValue()) {
+						tb.reset();
+						serviceStore.baseParams.AgentID = this.getValue();
+						serviceStore.reload();
+						tb.enable();
+					} else {
+						tb.reset();
+						tb.disable();
+					}
+				}
+			},
+		});
+	}
+	wispGroupFormWindow.show();
+
+	if (id) {
+		wispGroupFormWindow.getComponent('formpanel').load({
+			params: {
+				id: id,
+				SOAPGroupname: globalConfig.soap.username,
+				SOAPPassword: globalConfig.soap.password,
+				SOAPAuthType: globalConfig.soap.authtype,
+				SOAPModule: 'AdminGroups',
+				SOAPFunction: 'getAdminGroups',
+				SOAPParams: 'id'
+			}
+		});
+	}
+}
+
+
+
+
+// Display edit/add form
+function showAdminGroupRemoveWindow(parent,id) {
+	// Mask parent window
+	parent.getEl().mask();
+
+	// Display remove confirm window
+	Ext.Msg.show({
+		title: "Confirm removal",
+		msg: "Are you very sure you wish to remove this user?",
+		icon: Ext.MessageBox.ERROR,
+		buttons: Ext.Msg.YESNO,
+		modal: false,
+		fn: function(buttonId,text) {
+			// Check if user clicked on 'yes' button
+			if (buttonId == 'yes') {
+
+				// Do ajax request
+				uxAjaxRequest(parent,{
+					params: {
+						id: id,
+						SOAPGroupname: globalConfig.soap.username,
+						SOAPPassword: globalConfig.soap.password,
+						SOAPAuthType: globalConfig.soap.authtype,
+						SOAPModule: 'AdminGroups',
+						SOAPFunction: 'removeAdminGroup',
+						SOAPParams: 'id'
+					}
+				});
+
+
+			// Unmask if user answered no
+			} else {
+				parent.getEl().unmask();
+			}
+		}
+	});
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/webgui/js/app/windows/AdminRealms.js b/webgui/js/app/windows/AdminRealms.js
new file mode 100644
index 0000000000000000000000000000000000000000..99a1f92b2b8a1d45297f698640f9aa648f368dd9
--- /dev/null
+++ b/webgui/js/app/windows/AdminRealms.js
@@ -0,0 +1,404 @@
+
+
+function showAdminRealmWindow() {
+
+	var AdminRealmWindow = new Ext.ux.GenericGridWindow(
+		// Window config
+		{
+			title: "Realms",
+			
+			width: 600,
+			height: 335,
+		
+			minWidth: 600,
+			minHeight: 335,
+		},
+		// Grid config
+		{
+			// Inline toolbars
+			tbar: [
+				{
+					text:'Add',
+					tooltip:'Add realm',
+					iconCls:'add',
+					handler: function() {
+						showAdminRealmAddWindow();
+					}
+				}, 
+				'-',
+				{
+					text:'Remove',
+					tooltip:'Remove realm',
+					iconCls:'remove',
+					handler: function() {
+						var selectedItem = AdminRealmWindow.getComponent('gridpanel').getSelectionModel().getSelected();
+						// Check if we have selected item
+						if (selectedItem) {
+							// If so display window
+							showAdminRealmRemoveWindow(AdminRealmWindow,selectedItem.data.ID);
+						} else {
+							AdminRealmWindow.getEl().mask();
+
+							// Display error
+							Ext.Msg.show({
+								title: "Nothing selected",
+								msg: "No realm selected",
+								icon: Ext.MessageBox.ERROR,
+								buttons: Ext.Msg.CANCEL,
+								modal: false,
+								fn: function() {
+									AdminRealmWindow.getEl().unmask();
+								}
+							});
+						}
+					}
+				},
+				'-',
+				{
+					text:'Members',
+					tooltip:'Realm members',
+					iconCls:'logs',
+					handler: function() {
+						var selectedItem = AdminRealmWindow.getComponent('gridpanel').getSelectionModel().getSelected();
+						// Check if we have selected item
+						if (selectedItem) {
+							// If so display window
+							showAdminRealmMembersWindow(selectedItem.data.ID);
+						} else {
+							AdminRealmWindow.getEl().mask();
+
+							// Display error
+							Ext.Msg.show({
+								title: "Nothing selected",
+								msg: "No realm selected",
+								icon: Ext.MessageBox.ERROR,
+								buttons: Ext.Msg.CANCEL,
+								modal: false,
+								fn: function() {
+									AdminRealmWindow.getEl().unmask();
+								}
+							});
+						}
+					}
+				}
+			],
+			// Column model
+			colModel: new Ext.grid.ColumnModel([
+				{
+					id: 'ID',
+					header: "ID",
+					sortable: true,
+					dataIndex: 'ID'
+				},
+				{
+					header: "Name",
+					sortable: true,
+					dataIndex: 'Name'
+				},
+				{
+					header: "Disabled",
+					sortable: false,
+					dataIndex: 'Disabled'
+				}
+			]),
+			autoExpandColumn: 'Service'
+		},
+		// Store config
+		{
+			baseParams: {
+				SOAPUsername: globalConfig.soap.username,
+				SOAPPassword: globalConfig.soap.password,
+				SOAPAuthType: globalConfig.soap.authtype,
+				SOAPModule: 'AdminRealms',
+				SOAPFunction: 'getAdminRealms',
+				SOAPParams: '__null,__search'
+			}
+		},
+		// Filter config
+		{
+			filters: [
+				{type: 'numeric',  dataIndex: 'ID'},
+				{type: 'string',  dataIndex: 'Realmname'},
+				{type: 'boolean', dataIndex: 'Disabled'}
+			]
+		}
+	);
+
+	AdminRealmWindow.show();
+}
+
+
+// Display edit/add form
+function showAdminRealmEditWindow(id) {
+
+	var submitAjaxConfig;
+	var editMode;
+
+
+	// We doing an update
+	if (id) {
+		submitAjaxConfig = {
+			ID: id,
+			SOAPFunction: 'updateAdminRealm',
+			SOAPParams: 
+				'0:ID,'+
+				'0:UsageCap,'+
+				'0:AgentRef,'+
+				'0:AgentDisabled:boolean'
+		};
+		editMode = true;
+
+	// We doing an Add
+	} else {
+		submitAjaxConfig = {
+			SOAPFunction: 'createAdminRealm',
+			SOAPParams: 
+				'0:AgentID,'+
+				'0:RealmName,'+
+				'0:UsageCap,'+
+				'0:AgentRef,'+
+				'0:AgentDisabled:boolean'
+		};
+		editMode = false;
+	}
+	
+	// Service store
+	var serviceStore = new Ext.ux.JsonStore({
+		ID: id,
+		sortInfo: { field: "Name", direction: "ASC" },
+		baseParams: {
+			SOAPUsername: globalConfig.soap.username,
+			SOAPPassword: globalConfig.soap.password,
+			SOAPAuthType: globalConfig.soap.authtype,
+			SOAPModule: 'AdminRealms',
+			SOAPFunction: 'getClasses',
+			AgentID: 1,
+			SOAPParams: '0:AgentID,__search'
+		}
+	});
+
+	// Create window
+	var adminRealmFormWindow = new Ext.ux.GenericFormWindow(
+		// Window config
+		{
+			title: "Realm Information",
+
+			width: 475,
+			height: 260,
+
+			minWidth: 475,
+			minHeight: 260
+		},
+		// Form panel config
+		{
+			labelWidth: 85,
+			baseParams: {
+				SOAPUsername: globalConfig.soap.username,
+				SOAPPassword: globalConfig.soap.password,
+				SOAPAuthType: globalConfig.soap.authtype,
+				SOAPModule: 'AdminRealms'
+			},
+			items: [
+				{
+					fieldLabel: 'Realmname',
+					name: 'Realmname',
+					vtype: 'usernamePart',
+					maskRe: usernamePartRe,
+					allowBlank: false,
+					
+					disabled: editMode
+				},
+
+				{
+					xtype: 'combo',
+
+					// We use an ID so we can get the box later
+					id: 'agent_combobox',
+
+					fieldLabel: 'Agent',
+					name: 'Agent',
+					allowBlank: false,
+					width: 225,
+
+					store: new Ext.ux.JsonStore({
+						ID: id,
+						sortInfo: { field: "Name", direction: "ASC" },
+						baseParams: {
+							SOAPUsername: globalConfig.soap.username,
+							SOAPPassword: globalConfig.soap.password,
+							SOAPAuthType: globalConfig.soap.authtype,
+							SOAPModule: 'Agents',
+							SOAPFunction: 'getAgents',
+							SOAPParams: '__search'
+						}
+					}),
+					displayField: 'Name',
+					valueField: 'ID',
+					hiddenName: 'AgentID',
+
+					forceSelection: false,
+					triggerAction: 'all',
+					editable: false,
+
+					disabled: editMode
+				},
+
+				{
+					xtype: 'combo',
+
+					// We use an ID so we can get the box later
+					id: 'service_combobox',
+
+					fieldLabel: 'Service',
+					name: 'Service',
+					allowBlank: false,
+					width: 340,
+
+					store: serviceStore,
+
+					displayField: 'Service',
+					valueField: 'ID',
+					hiddenName: 'ClassID',
+
+					forceSelection: false,
+					triggerAction: 'all',
+					editable: false,
+
+					disabled: true
+				},
+
+				{
+					fieldLabel: 'Usage Cap',
+					name: 'UsageCap',
+				},
+
+				{
+					fieldLabel: 'Agent Ref',
+					name: 'AgentRef'
+				},
+
+				{
+					xtype: 'checkbox',
+					fieldLabel: 'Disabled',
+					name: 'AgentDisabled'
+				}/*,
+				{
+					xtype: 'tabpanel',
+					plain: 'true',
+					deferredRender: false, // Load all panels!
+					activeTab: 0,
+					height: 100,
+					defaults: {
+						layout: 'form',
+						bodyStyle: 'padding: 10px;'
+					},
+					
+					items: [
+						{
+							title: 'Policy Settings',
+							layout: 'form',
+							defaultType: 'textfield',
+							items: [
+								{
+									fieldLabel: 'Transport Policy',
+									name: 'Policy',
+									vtype: 'number',
+									value: '1'
+								}
+							]
+						}
+					]
+				}*/
+			],
+		},
+		// Submit button config
+		submitAjaxConfig
+	);
+
+	// Events
+	if (!id) {
+		adminRealmFormWindow.findById('agent_combobox').on({
+			select: {
+				fn: function() {
+					var tb = this.ownerCt.findById('service_combobox');
+
+					if (this.getValue()) {
+						tb.reset();
+						serviceStore.baseParams.AgentID = this.getValue();
+						serviceStore.reload();
+						tb.enable();
+					} else {
+						tb.reset();
+						tb.disable();
+					}
+				}
+			},
+		});
+	}
+	adminRealmFormWindow.show();
+
+	if (id) {
+		adminRealmFormWindow.getComponent('formpanel').load({
+			params: {
+				id: id,
+				SOAPUsername: globalConfig.soap.username,
+				SOAPPassword: globalConfig.soap.password,
+				SOAPAuthType: globalConfig.soap.authtype,
+				SOAPModule: 'AdminRealms',
+				SOAPFunction: 'getAdminRealm',
+				SOAPParams: 'id'
+			}
+		});
+	}
+}
+
+
+
+
+// Display edit/add form
+function showAdminRealmRemoveWindow(parent,id) {
+	// Mask parent window
+	parent.getEl().mask();
+
+	// Display remove confirm window
+	Ext.Msg.show({
+		title: "Confirm removal",
+		msg: "Are you very sure you wish to remove this user?",
+		icon: Ext.MessageBox.ERROR,
+		buttons: Ext.Msg.YESNO,
+		modal: false,
+		fn: function(buttonId,text) {
+			// Check if user clicked on 'yes' button
+			if (buttonId == 'yes') {
+
+				// Do ajax request
+				uxAjaxRequest(parent,{
+					params: {
+						id: id,
+						SOAPUsername: globalConfig.soap.username,
+						SOAPPassword: globalConfig.soap.password,
+						SOAPAuthType: globalConfig.soap.authtype,
+						SOAPModule: 'AdminRealms',
+						SOAPFunction: 'removeAdminRealm',
+						SOAPParams: 'id'
+					}
+				});
+
+
+			// Unmask if user answered no
+			} else {
+				parent.getEl().unmask();
+			}
+		}
+	});
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/webgui/js/app/windows/AdminUserLogs.js b/webgui/js/app/windows/AdminUserLogs.js
new file mode 100644
index 0000000000000000000000000000000000000000..f71bcf6b35974a4f6d4b6172fdb6295d8791eeac
--- /dev/null
+++ b/webgui/js/app/windows/AdminUserLogs.js
@@ -0,0 +1,287 @@
+
+
+function showWiSPUserLogsWindow(wispUserID) {
+	// Calculate dates we going to need
+	var today = new Date();
+	var firstOfMonth = today.getFirstDateOfMonth();
+	var firstOfNext = today.getLastDateOfMonth().add(Date.DAY, 1);
+	
+	var wispUserLogsWindow = new Ext.ux.GenericGridWindow(
+		// Window config
+		{
+			title: 'User Logs',
+			layout:'border',
+			height: 480,
+			width: 700,
+			minHeight: 480,
+			minWidth: 700,
+			closable: true,
+			plain: true,
+			uxItems: [
+				{
+					xtype: 'form',
+					id: 'search-form',
+					title: 'Search',
+					region: 'west',
+					border: true,
+					frame: true,
+					defaultType: 'datefield',
+					height: 180,
+					width: 300,
+					labelWidth: 100,
+					items: [
+						{
+							id: 'after',
+							name: 'after',
+							width: 180,
+							fieldLabel: 'From',
+							vtype: 'daterange',
+							format: 'Y-m-d',
+							value: firstOfMonth,
+							endDateField: 'before',
+						},
+						{
+							id: 'before',
+							name: 'before',
+							width: 180,
+							fieldLabel: 'To',
+							vtype: 'daterange',
+							format: 'Y-m-d',
+							value: firstOfNext,
+							startDateField: 'after'
+						}
+					],
+					buttons: [
+						{
+							text: 'Search',
+							id: 'formbtn',
+							handler: function() {
+								// Pull in window, grid & form	
+								var mainWindow = this.ownerCt.ownerCt;
+								var grid = mainWindow.getComponent('gridpanel');
+								var form = mainWindow.getComponent('search-form');
+
+								// Grab store
+								var store = grid.getStore();
+
+								// Grab timestamp filter
+								var gridFilters = grid.filters;
+								var timestampFilter = gridFilters.getFilter('Timestamp');
+
+								// Grab	form fields
+								var afterField = form.getForm().findField('after');
+								var beforeField = form.getForm().findField('before');
+
+								// Set filter values from form
+								timestampFilter.setValue({
+									after: afterField.getValue(),
+									before: beforeField.getValue()
+								});
+
+								// Trigger store reload
+								store.reload();
+							}
+						}
+					],
+					buttonAlign: 'center'
+				},
+				{
+					xtype: 'form',
+					id: 'summary-form',
+					region: 'center',
+					split: true,
+					border: true,
+					autoScroll: true,
+					defaultType: 'textarea',
+					height: 180,
+					width: 400,
+					labelWidth: 80,
+					items: [
+						{
+							id: 'summaryTotal',
+							name: 'summaryTotal',
+							readOnly: true,
+							height: 135,
+							width: 200,
+							fieldLabel: 'Summary',
+							fieldClass: 'font-family: monospace; font-size: 10px;',
+							value: ''
+						}
+					]					
+				}
+			]
+		},
+		// Grid config
+		{
+			region: 'south',
+			width: 700,
+			border: true,
+			tbar: [
+				{
+					text: 'Add Port Lock',
+					tooltip: 'Add port lock',
+					iconCls: 'add'
+				}	
+			],
+			// Column model
+			colModel: new Ext.grid.ColumnModel([
+				{
+					id: 'ID',
+					header: "ID",
+					hidden: true,
+					dataIndex: 'ID'
+				},
+				{
+					header: "Username",
+					hidden: true,
+					dataIndex: 'Username'
+				},
+				{
+					header: "Status",
+					sortable: true,
+					hidden: true,
+					dataIndex: 'Status'
+				},
+				{
+					header: "Timestamp",
+					sortable: true,
+					dataIndex: 'Timestamp'
+				},
+				{
+					header: "Session ID",
+					hidden: true,
+					dataIndex: 'AcctSessionID'
+				},
+				{
+					header: "Session Time",
+					dataIndex: 'AcctSessionTime'
+				},
+				{
+					header: "NAS IP",
+					hidden: true,
+					dataIndex: 'NASIPAddress'
+				},
+				{
+					header: "Port Type",
+					hidden: true,
+					dataIndex: 'NASPortType'
+				},
+				{
+					header: "NAS Port",
+					dataIndex: 'NASPort'
+				},
+				{
+					header: "Called Station",
+					hidden: true,
+					dataIndex: 'CalledStationID'
+				},
+				{
+					header: "Calling Station",
+					sortable: true,
+					dataIndex: 'CallingStationID'
+				},
+				{
+					header: "NAS Xmit Rate",
+					dataIndex: 'NASTransmitRate'
+				},
+				{
+					header: "NAS Recv Rate",
+					hidden: true,
+					dataIndex: 'NASReceiveRate'
+				},
+				{
+					header: "IP Address",
+					hidden: true,
+					dataIndex: 'FramedIPAddress'
+				},
+				{
+					header: "Input Mbyte",
+					dataIndex: 'AcctInputMbyte'
+				},
+				{
+					header: "Output Mbyte",
+					dataIndex: 'AcctOutputMbyte'
+				},
+				{
+					header: "Last Update",
+					hidden: true,
+					dataIndex: 'LastAcctUpdate'
+				},
+				{
+					header: "Term. Reason",
+					dataIndex: 'ConnectTermReason'
+				}
+			])
+		},
+		// Store config
+		{
+			baseParams: {
+				SOAPUsername: globalConfig.soap.username,
+				SOAPPassword: globalConfig.soap.password,
+				SOAPAuthType: globalConfig.soap.authtype,
+				SOAPModule: 'WiSPUsers',
+				SOAPFunction: 'getWiSPUserLogs',
+				SOAPParams: '0:UserID,__search',
+				UserID: wispUserID
+			}
+		},
+		// Filter config
+		{
+			filters: [
+				{type: 'numeric',  dataIndex: 'ID'},
+				{type: 'string',  dataIndex: 'Username'},
+				{type: 'numeric',  dataIndex: 'Status'},
+				{
+					type: 'date',  
+					dataIndex: 'Timestamp', 
+					value: {
+						after: firstOfMonth,
+						before: firstOfNext
+					}
+				},
+
+				{type: 'string',  dataIndex: 'AcctSessionID'},
+				{type: 'numeric',  dataIndex: 'AcctSessionTime'},
+
+				{type: 'string',  dataIndex: 'NASIPAddress'},
+				{type: 'string',  dataIndex: 'NASPortType'},
+				{type: 'string',  dataIndex: 'NASPort'},
+				{type: 'string',  dataIndex: 'CalledStationID'},
+				{type: 'string',  dataIndex: 'CallingStationID'},
+
+				{type: 'string',  dataIndex: 'NASTransmitRate'},
+				{type: 'string',  dataIndex: 'NASReceiveRate'},
+
+				{type: 'string',  dataIndex: 'FramedIPAddress'},
+
+				{type: 'date',  dataIndex: 'LastAcctUpdate'},
+
+				{type: 'string',  dataIndex: 'ConnectTermReason'}
+			]
+		}
+	);
+	// Grab store
+	var store = wispUserLogsWindow.getComponent('gridpanel').getStore();
+
+	store.on('load',function() {
+		var inputTotal = store.sum('AcctInputMbyte');
+		var outputTotal = store.sum('AcctOutputMbyte');
+
+		var userCap = 3000;
+		var userTopups = 1000;
+		
+		// Total up into this ... 
+		
+		var userTotalAllowed = userCap + userTopups;
+		var userUsage = inputTotal + outputTotal;
+		var userLeft = userTotalAllowed - userUsage;
+
+		var form = wispUserLogsWindow.getComponent('summary-form');
+		var summaryTotal = form.getForm().findField('summaryTotal');
+
+		summaryTotal.setValue(
+				sprintf('Cap Total: %6d\nTopups   : %6d\n-----------------\n           %6d\n-----------------\nUsage    : %6d\n=================\nAvailable: %6d',userCap,userTopups,userTotalAllowed,userUsage,userLeft)
+		);
+	});
+	wispUserLogsWindow.show();				
+}
diff --git a/webgui/js/app/windows/AdminUsers.js b/webgui/js/app/windows/AdminUsers.js
new file mode 100644
index 0000000000000000000000000000000000000000..74438efc5c69211f525eab221612c398d6847a6c
--- /dev/null
+++ b/webgui/js/app/windows/AdminUsers.js
@@ -0,0 +1,460 @@
+
+
+function showAdminUserWindow() {
+
+	var AdminUserWindow = new Ext.ux.GenericGridWindow(
+		// Window config
+		{
+			title: "Users",
+			
+			width: 600,
+			height: 335,
+		
+			minWidth: 600,
+			minHeight: 335,
+		},
+		// Grid config
+		{
+			// Inline toolbars
+			tbar: [
+				{
+					text:'Add',
+					tooltip:'Add user',
+					iconCls:'add',
+					handler: function() {
+						showAdminUserEditWindow();
+					}
+				}, 
+				'-', 
+				{
+					text:'Edit',
+					tooltip:'Edit user',
+					iconCls:'option',
+					handler: function() {
+						var selectedItem = AdminUserWindow.getComponent('gridpanel').getSelectionModel().getSelected();
+						// Check if we have selected item
+						if (selectedItem) {
+							// If so display window
+							showAdminUserEditWindow(selectedItem.data.ID);
+						} else {
+							AdminUserWindow.getEl().mask();
+
+							// Display error
+							Ext.Msg.show({
+								title: "Nothing selected",
+								msg: "No user selected",
+								icon: Ext.MessageBox.ERROR,
+								buttons: Ext.Msg.CANCEL,
+								modal: false,
+								fn: function() {
+									AdminUserWindow.getEl().unmask();
+								}
+							});
+						}
+					}
+				},
+				'-',
+				{
+					text:'Remove',
+					tooltip:'Remove user',
+					iconCls:'remove',
+					handler: function() {
+						var selectedItem = AdminUserWindow.getComponent('gridpanel').getSelectionModel().getSelected();
+						// Check if we have selected item
+						if (selectedItem) {
+							// If so display window
+							showAdminUserRemoveWindow(AdminUserWindow,selectedItem.data.ID);
+						} else {
+							AdminUserWindow.getEl().mask();
+
+							// Display error
+							Ext.Msg.show({
+								title: "Nothing selected",
+								msg: "No user selected",
+								icon: Ext.MessageBox.ERROR,
+								buttons: Ext.Msg.CANCEL,
+								modal: false,
+								fn: function() {
+									AdminUserWindow.getEl().unmask();
+								}
+							});
+						}
+					}
+				},
+				'-',
+				{
+					text:'Logs',
+					tooltip:'User logs',
+					iconCls:'logs',
+					handler: function() {
+						var selectedItem = AdminUserWindow.getComponent('gridpanel').getSelectionModel().getSelected();
+						// Check if we have selected item
+						if (selectedItem) {
+							// If so display window
+							showAdminUserLogsWindow(selectedItem.data.ID);
+						} else {
+							AdminUserWindow.getEl().mask();
+
+							// Display error
+							Ext.Msg.show({
+								title: "Nothing selected",
+								msg: "No user selected",
+								icon: Ext.MessageBox.ERROR,
+								buttons: Ext.Msg.CANCEL,
+								modal: false,
+								fn: function() {
+									AdminUserWindow.getEl().unmask();
+								}
+							});
+						}
+					}
+				},
+				'-',
+				{
+					text:'Groups',
+					tooltip:'User groups',
+					iconCls:'topups',
+					handler: function() {
+						var selectedItem = AdminUserWindow.getComponent('gridpanel').getSelectionModel().getSelected();
+						// Check if we have selected item
+						if (selectedItem) {
+							// If so display window
+							showAdminUserGroupsWindow(selectedItem.data.ID);
+						} else {
+							AdminUserWindow.getEl().mask();
+
+							// Display error
+							Ext.Msg.show({
+								title: "Nothing selected",
+								msg: "No user selected",
+								icon: Ext.MessageBox.ERROR,
+								buttons: Ext.Msg.CANCEL,
+								modal: false,
+								fn: function() {
+									AdminUserWindow.getEl().unmask();
+								}
+							});
+						}
+					}
+				}
+			],
+			// Column model
+			colModel: new Ext.grid.ColumnModel([
+				{
+					id: 'ID',
+					header: "ID",
+					sortable: true,
+					dataIndex: 'ID'
+				},
+				{
+					header: "Username",
+					sortable: true,
+					dataIndex: 'Username'
+				},
+				{
+					header: "Disabled",
+					sortable: false,
+					dataIndex: 'Disabled'
+				}
+			]),
+			autoExpandColumn: 'Service'
+		},
+		// Store config
+		{
+			baseParams: {
+				SOAPUsername: globalConfig.soap.username,
+				SOAPPassword: globalConfig.soap.password,
+				SOAPAuthType: globalConfig.soap.authtype,
+				SOAPModule: 'AdminUsers',
+				SOAPFunction: 'getAdminUsers',
+				SOAPParams: '__null,__search'
+			}
+		},
+		// Filter config
+		{
+			filters: [
+				{type: 'numeric',  dataIndex: 'ID'},
+				{type: 'string',  dataIndex: 'Username'},
+				{type: 'boolean', dataIndex: 'Disabled'}
+			]
+		}
+	);
+
+	AdminUserWindow.show();
+}
+
+
+// Display edit/add form
+function showAdminUserEditWindow(id) {
+
+	var submitAjaxConfig;
+	var editMode;
+
+
+	// We doing an update
+	if (id) {
+		submitAjaxConfig = {
+			ID: id,
+			SOAPFunction: 'updateAdminUser',
+			SOAPParams: 
+				'0:ID,'+
+				'0:UsageCap,'+
+				'0:AgentRef,'+
+				'0:AgentDisabled:boolean'
+		};
+		editMode = true;
+
+	// We doing an Add
+	} else {
+		submitAjaxConfig = {
+			SOAPFunction: 'createAdminUser',
+			SOAPParams: 
+				'0:AgentID,'+
+				'0:UserName,'+
+				'0:UsageCap,'+
+				'0:AgentRef,'+
+				'0:AgentDisabled:boolean'
+		};
+		editMode = false;
+	}
+	
+	// Service store
+	var serviceStore = new Ext.ux.JsonStore({
+		ID: id,
+		sortInfo: { field: "Name", direction: "ASC" },
+		baseParams: {
+			SOAPUsername: globalConfig.soap.username,
+			SOAPPassword: globalConfig.soap.password,
+			SOAPAuthType: globalConfig.soap.authtype,
+			SOAPModule: 'AdminUsers',
+			SOAPFunction: 'getClasses',
+			AgentID: 1,
+			SOAPParams: '0:AgentID,__search'
+		}
+	});
+
+	// Create window
+	var adminUserFormWindow = new Ext.ux.GenericFormWindow(
+		// Window config
+		{
+			title: "User Information",
+
+			width: 475,
+			height: 260,
+
+			minWidth: 475,
+			minHeight: 260
+		},
+		// Form panel config
+		{
+			labelWidth: 85,
+			baseParams: {
+				SOAPUsername: globalConfig.soap.username,
+				SOAPPassword: globalConfig.soap.password,
+				SOAPAuthType: globalConfig.soap.authtype,
+				SOAPModule: 'AdminUsers'
+			},
+			items: [
+				{
+					fieldLabel: 'Username',
+					name: 'Username',
+					vtype: 'usernamePart',
+					maskRe: usernamePartRe,
+					allowBlank: false,
+					
+					disabled: editMode
+				},
+
+				{
+					xtype: 'combo',
+
+					// We use an ID so we can get the box later
+					id: 'agent_combobox',
+
+					fieldLabel: 'Agent',
+					name: 'Agent',
+					allowBlank: false,
+					width: 225,
+
+					store: new Ext.ux.JsonStore({
+						ID: id,
+						sortInfo: { field: "Name", direction: "ASC" },
+						baseParams: {
+							SOAPUsername: globalConfig.soap.username,
+							SOAPPassword: globalConfig.soap.password,
+							SOAPAuthType: globalConfig.soap.authtype,
+							SOAPModule: 'Agents',
+							SOAPFunction: 'getAgents',
+							SOAPParams: '__search'
+						}
+					}),
+					displayField: 'Name',
+					valueField: 'ID',
+					hiddenName: 'AgentID',
+
+					forceSelection: false,
+					triggerAction: 'all',
+					editable: false,
+
+					disabled: editMode
+				},
+
+				{
+					xtype: 'combo',
+
+					// We use an ID so we can get the box later
+					id: 'service_combobox',
+
+					fieldLabel: 'Service',
+					name: 'Service',
+					allowBlank: false,
+					width: 340,
+
+					store: serviceStore,
+
+					displayField: 'Service',
+					valueField: 'ID',
+					hiddenName: 'ClassID',
+
+					forceSelection: false,
+					triggerAction: 'all',
+					editable: false,
+
+					disabled: true
+				},
+
+				{
+					fieldLabel: 'Usage Cap',
+					name: 'UsageCap',
+				},
+
+				{
+					fieldLabel: 'Agent Ref',
+					name: 'AgentRef'
+				},
+
+				{
+					xtype: 'checkbox',
+					fieldLabel: 'Disabled',
+					name: 'AgentDisabled'
+				}/*,
+				{
+					xtype: 'tabpanel',
+					plain: 'true',
+					deferredRender: false, // Load all panels!
+					activeTab: 0,
+					height: 100,
+					defaults: {
+						layout: 'form',
+						bodyStyle: 'padding: 10px;'
+					},
+					
+					items: [
+						{
+							title: 'Policy Settings',
+							layout: 'form',
+							defaultType: 'textfield',
+							items: [
+								{
+									fieldLabel: 'Transport Policy',
+									name: 'Policy',
+									vtype: 'number',
+									value: '1'
+								}
+							]
+						}
+					]
+				}*/
+			],
+		},
+		// Submit button config
+		submitAjaxConfig
+	);
+
+	// Events
+	if (!id) {
+		adminUserFormWindow.findById('agent_combobox').on({
+			select: {
+				fn: function() {
+					var tb = this.ownerCt.findById('service_combobox');
+
+					if (this.getValue()) {
+						tb.reset();
+						serviceStore.baseParams.AgentID = this.getValue();
+						serviceStore.reload();
+						tb.enable();
+					} else {
+						tb.reset();
+						tb.disable();
+					}
+				}
+			},
+		});
+	}
+	adminUserFormWindow.show();
+
+	if (id) {
+		adminUserFormWindow.getComponent('formpanel').load({
+			params: {
+				id: id,
+				SOAPUsername: globalConfig.soap.username,
+				SOAPPassword: globalConfig.soap.password,
+				SOAPAuthType: globalConfig.soap.authtype,
+				SOAPModule: 'AdminUsers',
+				SOAPFunction: 'getAdminUser',
+				SOAPParams: 'id'
+			}
+		});
+	}
+}
+
+
+
+
+// Display edit/add form
+function showAdminUserRemoveWindow(parent,id) {
+	// Mask parent window
+	parent.getEl().mask();
+
+	// Display remove confirm window
+	Ext.Msg.show({
+		title: "Confirm removal",
+		msg: "Are you very sure you wish to remove this user?",
+		icon: Ext.MessageBox.ERROR,
+		buttons: Ext.Msg.YESNO,
+		modal: false,
+		fn: function(buttonId,text) {
+			// Check if user clicked on 'yes' button
+			if (buttonId == 'yes') {
+
+				// Do ajax request
+				uxAjaxRequest(parent,{
+					params: {
+						id: id,
+						SOAPUsername: globalConfig.soap.username,
+						SOAPPassword: globalConfig.soap.password,
+						SOAPAuthType: globalConfig.soap.authtype,
+						SOAPModule: 'AdminUsers',
+						SOAPFunction: 'removeAdminUser',
+						SOAPParams: 'id'
+					}
+				});
+
+
+			// Unmask if user answered no
+			} else {
+				parent.getEl().unmask();
+			}
+		}
+	});
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/webgui/js/app/windows/WiSPLocations.js b/webgui/js/app/windows/WiSPLocations.js
new file mode 100644
index 0000000000000000000000000000000000000000..5cf9c0518bddf04b51510ec3d6aced27daad6145
--- /dev/null
+++ b/webgui/js/app/windows/WiSPLocations.js
@@ -0,0 +1,175 @@
+
+
+function showWiSPLocationWindow() {
+
+	var WiSPLocationWindow = new Ext.ux.GenericGridWindow(
+		// Window config
+		{
+			title: "Locations",
+			
+			width: 600,
+			height: 335,
+		
+			minWidth: 600,
+			minHeight: 335,
+		},
+		// Grid config
+		{
+			// Inline toolbars
+			tbar: [
+				{
+					text:'Add',
+					tooltip:'Add location',
+					iconCls:'add',
+					handler: function() {
+						showWiSPLocationEditWindow();
+					}
+				}, 
+				'-',
+				{
+					text:'Remove',
+					tooltip:'Remove location',
+					iconCls:'remove',
+					handler: function() {
+						var selectedItem = WiSPLocationWindow.getComponent('gridpanel').getSelectionModel().getSelected();
+						// Check if we have selected item
+						if (selectedItem) {
+							// If so display window
+							showWiSPLocationRemoveWindow(WiSPLocationWindow,selectedItem.data.ID);
+						} else {
+							WiSPLocationWindow.getEl().mask();
+
+							// Display error
+							Ext.Msg.show({
+								title: "Nothing selected",
+								msg: "No location selected",
+								icon: Ext.MessageBox.ERROR,
+								buttons: Ext.Msg.CANCEL,
+								modal: false,
+								fn: function() {
+									WiSPLocationWindow.getEl().unmask();
+								}
+							});
+						}
+					}
+				},
+				'-',
+				{
+					text:'Members',
+					tooltip:'List members',
+					iconCls:'remove',
+					handler: function() {
+						var selectedItem = WiSPLocationWindow.getComponent('gridpanel').getSelectionModel().getSelected();
+						// Check if we have selected item
+						if (selectedItem) {
+							// If so display window
+							showWiSPLocationMembersWindow(WiSPLocationWindow,selectedItem.data.ID);
+						} else {
+							WiSPLocationWindow.getEl().mask();
+
+							// Display error
+							Ext.Msg.show({
+								title: "Nothing selected",
+								msg: "No user selected",
+								icon: Ext.MessageBox.ERROR,
+								buttons: Ext.Msg.CANCEL,
+								modal: false,
+								fn: function() {
+									WiSPLocationWindow.getEl().unmask();
+								}
+							});
+						}
+					}
+				}
+			],
+			// Column model
+			colModel: new Ext.grid.ColumnModel([
+				{
+					id: 'ID',
+					header: "ID",
+					sortable: true,
+					dataIndex: 'ID'
+				},
+				{
+					header: "Name",
+					sortable: true,
+					dataIndex: 'Name'
+				}
+			]),
+			autoExpandColumn: 'Name'
+		},
+		// Store config
+		{
+			baseParams: {
+				SOAPUsername: globalConfig.soap.username,
+				SOAPPassword: globalConfig.soap.password,
+				SOAPAuthType: globalConfig.soap.authtype,
+				SOAPModule: 'WiSPLocations',
+				SOAPFunction: 'getLocations',
+				SOAPParams: '__null,__search'
+			}
+		},
+		// Filter config
+		{
+			filters: [
+				{type: 'numeric',  dataIndex: 'ID'},
+				{type: 'string',  dataIndex: 'Name'}
+			]
+		}
+	);
+
+	WiSPLocationWindow.show();
+}
+
+
+
+
+
+
+// Display remove form
+function showWiSPLocationRemoveWindow(parent,id) {
+	// Mask parent window
+	parent.getEl().mask();
+
+	// Display remove confirm window
+	Ext.Msg.show({
+		title: "Confirm removal",
+		msg: "Are you very sure you wish to remove this user?",
+		icon: Ext.MessageBox.ERROR,
+		buttons: Ext.Msg.YESNO,
+		modal: false,
+		fn: function(buttonId,text) {
+			// Check if user clicked on 'yes' button
+			if (buttonId == 'yes') {
+
+				// Do ajax request
+				uxAjaxRequest(parent,{
+					params: {
+						id: id,
+						SOAPUsername: globalConfig.soap.username,
+						SOAPPassword: globalConfig.soap.password,
+						SOAPAuthType: globalConfig.soap.authtype,
+						SOAPModule: 'WiSPUsers',
+						SOAPFunction: 'removeWiSPUser',
+						SOAPParams: 'id'
+					}
+				});
+
+
+			// Unmask if user answered no
+			} else {
+				parent.getEl().unmask();
+			}
+		}
+	});
+}
+
+
+
+
+
+
+
+
+
+