Skip to content

Commit cdfd2e4

Browse files
authored
feat: Improve web-ui for listing of repositories (#114)
* feat: Improve web-ui for listing of repositories with support of search by repo name and viewing ports and type of presented repos. Add signout.
1 parent 6b0622c commit cdfd2e4

8 files changed

Lines changed: 268 additions & 39 deletions

File tree

src/main/java/com/artipie/front/Service.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,21 @@ void start(final int port, final String rest) {
137137
);
138138
}
139139
);
140+
this.ignite.path(
141+
"/signout",
142+
() -> {
143+
this.ignite.get(
144+
"",
145+
(req, rsp) -> {
146+
if (req.session() != null) {
147+
req.session().invalidate();
148+
}
149+
rsp.redirect("/dashboard");
150+
return "Ok";
151+
}
152+
);
153+
}
154+
);
140155
this.ignite.path(
141156
"/api",
142157
() -> {

src/main/java/com/artipie/front/rest/RepositoryService.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,16 @@ public List<String> list(final String token, final String uname) {
7474
* @return Repository content.
7575
*/
7676
public String repo(final String token, final RepositoryName rname) {
77+
return this.repo(token, rname.toString());
78+
}
79+
80+
/**
81+
* Obtain repository content.
82+
* @param token Token.
83+
* @param rname Repository name.
84+
* @return Repository content.
85+
*/
86+
public String repo(final String token, final String rname) {
7787
return BaseService.handle(
7888
this.httpGet(
7989
Optional.of(token),

src/main/java/com/artipie/front/rest/SettingsService.java

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,34 @@
77
import com.artipie.front.Layout;
88
import java.util.Optional;
99
import java.util.concurrent.atomic.AtomicReference;
10+
import java.util.function.Function;
1011
import javax.json.JsonObject;
1112

1213
/**
1314
* Settings-service.
1415
*
1516
* @since 1.0
1617
*/
18+
@SuppressWarnings("PMD.AvoidFieldNameMatchingMethodName")
1719
public class SettingsService extends BaseService {
20+
/**
21+
* Path to port rest-api.
22+
*/
23+
private static final String PORT_PATH = "/api/v1/settings/port";
24+
1825
/**
1926
* Path to layout rest-api.
2027
*/
2128
private static final String LAYOUT_PATH = "/api/v1/settings/layout";
2229

30+
/**
31+
* Port.
32+
*/
33+
private final AtomicReference<Integer> port;
34+
2335
/**
2436
* Layout.
2537
*/
26-
@SuppressWarnings("PMD.AvoidFieldNameMatchingMethodName")
2738
private final AtomicReference<Layout> layout;
2839

2940
/**
@@ -32,24 +43,54 @@ public class SettingsService extends BaseService {
3243
*/
3344
public SettingsService(final String rest) {
3445
super(rest);
46+
this.port = new AtomicReference<>();
3547
this.layout = new AtomicReference<>();
3648
}
3749

50+
/**
51+
* Obtain Artipie server port.
52+
* @return Artipie server port
53+
*/
54+
public int port() {
55+
return this.value(
56+
this.port,
57+
SettingsService.PORT_PATH,
58+
json -> json.getInt("port")
59+
);
60+
}
61+
3862
/**
3963
* Obtain Artipie layout.
4064
* @return Artipie layout
4165
*/
4266
public Layout layout() {
43-
if (this.layout.get() == null) {
44-
final Layout value = BaseService.handle(
45-
this.httpGet(Optional.empty(), SettingsService.LAYOUT_PATH),
67+
return this.value(
68+
this.layout,
69+
SettingsService.LAYOUT_PATH,
70+
json -> Layout.byName(json.getString("layout"))
71+
);
72+
}
73+
74+
/**
75+
* Obtain Artipie setting's value.
76+
* @param ref Reference to setting value
77+
* @param path Path to rest service
78+
* @param handler Handler of json content
79+
* @param <T> Resulting type of handler
80+
* @return Artipie layout
81+
*/
82+
private <T> T value(final AtomicReference<T> ref, final String path,
83+
final Function<JsonObject, T> handler) {
84+
if (ref.get() == null) {
85+
final T value = BaseService.handle(
86+
this.httpGet(Optional.empty(), path),
4687
res -> {
4788
final JsonObject json = BaseService.jsonObject(res);
48-
return Layout.byName(json.getString("layout"));
89+
return handler.apply(json);
4990
}
5091
);
51-
this.layout.compareAndSet(null, value);
92+
ref.compareAndSet(null, value);
5293
}
53-
return this.layout.get();
94+
return ref.get();
5495
}
5596
}

src/main/java/com/artipie/front/ui/repository/RepoList.java

Lines changed: 90 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,18 @@
44
*/
55
package com.artipie.front.ui.repository;
66

7+
import com.amihaiemil.eoyaml.Yaml;
8+
import com.amihaiemil.eoyaml.YamlMapping;
79
import com.artipie.front.Layout;
810
import com.artipie.front.misc.RouteWrap;
911
import com.artipie.front.rest.RepositoryService;
1012
import com.artipie.front.rest.SettingsService;
1113
import com.artipie.front.ui.HbPage;
14+
import java.io.IOException;
15+
import java.util.ArrayList;
1216
import java.util.List;
1317
import java.util.Map;
18+
import java.util.Optional;
1419

1520
/**
1621
* List of repositories page.
@@ -33,12 +38,23 @@ public RepoList(final RepositoryService repository, final SettingsService settin
3338
req -> {
3439
final String uid = req.session().attribute("uid");
3540
final String token = req.session().attribute("token");
36-
final List<String> repos;
41+
final List<String> names;
3742
if (settings.layout() == Layout.FLAT) {
38-
repos = repository.list(token);
43+
names = repository.list(token);
3944
} else {
40-
repos = repository.list(token, uid);
45+
names = repository.list(token, uid);
4146
}
47+
final List<Repo> repos = new ArrayList<>(names.size());
48+
names.stream().sorted().forEach(
49+
name ->
50+
repos.add(
51+
new Repo(
52+
Integer.toString(settings.port()),
53+
name,
54+
repository.repo(token, name)
55+
)
56+
)
57+
);
4258
return Map.of(
4359
"title", "Repository list",
4460
"repos", repos
@@ -47,4 +63,75 @@ public RepoList(final RepositoryService repository, final SettingsService settin
4763
)
4864
);
4965
}
66+
67+
/**
68+
* Repository information.
69+
* @since 0.1.3
70+
*/
71+
@SuppressWarnings("PMD.AvoidFieldNameMatchingMethodName")
72+
public static class Repo {
73+
/**
74+
* Repository name.
75+
*/
76+
private final String name;
77+
78+
/**
79+
* Artipie server port.
80+
*/
81+
private final String port;
82+
83+
/**
84+
* Repository configuration.
85+
*/
86+
private Optional<YamlMapping> conf;
87+
88+
/**
89+
* Ctor.
90+
* @param port Artipie's default port
91+
* @param name Name of repository.
92+
* @param conf Repository configuration content
93+
*/
94+
@SuppressWarnings("PMD.ConstructorOnlyInitializesOrCallOtherConstructors")
95+
public Repo(final String port, final String name, final String conf) {
96+
this.port = port;
97+
this.name = name;
98+
try {
99+
this.conf = Optional.of(Yaml.createYamlInput(conf).readYamlMapping());
100+
} catch (final IOException exc) {
101+
this.conf = Optional.empty();
102+
}
103+
}
104+
105+
/**
106+
* Name of repository.
107+
* @return Name of repository.
108+
*/
109+
public String name() {
110+
return this.name;
111+
}
112+
113+
/**
114+
* Type of repository defined in configuration.
115+
* @return Repository type or empty string
116+
*/
117+
public String type() {
118+
return this.repo().map(repo -> repo.string("type")).orElse("");
119+
}
120+
121+
/**
122+
* Port of repository defined in configuration.
123+
* @return Repository port or default Artipie port
124+
*/
125+
public String port() {
126+
return this.repo().map(repo -> repo.string("port")).orElse(this.port);
127+
}
128+
129+
/**
130+
* Repository repo-section in yaml.
131+
* @return Repository repo-configuration
132+
*/
133+
private Optional<YamlMapping> repo() {
134+
return this.conf.map(value -> value.yamlMapping("repo"));
135+
}
136+
}
50137
}

src/main/resources/html/base

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<link rel="shortcut icon" href="/logo.png"/>
88
<link rel="stylesheet" href="//cdn.jsdelivr.net/gh/yegor256/tacit@gh-pages/tacit-css.min.css"/>
99
<link rel="stylesheet" href="//cdn.jsdelivr.net/gh/yegor256/drops@gh-pages/drops.min.css"/>
10+
<link rel="stylesheet" href="/css/style.css"/>
1011
<script src="/scripts/jquery-3.6.1.min.js"></script>
1112
</head>
1213
<body>
@@ -19,33 +20,34 @@
1920
</ul>
2021
</nav>
2122
</header>
22-
<table>
23-
<tr>
24-
<td>
25-
<ul id="navMenu">
26-
<li><a href="/dashboard/repository/list">Repositories</a>
27-
<ul>
23+
<main>
24+
<div class="main">
25+
<div class="menu">
26+
<ul id="navMenu">
27+
<li><a href="/dashboard/repository/list">Repositories</a>
28+
<ul>
2829
<li><a href="/dashboard/repository/create">Create</a></li>
29-
</ul>
30-
</li>
31-
<li>Artipie
32-
<ul>
30+
</ul>
31+
</li>
32+
<li>Artipie
33+
<ul>
3334
<li><a href="https://github.com/artipie">Github</a></li>
3435
<li><a href="https://github.com/artipie/artipie/wiki">Wiki</a></li>
35-
</ul>
36-
</li>
37-
</ul>
38-
</td>
39-
<td>
40-
<section style="width:90%">
41-
<article>
42-
{{#block "content"}}
43-
{{/block}}
44-
</article>
45-
</section>
46-
</td>
47-
</tr>
48-
</table>
36+
</ul>
37+
</li>
38+
<li><a href="/signout">Sign out</a></li>
39+
</ul>
40+
</div>
41+
<div class="content">
42+
<section style="width:100%">
43+
<article>
44+
{{#block "content"}}
45+
{{/block}}
46+
</article>
47+
</section>
48+
</div>
49+
</div>
50+
</main>
4951
<footer>
5052
<nav>
5153
<ul>

0 commit comments

Comments
 (0)