From 3f5a936d62df428a713a04ff0436388c73e3c003 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Fri, 28 Oct 2011 08:09:24 -0400
Subject: [PATCH] New login/edit registration dialog. Added url to status panel.

---
 src/com/gitblit/client/RegistrationsDialog.java    |   74 ++++++--
 src/com/gitblit/client/EditRegistrationDialog.java |  196 ++++++++++++++++++++++++
 src/com/gitblit/client/GitblitPanel.java           |    2 
 src/com/gitblit/client/DateCellRenderer.java       |   12 +
 src/com/gitblit/client/StatusPanel.java            |   12 +
 src/com/gitblit/client/GitblitManager.java         |  127 ++++++---------
 src/com/gitblit/client/GitblitRegistration.java    |    6 
 7 files changed, 324 insertions(+), 105 deletions(-)

diff --git a/src/com/gitblit/client/DateCellRenderer.java b/src/com/gitblit/client/DateCellRenderer.java
index 053cf52..f30b05f 100644
--- a/src/com/gitblit/client/DateCellRenderer.java
+++ b/src/com/gitblit/client/DateCellRenderer.java
@@ -49,8 +49,16 @@
 		super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
 		if (value instanceof Date) {
 			Date date = (Date) value;
-			String timeAgo = TimeUtils.timeAgo(date);
-			String strDate = new SimpleDateFormat(pattern).format((Date) value);
+			String timeAgo;
+			String strDate;
+			if (date.getTime() == 0) {
+				timeAgo = "--";
+				strDate = "never";
+			} else {
+				timeAgo = TimeUtils.timeAgo(date);
+				strDate = new SimpleDateFormat(pattern).format((Date) value);
+			}
+
 			this.setText(timeAgo);
 			this.setToolTipText(strDate);
 		}
