Refactor web UI to use HTML frames layout
Replace single-page layout with a frameset: left navigation frame with repo dropdown and page links, right content frame showing the selected page. Split the repo page into separate sub-pages: branches, changes, remote, and manage. Uses <frameset> for maximum compatibility with ancient browsers (Netscape 2+, IE 3+). Clone and delete forms target _top to reload the full frameset when the repo list changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -18,16 +18,43 @@ public class HomeController
|
||||
private final GitService gitService;
|
||||
|
||||
@GetMapping("/")
|
||||
public String home(Model model) throws IOException
|
||||
public String frameset(@RequestParam(required = false) String repo, Model model) throws IOException
|
||||
{
|
||||
model.addAttribute("selectedRepo", repo);
|
||||
return "frameset";
|
||||
}
|
||||
|
||||
@GetMapping("/nav")
|
||||
public String nav(@RequestParam(required = false) String repo, Model model) throws IOException
|
||||
{
|
||||
model.addAttribute("repositories", gitService.listRepositories());
|
||||
return "home";
|
||||
model.addAttribute("selectedRepo", repo);
|
||||
return "nav";
|
||||
}
|
||||
|
||||
@GetMapping("/welcome")
|
||||
public String welcome()
|
||||
{
|
||||
return "welcome";
|
||||
}
|
||||
|
||||
@GetMapping("/repos")
|
||||
public String repos(Model model) throws IOException
|
||||
{
|
||||
model.addAttribute("repositories", gitService.listRepositories());
|
||||
return "repos";
|
||||
}
|
||||
|
||||
@GetMapping("/clone-form")
|
||||
public String cloneForm()
|
||||
{
|
||||
return "clone";
|
||||
}
|
||||
|
||||
@PostMapping("/clone")
|
||||
public String cloneRepo(@RequestParam String url, @RequestParam String name) throws GitAPIException, IOException
|
||||
{
|
||||
gitService.cloneRepository(url, name);
|
||||
return "redirect:/";
|
||||
return "redirect:/?repo=" + name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,63 +20,90 @@ public class RepoController
|
||||
private final GitService gitService;
|
||||
|
||||
@GetMapping("/repo/{name}")
|
||||
public String repo(@PathVariable String name, Model model) throws IOException, GitAPIException
|
||||
public String repo(@PathVariable String name)
|
||||
{
|
||||
return "redirect:/repo/" + name + "/branches";
|
||||
}
|
||||
|
||||
@GetMapping("/repo/{name}/branches")
|
||||
public String branches(@PathVariable String name, Model model) throws IOException, GitAPIException
|
||||
{
|
||||
model.addAttribute("name", name);
|
||||
model.addAttribute("currentBranch", gitService.getCurrentBranch(name));
|
||||
model.addAttribute("branches", gitService.listBranches(name));
|
||||
return "branches";
|
||||
}
|
||||
|
||||
@GetMapping("/repo/{name}/changes")
|
||||
public String changes(@PathVariable String name, Model model) throws IOException, GitAPIException
|
||||
{
|
||||
model.addAttribute("name", name);
|
||||
model.addAttribute("modifiedFiles", gitService.getModifiedFiles(name));
|
||||
model.addAttribute("stagedFiles", gitService.getStagedFiles(name));
|
||||
return "repo";
|
||||
return "changes";
|
||||
}
|
||||
|
||||
@GetMapping("/repo/{name}/remote")
|
||||
public String remote(@PathVariable String name, Model model)
|
||||
{
|
||||
model.addAttribute("name", name);
|
||||
return "remote";
|
||||
}
|
||||
|
||||
@GetMapping("/repo/{name}/manage")
|
||||
public String manage(@PathVariable String name, Model model)
|
||||
{
|
||||
model.addAttribute("name", name);
|
||||
return "manage";
|
||||
}
|
||||
|
||||
@PostMapping("/repo/{name}/checkout")
|
||||
public String checkout(@PathVariable String name, @RequestParam String branch) throws IOException, GitAPIException
|
||||
{
|
||||
gitService.checkoutBranch(name, branch);
|
||||
return "redirect:/repo/" + name;
|
||||
return "redirect:/repo/" + name + "/branches";
|
||||
}
|
||||
|
||||
@PostMapping("/repo/{name}/new-branch")
|
||||
public String newBranch(@PathVariable String name, @RequestParam String branch) throws IOException, GitAPIException
|
||||
{
|
||||
gitService.createAndCheckoutBranch(name, branch);
|
||||
return "redirect:/repo/" + name;
|
||||
return "redirect:/repo/" + name + "/branches";
|
||||
}
|
||||
|
||||
@PostMapping("/repo/{name}/stage")
|
||||
public String stage(@PathVariable String name, @RequestParam List<String> files) throws IOException, GitAPIException
|
||||
{
|
||||
gitService.stageFiles(name, files);
|
||||
return "redirect:/repo/" + name;
|
||||
return "redirect:/repo/" + name + "/changes";
|
||||
}
|
||||
|
||||
@PostMapping("/repo/{name}/unstage")
|
||||
public String unstage(@PathVariable String name, @RequestParam List<String> files) throws IOException, GitAPIException
|
||||
{
|
||||
gitService.unstageFiles(name, files);
|
||||
return "redirect:/repo/" + name;
|
||||
return "redirect:/repo/" + name + "/changes";
|
||||
}
|
||||
|
||||
@PostMapping("/repo/{name}/commit")
|
||||
public String commit(@PathVariable String name, @RequestParam String message) throws IOException, GitAPIException
|
||||
{
|
||||
gitService.commit(name, message);
|
||||
return "redirect:/repo/" + name;
|
||||
return "redirect:/repo/" + name + "/changes";
|
||||
}
|
||||
|
||||
@PostMapping("/repo/{name}/push")
|
||||
public String push(@PathVariable String name) throws IOException, GitAPIException
|
||||
{
|
||||
gitService.push(name);
|
||||
return "redirect:/repo/" + name;
|
||||
return "redirect:/repo/" + name + "/remote";
|
||||
}
|
||||
|
||||
@PostMapping("/repo/{name}/pull")
|
||||
public String pull(@PathVariable String name) throws IOException, GitAPIException
|
||||
{
|
||||
gitService.pull(name);
|
||||
return "redirect:/repo/" + name;
|
||||
return "redirect:/repo/" + name + "/remote";
|
||||
}
|
||||
|
||||
@PostMapping("/repo/{name}/delete")
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title th:text="'Branches - ' + ${name}">Branches</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Branches</h2>
|
||||
|
||||
<table border="0" cellpadding="4" cellspacing="0">
|
||||
<tr>
|
||||
<td>Current branch:</td>
|
||||
<td><b th:text="${currentBranch}"></b></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h3>Switch Branch</h3>
|
||||
<form method="post" th:action="@{/repo/{name}/checkout(name=${name})}">
|
||||
<table border="0" cellpadding="4" cellspacing="0">
|
||||
<tr>
|
||||
<td>
|
||||
<select name="branch">
|
||||
<option th:each="b : ${branches}" th:value="${b}" th:text="${b}" th:selected="${b == currentBranch}"></option>
|
||||
</select>
|
||||
</td>
|
||||
<td><input type="submit" value="Checkout"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
<h3>Create New Branch</h3>
|
||||
<form method="post" th:action="@{/repo/{name}/new-branch(name=${name})}">
|
||||
<table border="0" cellpadding="4" cellspacing="0">
|
||||
<tr>
|
||||
<td><input type="text" name="branch" size="20"></td>
|
||||
<td><input type="submit" value="Create"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,41 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title th:text="'WebGit - ' + ${name}">WebGit - repo</title>
|
||||
<title th:text="'Changes - ' + ${name}">Changes</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1><a href="/">WebGit</a></h1>
|
||||
<h2 th:text="${name}">repo</h2>
|
||||
|
||||
<h3>Branch</h3>
|
||||
<table border="0" cellpadding="4" cellspacing="0">
|
||||
<tr>
|
||||
<td>Current branch:</td>
|
||||
<td><b th:text="${currentBranch}"></b></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table border="0" cellpadding="4" cellspacing="0">
|
||||
<tr>
|
||||
<td>
|
||||
<form method="post" th:action="@{/repo/{name}/checkout(name=${name})}">
|
||||
Switch to:
|
||||
<select name="branch">
|
||||
<option th:each="b : ${branches}" th:value="${b}" th:text="${b}" th:selected="${b == currentBranch}"></option>
|
||||
</select>
|
||||
<input type="submit" value="Checkout">
|
||||
</form>
|
||||
</td>
|
||||
<td>
|
||||
<form method="post" th:action="@{/repo/{name}/new-branch(name=${name})}">
|
||||
New branch: <input type="text" name="branch" size="20">
|
||||
<input type="submit" value="Create">
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<hr>
|
||||
<h2>Changes</h2>
|
||||
|
||||
<h3>Modified Files (unstaged)</h3>
|
||||
<form method="post" th:action="@{/repo/{name}/stage(name=${name})}" th:if="${!#lists.isEmpty(modifiedFiles)}">
|
||||
@@ -81,30 +50,5 @@ New branch: <input type="text" name="branch" size="20">
|
||||
</table>
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>Remote</h3>
|
||||
<table border="0" cellpadding="4" cellspacing="0">
|
||||
<tr>
|
||||
<td>
|
||||
<form method="post" th:action="@{/repo/{name}/push(name=${name})}">
|
||||
<input type="submit" value="Push">
|
||||
</form>
|
||||
</td>
|
||||
<td>
|
||||
<form method="post" th:action="@{/repo/{name}/pull(name=${name})}">
|
||||
<input type="submit" value="Pull">
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>Danger Zone</h3>
|
||||
<form method="post" th:action="@{/repo/{name}/delete(name=${name})}">
|
||||
<input type="submit" value="Delete Repository">
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Clone Repository</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Clone a Repository</h2>
|
||||
<form method="post" action="/clone" target="_top">
|
||||
<table border="0" cellpadding="4" cellspacing="0">
|
||||
<tr>
|
||||
<td>URL:</td>
|
||||
<td><input type="text" name="url" size="60"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Name:</td>
|
||||
<td><input type="text" name="name" size="30"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><input type="submit" value="Clone"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,14 @@
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>WebGit</title>
|
||||
</head>
|
||||
<frameset cols="180,*">
|
||||
<frame th:src="${selectedRepo != null} ? '/nav?repo=' + ${selectedRepo} : '/nav'" name="nav">
|
||||
<frame th:src="${selectedRepo != null} ? '/repo/' + ${selectedRepo} + '/branches' : '/welcome'" name="content">
|
||||
<noframes>
|
||||
<body>
|
||||
<p>Your browser does not support frames. <a href="/repos">Click here</a> to continue.</p>
|
||||
</body>
|
||||
</noframes>
|
||||
</frameset>
|
||||
</html>
|
||||
@@ -1,43 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>WebGit</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>WebGit</h1>
|
||||
|
||||
<h2>Repositories</h2>
|
||||
<table border="1" cellpadding="4" cellspacing="0">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
<tr th:each="repo : ${repositories}">
|
||||
<td th:text="${repo}"></td>
|
||||
<td><a th:href="@{/repo/{name}(name=${repo})}">Open</a></td>
|
||||
</tr>
|
||||
<tr th:if="${#lists.isEmpty(repositories)}">
|
||||
<td colspan="2"><i>No repositories cloned yet.</i></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2>Clone a Repository</h2>
|
||||
<form method="post" action="/clone">
|
||||
<table border="0" cellpadding="4" cellspacing="0">
|
||||
<tr>
|
||||
<td>URL:</td>
|
||||
<td><input type="text" name="url" size="60"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Name:</td>
|
||||
<td><input type="text" name="name" size="30"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><input type="submit" value="Clone"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title th:text="'Manage - ' + ${name}">Manage</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Manage Repository</h2>
|
||||
|
||||
<h3>Danger Zone</h3>
|
||||
<p>This will permanently delete the repository and its working tree.</p>
|
||||
<form method="post" th:action="@{/repo/{name}/delete(name=${name})}" target="_top">
|
||||
<input type="submit" value="Delete Repository">
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,33 @@
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>Navigation</title>
|
||||
</head>
|
||||
<body>
|
||||
<b>WebGit</b>
|
||||
<hr>
|
||||
|
||||
<form method="get" action="/" target="_top">
|
||||
<select name="repo">
|
||||
<option value="">-- Select repo --</option>
|
||||
<option th:each="r : ${repositories}" th:value="${r}" th:text="${r}" th:selected="${r == selectedRepo}"></option>
|
||||
</select>
|
||||
<br>
|
||||
<input type="submit" value="Go">
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
||||
<a href="/repos" target="content">Repositories</a><br>
|
||||
<a href="/clone-form" target="content">Clone New</a><br>
|
||||
|
||||
<th:block th:if="${selectedRepo != null}">
|
||||
<hr>
|
||||
<b th:text="${selectedRepo}"></b><br>
|
||||
<a th:href="@{/repo/{name}/branches(name=${selectedRepo})}" target="content">Branches</a><br>
|
||||
<a th:href="@{/repo/{name}/changes(name=${selectedRepo})}" target="content">Changes</a><br>
|
||||
<a th:href="@{/repo/{name}/remote(name=${selectedRepo})}" target="content">Remote</a><br>
|
||||
<a th:href="@{/repo/{name}/manage(name=${selectedRepo})}" target="content">Manage</a><br>
|
||||
</th:block>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title th:text="'Remote - ' + ${name}">Remote</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Remote</h2>
|
||||
|
||||
<table border="0" cellpadding="4" cellspacing="0">
|
||||
<tr>
|
||||
<td>
|
||||
<form method="post" th:action="@{/repo/{name}/push(name=${name})}">
|
||||
<input type="submit" value="Push">
|
||||
</form>
|
||||
</td>
|
||||
<td>
|
||||
<form method="post" th:action="@{/repo/{name}/pull(name=${name})}">
|
||||
<input type="submit" value="Pull">
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>Repositories</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Repositories</h2>
|
||||
<table border="1" cellpadding="4" cellspacing="0">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
<tr th:each="repo : ${repositories}">
|
||||
<td th:text="${repo}"></td>
|
||||
<td><a th:href="@{/repo/{name}/branches(name=${repo})}">Open</a></td>
|
||||
</tr>
|
||||
<tr th:if="${#lists.isEmpty(repositories)}">
|
||||
<td colspan="2"><i>No repositories cloned yet.</i></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>WebGit</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Welcome to WebGit</h1>
|
||||
<p>Select a repository from the menu on the left, or clone a new one.</p>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user