Skip to content

Commit 344f08e

Browse files
committed
feat(model-server): added repository overview
This merges the content explorer overview with the history overview. Also adds the option to view the content of a specific version in the history page.
1 parent d25f3c9 commit 344f08e

File tree

5 files changed

+137
-117
lines changed

5 files changed

+137
-117
lines changed

model-server/src/main/kotlin/org/modelix/model/server/Main.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import io.ktor.server.plugins.cors.routing.*
2727
import io.ktor.server.plugins.forwardedheaders.*
2828
import io.ktor.server.response.*
2929
import io.ktor.server.routing.*
30-
import io.ktor.server.routing.get
3130
import io.ktor.server.websocket.*
3231
import kotlinx.html.*
3332
import org.apache.commons.io.FileUtils
@@ -126,6 +125,7 @@ object Main {
126125

127126
val jsonModelServer = DeprecatedLightModelServer(localModelClient)
128127
val repositoriesManager = RepositoriesManager(localModelClient)
128+
val repositoryOverview = RepositoryOverview(repositoriesManager)
129129
val historyHandler = HistoryHandler(localModelClient, repositoriesManager)
130130
val contentExplorer = ContentExplorer(localModelClient, repositoriesManager)
131131
val modelReplicationServer = ModelReplicationServer(repositoriesManager)
@@ -148,6 +148,7 @@ object Main {
148148

149149
modelServer.init(this)
150150
historyHandler.init(this)
151+
repositoryOverview.init(this)
151152
contentExplorer.init(this)
152153
jsonModelServer.init(this)
153154
modelReplicationServer.init(this)
@@ -174,7 +175,7 @@ object Main {
174175
h1 { +"Model Server" }
175176
ul {
176177
li {
177-
a("history/") { +"Model History" }
178+
a("repos/") { +"View Repositories on the Model Server" }
178179
}
179180
li {
180181
a("json/") { +"JSON API for JavaScript clients" }

model-server/src/main/kotlin/org/modelix/model/server/handlers/ContentExplorer.kt

Lines changed: 38 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -29,28 +29,10 @@ class ContentExplorer(private val client: IModelClient, private val repoManager:
2929
return nodeList
3030
}
3131

32-
private val allVersions: Set<CLVersion>
33-
get() {
34-
val versions = linkedSetOf<CLVersion>()
35-
for (repoId in repoManager.getRepositories()) {
36-
val hash = repoManager.getVersionHash(repoId.getBranchReference()) ?: continue
37-
val version = CLVersion(hash, client.storeCache)
38-
var current: CLVersion? = version
39-
while (current != null) {
40-
versions.add(current)
41-
current = current.baseVersion
42-
}
43-
}
44-
return versions
45-
}
46-
4732
fun init(application: Application) {
4833
application.routing {
4934
get("/content/") {
50-
call.respondHtmlTemplate(PageWithMenuBar("content/", "..")) {
51-
headContent {title("Content Explorer")}
52-
bodyContent {contentOverviewBody()}
53-
}
35+
call.respondRedirect("../repos/")
5436
}
5537
get("/content/{versionHash}/") {
5638
val versionHash = call.parameters["versionHash"]
@@ -60,13 +42,13 @@ class ContentExplorer(private val client: IModelClient, private val repoManager:
6042
}
6143
val tree = CLVersion.loadFromHash(versionHash, client.storeCache).getTree()
6244
val rootNode = PNodeAdapter(ITree.ROOT_ID, TreePointer(tree))
63-
call.respondHtmlTemplate(PageWithMenuBar("content/", "../..")) {
45+
call.respondHtmlTemplate(PageWithMenuBar("repos/", "../..")) {
6446
headContent {
6547
title("Content Explorer")
6648
link("../../public/content-explorer.css", rel = "stylesheet")
6749
script("text/javascript", src = "../../public/content-explorer.js") {}
6850
}
69-
bodyContent {contentPageBody(rootNode)}
51+
bodyContent {contentPageBody(rootNode, versionHash)}
7052
}
7153
}
7254
get("/content/{versionHash}/{nodeId}/") {
@@ -88,25 +70,12 @@ class ContentExplorer(private val client: IModelClient, private val repoManager:
8870
}
8971
}
9072

91-
private fun FlowContent.contentOverviewBody() {
92-
h1 { +"Model Server Content" }
93-
h2 { +"Select a Version" }
94-
95-
if (allVersions.isEmpty()) {
96-
span { +"No versions available." }
97-
} else {
98-
ul {
99-
for (version in allVersions) {
100-
li {
101-
a(href = "$version/"){+"$version"}
102-
}
103-
}
104-
}
105-
}
106-
}
107-
108-
private fun FlowContent.contentPageBody(rootNode: PNodeAdapter) {
73+
private fun FlowContent.contentPageBody(rootNode: PNodeAdapter, versionHash: String) {
10974
h1 {+"Model Server Content"}
75+
small {
76+
style = "color: #888; text-align: center; margin-bottom: 15px;"
77+
+versionHash
78+
}
11079
div {
11180
style = "display: flex;"
11281
button(classes="btn") {
@@ -175,33 +144,41 @@ class ContentExplorer(private val client: IModelClient, private val repoManager:
175144
div { +"No roles." }
176145
return
177146
}
178-
table {
179-
thead {
180-
tr {
181-
th { +"PropertyRole" }
182-
th { +"Value" }
147+
if (node.getPropertyRoles().isEmpty()) {
148+
div { +"No properties." }
149+
} else {
150+
table {
151+
thead {
152+
tr {
153+
th { +"PropertyRole" }
154+
th { +"Value" }
155+
}
183156
}
184-
}
185-
for (propertyRole in node.getPropertyRoles()) {
186-
tr {
187-
td { +propertyRole }
188-
td { +(node.getPropertyValue(propertyRole) ?: "null") }
157+
for (propertyRole in node.getPropertyRoles()) {
158+
tr {
159+
td { +propertyRole }
160+
td { +(node.getPropertyValue(propertyRole) ?: "null") }
161+
}
189162
}
190163
}
191164
}
192-
table {
193-
thead {
194-
tr {
195-
th { +"ReferenceRole" }
196-
th { +"Value" }
165+
if (node.getReferenceRoles().isEmpty()) {
166+
div { +"No references." }
167+
} else {
168+
table {
169+
thead {
170+
tr {
171+
th { +"ReferenceRole" }
172+
th { +"Value" }
173+
}
197174
}
198-
}
199-
for (referenceRole in node.getReferenceRoles()) {
200-
tr {
201-
td { +referenceRole }
202-
td {
203-
// TODO MODELIX-387
204-
// +"${node.getReferenceTarget(referenceRole)}"
175+
for (referenceRole in node.getReferenceRoles()) {
176+
tr {
177+
td { +referenceRole }
178+
td {
179+
// TODO MODELIX-387
180+
// +"${node.getReferenceTarget(referenceRole)}"
181+
}
205182
}
206183
}
207184
}

model-server/src/main/kotlin/org/modelix/model/server/handlers/HistoryHandler.kt

Lines changed: 13 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -27,28 +27,20 @@ import org.modelix.model.server.templates.PageWithMenuBar
2727
import java.time.LocalDateTime
2828
import java.time.format.DateTimeFormatter
2929

30-
class HistoryHandler(val client: IModelClient, val repositoriesManager: RepositoriesManager) {
31-
30+
class HistoryHandler(val client: IModelClient, private val repositoriesManager: RepositoriesManager) {
3231

3332
fun init(application: Application) {
3433
application.routing {
3534
get("/history/") {
36-
call.respondHtmlTemplate(PageWithMenuBar("history/","..")) {
37-
headContent {
38-
title("History: Choose Repository")
39-
}
40-
bodyContent {
41-
buildMainPage()
42-
}
43-
}
35+
call.respondRedirect("../repos/")
4436
}
4537
get("/history/{repoId}/{branch}/") {
4638
val repositoryId = RepositoryId(call.parameters["repoId"]!!)
4739
val branch = repositoryId.getBranchReference(call.parameters["branch"]!!)
4840
val params = call.request.queryParameters
4941
val limit = toInt(params["limit"], 500)
5042
val skip = toInt(params["skip"], 0)
51-
call.respondHtmlTemplate(PageWithMenuBar("history/", "../../..")) {
43+
call.respondHtmlTemplate(PageWithMenuBar("repos/", "../../..")) {
5244
headContent {
5345
style {
5446
+"""
@@ -103,46 +95,6 @@ class HistoryHandler(val client: IModelClient, val repositoriesManager: Reposito
10395
repositoriesManager.mergeChanges(repositoryAndBranch, newVersion.getContentHash())
10496
}
10597

106-
private fun FlowContent.buildMainPage() {
107-
h1 { +"Choose Repository" }
108-
val repositories = repositoriesManager.getRepositories()
109-
if (repositories.isEmpty()) {
110-
p { i { +"No repositories available, add one" } }
111-
} else {
112-
table {
113-
thead {
114-
tr {
115-
th { +"Repository" }
116-
th { +"Branch" }
117-
}
118-
}
119-
tbody {
120-
for (repository in repositories) {
121-
val branches = repositoriesManager.getBranches(repository)
122-
tr {
123-
td {
124-
rowSpan = branches.size.coerceAtLeast(1).toString()
125-
+repository.id
126-
}
127-
if (branches.isEmpty()) {
128-
td { }
129-
} else {
130-
for (branch in branches) {
131-
td {
132-
a {
133-
href = "${branch.repositoryId.id}/${branch.branchName}/"
134-
+branch.branchName
135-
}
136-
}
137-
}
138-
}
139-
}
140-
}
141-
}
142-
}
143-
}
144-
}
145-
14698
private fun HEAD.repositoryPageStyle() {
14799
style {
148100
+"""
@@ -230,7 +182,10 @@ class HistoryHandler(val client: IModelClient, val repositoriesManager: Reposito
230182
th { +"Author" }
231183
th { +"Time" }
232184
th { +"Operations" }
233-
th { }
185+
th {
186+
colSpan = "2"
187+
+"Actions"
188+
}
234189
}
235190
}
236191
tbody {
@@ -291,6 +246,12 @@ class HistoryHandler(val client: IModelClient, val repositoriesManager: Reposito
291246
}
292247
}
293248
}
249+
td {
250+
style = "white-space: nowrap;"
251+
a("/../../../content/${version.getContentHash()}/") {
252+
+"Explore Content"
253+
}
254+
}
294255
td {
295256
form(action = "revert", method = FormMethod.post) {
296257
hiddenInput(name = "from") { value = latestVersion.getContentHash() }
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package org.modelix.model.server.handlers
2+
3+
import io.ktor.server.application.*
4+
import io.ktor.server.html.*
5+
import io.ktor.server.routing.*
6+
import kotlinx.html.*
7+
import org.modelix.model.server.templates.PageWithMenuBar
8+
9+
class RepositoryOverview(private val repoManager: RepositoriesManager) {
10+
11+
fun init(application: Application) {
12+
application.routing {
13+
get("/repos/") {
14+
call.respondHtmlTemplate(PageWithMenuBar("repos/", "..")) {
15+
headContent { title("Repositories") }
16+
bodyContent { buildMainPage() }
17+
}
18+
}
19+
}
20+
}
21+
22+
private fun FlowContent.buildMainPage() {
23+
h1 { +"Choose Repository" }
24+
val repositories = repoManager.getRepositories()
25+
if (repositories.isEmpty()) {
26+
p { i { +"No repositories available, add one" } }
27+
} else {
28+
table {
29+
thead {
30+
tr {
31+
th { +"Repository" }
32+
th { +"Branch" }
33+
th {
34+
colSpan = "2"
35+
+"Actions"
36+
}
37+
}
38+
}
39+
tbody {
40+
for (repository in repositories) {
41+
val branches = repoManager.getBranches(repository)
42+
tr {
43+
td {
44+
rowSpan = branches.size.coerceAtLeast(1).plus(1).toString()
45+
+repository.id
46+
}
47+
}
48+
if (branches.isEmpty()) {
49+
tr {
50+
td { }
51+
td { }
52+
td { }
53+
}
54+
} else {
55+
for (branch in branches) {
56+
tr {
57+
td {
58+
span {
59+
+branch.branchName
60+
}
61+
}
62+
td {
63+
a("../history/${branch.repositoryId.id}/${branch.branchName}/") {
64+
+"Show History"
65+
}
66+
}
67+
td {
68+
val latestVersion = repoManager.getVersion(branch)
69+
?: throw RuntimeException("Branch not found: $branch")
70+
a("../content/${latestVersion.getContentHash()}/") {
71+
+"Explore Latest Version"
72+
}
73+
}
74+
}
75+
}
76+
}
77+
}
78+
}
79+
}
80+
}
81+
}
82+
}

model-server/src/main/kotlin/org/modelix/model/server/templates/PageWithMenuBar.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ class PageWithMenuBar(val activePage: String, val baseUrl: String) : Template<HT
2323
height = "70px"
2424
}
2525
}
26-
val menuItems = mapOf("history/" to "History",
27-
"content/" to "Content",
26+
val menuItems = mapOf("repos/" to "Repositories",
2827
"json/" to "JSON API",
2928
"headers" to "HTTP Headers",
3029
"user" to "JWT token and permissions")

0 commit comments

Comments
 (0)