diff --git a/src/com/gitblit/client/EditRegistrationDialog.java b/src/com/gitblit/client/EditRegistrationDialog.java
new file mode 100644
index 0000000..99cd36f
--- /dev/null
+++ b/src/com/gitblit/client/EditRegistrationDialog.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2011 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.client;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GridLayout;
+import java.awt.Insets;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.JRootPane;
+import javax.swing.JTextField;
+import javax.swing.KeyStroke;
+
+import com.gitblit.utils.StringUtils;
+
+/**
+ * Dialog to create or edit a Gitblit registration.
+ * 
+ * @author James Moger
+ * 
+ */
+public class EditRegistrationDialog extends JDialog {
+
+	private static final long serialVersionUID = 1L;
+	private JTextField urlField;
+	private JTextField nameField;
+	private JTextField accountField;
+	private JPasswordField passwordField;
+	private JCheckBox savePassword;
+	private boolean canceled;
+	private HeaderPanel headerPanel;
+
+	public EditRegistrationDialog(Window owner) {
+		this(owner, null, false);
+	}
+
+	public EditRegistrationDialog(Window owner, GitblitRegistration reg, boolean isLogin) {
+		super(owner);
+		initialize(reg, isLogin);
+	}
+
+	@Override
+	protected JRootPane createRootPane() {
+		KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
+		JRootPane rootPane = new JRootPane();
+		rootPane.registerKeyboardAction(new ActionListener() {
+			public void actionPerformed(ActionEvent actionEvent) {
+				setVisible(false);
+			}
+		}, stroke, JComponent.WHEN_IN_FOCUSED_WINDOW);
+		return rootPane;
+	}
+
+	private void initialize(GitblitRegistration reg, boolean isLogin) {
+		setIconImage(new ImageIcon(getClass().getResource("/gitblt-favicon.png")).getImage());
+		canceled = true;
+		urlField = new JTextField(reg == null ? "" : reg.url, 30);
+		nameField = new JTextField(reg == null ? "" : reg.name);
+		accountField = new JTextField(reg == null ? "" : reg.account);
+		passwordField = new JPasswordField(reg == null ? "" : new String(reg.password));
+		savePassword = new JCheckBox("save password (passwords are NOT encrypted!)");
+		savePassword.setSelected(reg == null ? false
+				: (reg.password != null && reg.password.length > 0));
+
+		JPanel panel = new JPanel(new GridLayout(0, 1, 5, 5));
+		panel.add(newLabelPanel(Translation.get("gb.name"), nameField));
+		panel.add(newLabelPanel(Translation.get("gb.url"), urlField));
+		panel.add(newLabelPanel(Translation.get("gb.username"), accountField));
+		panel.add(newLabelPanel(Translation.get("gb.password"), passwordField));
+		panel.add(newLabelPanel("", savePassword));
+
+		JButton cancel = new JButton(Translation.get("gb.cancel"));
+		cancel.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent event) {
+				setVisible(false);
+			}
+		});
+
+		final JButton save = new JButton(Translation.get(isLogin ? "gb.login" : "gb.save"));
+		save.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent event) {
+				if (validateFields()) {
+					canceled = false;
+					setVisible(false);
+				}
+			}
+		});
+
+		// on enter in password field, save or login
+		passwordField.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent event) {
+				save.doClick();
+			}
+		});
+
+		JPanel controls = new JPanel();
+		controls.add(cancel);
+		controls.add(save);
+
+		if (reg == null) {
+			this.setTitle(Translation.get("gb.create"));
+			headerPanel = new HeaderPanel(Translation.get("gb.create"), null);
+		} else {
+			this.setTitle(Translation.get(isLogin ? "gb.login" : "gb.edit"));
+			headerPanel = new HeaderPanel(reg.name, null);
+		}
+
+		final Insets insets = new Insets(5, 5, 5, 5);
+		JPanel centerPanel = new JPanel(new BorderLayout(5, 5)) {
+
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public Insets getInsets() {
+				return insets;
+			}
+		};
+		centerPanel.add(headerPanel, BorderLayout.NORTH);
+		centerPanel.add(panel, BorderLayout.CENTER);
+		centerPanel.add(controls, BorderLayout.SOUTH);
+
+		getContentPane().setLayout(new BorderLayout());
+		getContentPane().add(centerPanel, BorderLayout.CENTER);
+		pack();
+		setModal(true);
+		if (isLogin) {
+			passwordField.requestFocus();
+		}
+	}
+
+	private JPanel newLabelPanel(String text, JComponent field) {
+		JLabel label = new JLabel(text);
+		label.setFont(label.getFont().deriveFont(Font.BOLD));
+		label.setPreferredSize(new Dimension(75, 10));
+		JPanel jpanel = new JPanel(new BorderLayout());
+		jpanel.add(label, BorderLayout.WEST);
+		jpanel.add(field, BorderLayout.CENTER);
+		return jpanel;
+	}
+
+	private boolean validateFields() {
+		String name = nameField.getText();
+		if (StringUtils.isEmpty(name)) {
+			error("Please enter a name for this registration!");
+			return false;
+		}
+		String url = urlField.getText();
+		if (StringUtils.isEmpty(url)) {
+			error("Please enter a url for this registration!");
+			return false;
+		}
+		return true;
+	}
+
+	private void error(String message) {
+		JOptionPane.showMessageDialog(EditRegistrationDialog.this, message,
+				Translation.get("gb.error"), JOptionPane.ERROR_MESSAGE);
+	}
+
+	public GitblitRegistration getRegistration() {
+		if (canceled) {
+			return null;
+		}
+		GitblitRegistration reg = new GitblitRegistration(nameField.getText(), urlField.getText(),
+				accountField.getText(), passwordField.getPassword());
+		reg.savePassword = savePassword.isSelected();
+		return reg;
+	}
+}
diff --git a/src/com/gitblit/client/GitblitManager.java b/src/com/gitblit/client/GitblitManager.java
index 49750b1..f16616a 100644
--- a/src/com/gitblit/client/GitblitManager.java
+++ b/src/com/gitblit/client/GitblitManager.java
@@ -19,8 +19,6 @@
 import java.awt.Cursor;
 import java.awt.Dimension;
 import java.awt.EventQueue;
-import java.awt.Font;
-import java.awt.GridLayout;
 import java.awt.Point;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
@@ -45,15 +43,12 @@
 
 import javax.swing.ImageIcon;
 import javax.swing.JFrame;
-import javax.swing.JLabel;
 import javax.swing.JMenu;
 import javax.swing.JMenuBar;
 import javax.swing.JMenuItem;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
-import javax.swing.JPasswordField;
 import javax.swing.JTabbedPane;
-import javax.swing.JTextField;
 import javax.swing.KeyStroke;
 import javax.swing.SwingWorker;
 import javax.swing.UIManager;
@@ -101,7 +96,7 @@
 			public void windowClosing(WindowEvent event) {
 				saveSizeAndPosition();
 			}
-			
+
 			@Override
 			public void windowOpened(WindowEvent event) {
 				manageRegistrations();
@@ -177,25 +172,7 @@
 		});
 		serversMenu.add(manage);
 
-		JMenuItem login = new JMenuItem(Translation.get("gb.login") + "...");
-		login.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, KeyEvent.CTRL_DOWN_MASK, false));
-		login.addActionListener(new ActionListener() {
-			public void actionPerformed(ActionEvent event) {
-				loginPrompt(GitblitRegistration.LOCALHOST);
-			}
-		});
-		serversMenu.add(login);
 		return menuBar;
-	}
-
-	private JPanel newLabelPanel(String text, JTextField field) {
-		JLabel label = new JLabel(text);
-		label.setFont(label.getFont().deriveFont(Font.BOLD));
-		label.setPreferredSize(new Dimension(75, 10));
-		JPanel jpanel = new JPanel(new BorderLayout());
-		jpanel.add(label, BorderLayout.WEST);
-		jpanel.add(field, BorderLayout.CENTER);
-		return jpanel;
 	}
 
 	private JPanel getCenterPanel() {
@@ -215,48 +192,23 @@
 	}
 
 	@Override
-	public void loginPrompt(GitblitRegistration reg) {
-		JTextField urlField = new JTextField(reg.url, 30);
-		JTextField nameField = new JTextField(reg.name);
-		JTextField accountField = new JTextField(reg.account);
-		JPasswordField passwordField = new JPasswordField(new String(reg.password));
-
-		JPanel panel = new JPanel(new GridLayout(0, 1, 5, 5));
-		panel.add(newLabelPanel(Translation.get("gb.name"), nameField));
-		panel.add(newLabelPanel(Translation.get("gb.url"), urlField));
-		panel.add(newLabelPanel(Translation.get("gb.username"), accountField));
-		panel.add(newLabelPanel(Translation.get("gb.password"), passwordField));
-
-		int result = JOptionPane.showConfirmDialog(GitblitManager.this, panel,
-				Translation.get("gb.login"), JOptionPane.OK_CANCEL_OPTION);
-		if (result != JOptionPane.OK_OPTION) {
-			return;
-		}
-		String url = urlField.getText();
-		if (StringUtils.isEmpty(url)) {
-			return;
-		}
-		String originalName = reg.name;
-		reg = new GitblitRegistration(nameField.getText(), url, accountField.getText(),
-				passwordField.getPassword());
-		if (!StringUtils.isEmpty(originalName) && !originalName.equals(reg.name)) {
-			// delete old registration
-			registrations.remove(originalName);
-			try {
-				StoredConfig config = getConfig();
-				config.unsetSection("servers", originalName);
-				config.save();
-			} catch (Throwable t) {
-				Utils.showException(GitblitManager.this, t);
+	public void login(GitblitRegistration reg) {
+		if (!reg.savePassword && (reg.password == null || reg.password.length == 0)) {
+			// prompt for password
+			EditRegistrationDialog dialog = new EditRegistrationDialog(this, reg, true);
+			dialog.setLocationRelativeTo(GitblitManager.this);
+			dialog.setVisible(true);
+			reg = dialog.getRegistration();
+			if (reg == null) {
+				// user canceled
+				return;
 			}
 		}
-		login(reg);
-	}
-
-	@Override
-	public void login(final GitblitRegistration reg) {
+		
+		// login
 		setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
-		final GitblitPanel panel = new GitblitPanel(reg);
+		final GitblitRegistration registration = reg;
+		final GitblitPanel panel = new GitblitPanel(registration);
 		SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {
 
 			@Override
@@ -269,15 +221,19 @@
 			protected void done() {
 				try {
 					boolean success = get();
-					serverTabs.addTab(reg.name, panel);
+					serverTabs.addTab(registration.name, panel);
 					int idx = serverTabs.getTabCount() - 1;
 					serverTabs.setSelectedIndex(idx);
-					serverTabs.setTabComponentAt(idx, new ClosableTabComponent(reg.name, null,
-							serverTabs, panel));
-					reg.lastLogin = new Date();
-					saveRegistration(reg);
-					registrations.put(reg.name, reg);
+					serverTabs.setTabComponentAt(idx, new ClosableTabComponent(registration.name,
+							null, serverTabs, panel));
+					registration.lastLogin = new Date();
+					saveRegistration(registration.name, registration);
+					registrations.put(registration.name, registration);
 					rebuildRecentMenu();
+					if (!registration.savePassword) {
+						// clear password
+						registration.password = null;
+					}
 				} catch (Throwable t) {
 					Throwable cause = t.getCause();
 					if (cause instanceof ConnectException) {
@@ -332,7 +288,11 @@
 			StoredConfig config = getConfig();
 			Set<String> servers = config.getSubsections("servers");
 			for (String server : servers) {
-				Date lastLogin = dateFormat.parse(config.getString("servers", server, "lastLogin"));
+				Date lastLogin = new Date(0);
+				String date = config.getString("servers", server, "lastLogin");
+				if (!StringUtils.isEmpty(date)) {
+					lastLogin = dateFormat.parse(date);
+				}
 				String url = config.getString("servers", server, "url");
 				String account = config.getString("servers", server, "account");
 				char[] password;
@@ -340,7 +300,6 @@
 				if (StringUtils.isEmpty(pw)) {
 					password = new char[0];
 				} else {
-					// FIXME this is pretty lame
 					password = new String(Base64.decode(pw)).toCharArray();
 				}
 				GitblitRegistration reg = new GitblitRegistration(server, url, account, password);
@@ -352,21 +311,37 @@
 		}
 	}
 
-	private void saveRegistration(GitblitRegistration reg) {
+	@Override
+	public boolean saveRegistration(String name, GitblitRegistration reg) {
 		try {
 			StoredConfig config = getConfig();
+			if (!StringUtils.isEmpty(name) && !name.equals(reg.name)) {
+				// delete old registration
+				registrations.remove(name);
+				config.unsetSection("servers", name);
+			}
+
+			// update registration
 			config.setString("servers", reg.name, "url", reg.url);
 			config.setString("servers", reg.name, "account", reg.account);
-			// FIXME this is pretty lame
-			config.setString("servers", reg.name, "password",
-					Base64.encodeBytes(new String(reg.password).getBytes("UTF-8")));
-			config.setString("servers", reg.name, "lastLogin", dateFormat.format(reg.lastLogin));
+			if (reg.savePassword) {
+				config.setString("servers", reg.name, "password",
+						Base64.encodeBytes(new String(reg.password).getBytes("UTF-8")));
+			} else {
+				config.setString("servers", reg.name, "password", "");
+			}
+			if (reg.lastLogin != null) {
+				config.setString("servers", reg.name, "lastLogin", dateFormat.format(reg.lastLogin));
+			}
 			config.save();
+			return true;
 		} catch (Throwable t) {
 			Utils.showException(GitblitManager.this, t);
 		}
+		return false;
 	}
 
+	@Override
 	public boolean deleteRegistrations(List<GitblitRegistration> list) {
 		boolean success = false;
 		try {
diff --git a/src/com/gitblit/client/GitblitPanel.java b/src/com/gitblit/client/GitblitPanel.java
index 23aadb8..03ddfb3 100644
--- a/src/com/gitblit/client/GitblitPanel.java
+++ b/src/com/gitblit/client/GitblitPanel.java
@@ -564,7 +564,7 @@
 	}
 
 	private void updateStatusPanel() {
-		statusPanel.setStatus(gitblit.getStatus());
+		statusPanel.setStatus(gitblit.url, gitblit.getStatus());
 	}
 
 	private void filterRepositories(final String fragment) {
diff --git a/src/com/gitblit/client/GitblitRegistration.java b/src/com/gitblit/client/GitblitRegistration.java
index bdd8b23..0463c12 100644
--- a/src/com/gitblit/client/GitblitRegistration.java
+++ b/src/com/gitblit/client/GitblitRegistration.java
@@ -28,20 +28,20 @@
  */
 public class GitblitRegistration implements Serializable, Comparable<GitblitRegistration> {
 
-	public static final GitblitRegistration LOCALHOST = new GitblitRegistration("localhost",
-			"https://localhost:8443", "admin", "admin".toCharArray());
 	private static final long serialVersionUID = 1L;
 
 	String name;
 	String url;
 	String account;
 	char[] password;
+	boolean savePassword;
 	Date lastLogin;
 
 	public GitblitRegistration(String name, String url, String account, char[] password) {
 		this.url = url;
 		this.account = account;
 		this.password = password;
+		this.savePassword = password != null && password.length > 0;
 		if (StringUtils.isEmpty(name)) {
 			this.name = url.substring(url.indexOf("//") + 2);
 		} else {
@@ -51,6 +51,6 @@
 
 	@Override
 	public int compareTo(GitblitRegistration o) {
-		return name.compareTo(o.name);
+		return name.toLowerCase().compareTo(o.name.toLowerCase());
 	}
 }
diff --git a/src/com/gitblit/client/RegistrationsDialog.java b/src/com/gitblit/client/RegistrationsDialog.java
index 71178f3..0b87bb4 100644
--- a/src/com/gitblit/client/RegistrationsDialog.java
+++ b/src/com/gitblit/client/RegistrationsDialog.java
@@ -38,14 +38,22 @@
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
 
+/**
+ * Displays a list of registrations and allows management of server
+ * registrations.
+ * 
+ * @author James Moger
+ * 
+ */
 public class RegistrationsDialog extends JDialog {
 
 	interface RegistrationListener {
-		boolean deleteRegistrations(List<GitblitRegistration> list);
-
-		void loginPrompt(GitblitRegistration reg);
 
 		void login(GitblitRegistration reg);
+
+		boolean saveRegistration(String name, GitblitRegistration reg);
+
+		boolean deleteRegistrations(List<GitblitRegistration> list);
 	}
 
 	private static final long serialVersionUID = 1L;
@@ -87,12 +95,13 @@
 		registrationsTable = Utils.newTable(model);
 		registrationsTable.setRowHeight(nameRenderer.getFont().getSize() + 8);
 
-		String id = registrationsTable.getColumnName(RegistrationsTableModel.Columns.Name.ordinal());
+		String id = registrationsTable
+				.getColumnName(RegistrationsTableModel.Columns.Name.ordinal());
 		registrationsTable.getColumn(id).setCellRenderer(nameRenderer);
 		registrationsTable.addMouseListener(new MouseAdapter() {
 			public void mouseClicked(MouseEvent e) {
 				if (e.getClickCount() == 2) {
-					login(false);
+					login();
 				}
 			}
 		});
@@ -100,8 +109,7 @@
 		final JButton create = new JButton(Translation.get("gb.create"));
 		create.addActionListener(new ActionListener() {
 			public void actionPerformed(ActionEvent event) {
-				RegistrationsDialog.this.setVisible(false);
-				listener.loginPrompt(GitblitRegistration.LOCALHOST);
+				create();
 			}
 		});
 
@@ -109,15 +117,15 @@
 		login.setEnabled(false);
 		login.addActionListener(new ActionListener() {
 			public void actionPerformed(ActionEvent event) {
-				login(false);
+				login();
 			}
 		});
 
-		final JButton loginPrompt = new JButton(Translation.get("gb.login") + "...");
-		loginPrompt.setEnabled(false);
-		loginPrompt.addActionListener(new ActionListener() {
+		final JButton edit = new JButton(Translation.get("gb.edit"));
+		edit.setEnabled(false);
+		edit.addActionListener(new ActionListener() {
 			public void actionPerformed(ActionEvent event) {
-				login(true);
+				edit();
 			}
 		});
 
@@ -139,7 +147,7 @@
 						boolean singleSelection = registrationsTable.getSelectedRowCount() == 1;
 						boolean selected = registrationsTable.getSelectedRow() > -1;
 						login.setEnabled(singleSelection);
-						loginPrompt.setEnabled(singleSelection);
+						edit.setEnabled(singleSelection);
 						delete.setEnabled(selected);
 					}
 				});
@@ -147,7 +155,7 @@
 		JPanel controls = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 0));
 		controls.add(create);
 		controls.add(login);
-		controls.add(loginPrompt);
+		controls.add(edit);
 		controls.add(delete);
 
 		final Insets insets = new Insets(5, 5, 5, 5);
@@ -159,6 +167,7 @@
 				return insets;
 			}
 		};
+		centerPanel.add(new HeaderPanel(Translation.get("gb.servers"), null), BorderLayout.NORTH);
 		centerPanel.add(new JScrollPane(registrationsTable), BorderLayout.CENTER);
 		centerPanel.add(controls, BorderLayout.SOUTH);
 
@@ -166,15 +175,42 @@
 		getContentPane().add(centerPanel, BorderLayout.CENTER);
 	}
 
-	private void login(boolean prompt) {
+	private void login() {
 		int viewRow = registrationsTable.getSelectedRow();
 		int modelRow = registrationsTable.convertRowIndexToModel(viewRow);
 		GitblitRegistration reg = registrations.get(modelRow);
 		RegistrationsDialog.this.setVisible(false);
-		if (prompt) {
-			listener.loginPrompt(reg);
-		} else {
-			listener.login(reg);
+		listener.login(reg);
+	}
+
+	private void create() {
+		EditRegistrationDialog dialog = new EditRegistrationDialog(getOwner());
+		dialog.setLocationRelativeTo(this);
+		dialog.setVisible(true);
+		GitblitRegistration reg = dialog.getRegistration();
+		if (reg == null) {
+			return;
+		}
+		if (listener.saveRegistration(reg.name, reg)) {
+			model.list.add(reg);
+			model.fireTableDataChanged();
+		}
+	}
+
+	private void edit() {
+		int viewRow = registrationsTable.getSelectedRow();
+		int modelRow = registrationsTable.convertRowIndexToModel(viewRow);
+		GitblitRegistration reg = registrations.get(modelRow);
+		String originalName = reg.name;
+		EditRegistrationDialog dialog = new EditRegistrationDialog(getOwner(), reg, false);
+		dialog.setLocationRelativeTo(this);
+		dialog.setVisible(true);
+		reg = dialog.getRegistration();
+		if (reg == null) {
+			return;
+		}
+		if (listener.saveRegistration(originalName, reg)) {
+			model.fireTableDataChanged();
 		}
 	}
 
diff --git a/src/com/gitblit/client/StatusPanel.java b/src/com/gitblit/client/StatusPanel.java
index 0cc530e..b85d87a 100644
--- a/src/com/gitblit/client/StatusPanel.java
+++ b/src/com/gitblit/client/StatusPanel.java
@@ -42,6 +42,7 @@
 	private static final long serialVersionUID = 1L;
 	private final Insets insets = new Insets(5, 5, 5, 5);
 	private JLabel bootDate;
+	private JLabel url;
 	private JLabel servletContainer;
 	private JLabel heapMaximum;
 	private JLabel heapAllocated;
@@ -56,15 +57,16 @@
 		initialize();
 	}
 
-	public StatusPanel(ServerStatus status) {
+	public StatusPanel(String url, ServerStatus status) {
 		this();
-		setStatus(status);
+		setStatus(url, status);
 	}
 
 	private void initialize() {
 		version = new JLabel();
 		releaseDate = new JLabel();
 		bootDate = new JLabel();
+		url = new JLabel();
 		servletContainer = new JLabel();
 
 		heapMaximum = new JLabel();
@@ -72,7 +74,7 @@
 		heapUsed = new JLabel();
 
 		JPanel fieldsPanel = new JPanel(new GridLayout(0, 1, 0, 5)) {
-		
+
 			private static final long serialVersionUID = 1L;
 
 			@Override
@@ -83,6 +85,7 @@
 		fieldsPanel.add(createFieldPanel("gb.version", version));
 		fieldsPanel.add(createFieldPanel("gb.releaseDate", releaseDate));
 		fieldsPanel.add(createFieldPanel("gb.bootDate", bootDate));
+		fieldsPanel.add(createFieldPanel("gb.url", url));
 		fieldsPanel.add(createFieldPanel("gb.servletContainer", servletContainer));
 		fieldsPanel.add(createFieldPanel("gb.heapUsed", heapUsed));
 		fieldsPanel.add(createFieldPanel("gb.heapAllocated", heapAllocated));
@@ -120,12 +123,13 @@
 		return insets;
 	}
 
-	public void setStatus(ServerStatus status) {
+	public void setStatus(String url, ServerStatus status) {
 		headerPanel.setText(Translation.get("gb.status"));
 		version.setText(Constants.NAME + (status.isGO ? " GO v" : " WAR v") + status.version);
 		releaseDate.setText(status.releaseDate);
 		bootDate.setText(status.bootDate.toString() + " (" + TimeUtils.timeAgo(status.bootDate)
 				+ ")");
+		this.url.setText(url);
 		servletContainer.setText(status.servletContainer);
 		ByteFormat byteFormat = new ByteFormat();
 		heapMaximum.setText(byteFormat.format(status.heapMaximum));

--
Gitblit v1.9.1