Skip to content

Commit d25f3c9

Browse files
committed
fix(model-server): fixed inconsistencies and streamlined styling
1 parent 4f81e06 commit d25f3c9

File tree

11 files changed

+334
-339
lines changed

11 files changed

+334
-339
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@ import io.ktor.serialization.kotlinx.json.*
2020
import io.ktor.server.application.*
2121
import io.ktor.server.engine.*
2222
import io.ktor.server.html.*
23+
import io.ktor.server.http.content.*
2324
import io.ktor.server.netty.*
2425
import io.ktor.server.plugins.contentnegotiation.*
2526
import io.ktor.server.plugins.cors.routing.*
2627
import io.ktor.server.plugins.forwardedheaders.*
2728
import io.ktor.server.response.*
2829
import io.ktor.server.routing.*
30+
import io.ktor.server.routing.get
2931
import io.ktor.server.websocket.*
3032
import kotlinx.html.*
3133
import org.apache.commons.io.FileUtils
@@ -150,6 +152,9 @@ object Main {
150152
jsonModelServer.init(this)
151153
modelReplicationServer.init(this)
152154
routing {
155+
static("/public") {
156+
resources("public")
157+
}
153158
get("/") {
154159
call.respondHtmlTemplate(PageWithMenuBar("root", ".")) {
155160
headContent {

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

Lines changed: 21 additions & 190 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class ContentExplorer(private val client: IModelClient, private val repoManager:
4848
application.routing {
4949
get("/content/") {
5050
call.respondHtmlTemplate(PageWithMenuBar("content/", "..")) {
51-
headContent {contentOverviewHead()}
51+
headContent {title("Content Explorer")}
5252
bodyContent {contentOverviewBody()}
5353
}
5454
}
@@ -61,7 +61,11 @@ class ContentExplorer(private val client: IModelClient, private val repoManager:
6161
val tree = CLVersion.loadFromHash(versionHash, client.storeCache).getTree()
6262
val rootNode = PNodeAdapter(ITree.ROOT_ID, TreePointer(tree))
6363
call.respondHtmlTemplate(PageWithMenuBar("content/", "../..")) {
64-
headContent {contentPageHead()}
64+
headContent {
65+
title("Content Explorer")
66+
link("../../public/content-explorer.css", rel = "stylesheet")
67+
script("text/javascript", src = "../../public/content-explorer.js") {}
68+
}
6569
bodyContent {contentPageBody(rootNode)}
6670
}
6771
}
@@ -84,19 +88,6 @@ class ContentExplorer(private val client: IModelClient, private val repoManager:
8488
}
8589
}
8690

87-
private fun HEAD.contentOverviewHead() {
88-
title("Content Explorer")
89-
style {
90-
unsafe {
91-
+"""
92-
body {
93-
font-family: sans-serif;
94-
}
95-
""".trimIndent()
96-
}
97-
}
98-
}
99-
10091
private fun FlowContent.contentOverviewBody() {
10192
h1 { +"Model Server Content" }
10293
h2 { +"Select a Version" }
@@ -114,181 +105,18 @@ class ContentExplorer(private val client: IModelClient, private val repoManager:
114105
}
115106
}
116107

117-
private fun HEAD.contentPageHead() {
118-
title("Content Explorer")
119-
style {
120-
+"""
121-
body {
122-
font-family: sans-serif;
123-
}
124-
table {
125-
border-collapse: collapse;
126-
font-family: sans-serif;
127-
font-size: 0.9em;
128-
border-radius:6px;
129-
}
130-
thead tr {
131-
background-color: #009879;
132-
color: #ffffff;
133-
text-align: left;
134-
}
135-
th {
136-
padding: 8px 10px;
137-
}
138-
td {
139-
padding: 5px 10px;
140-
}
141-
tbody tr {
142-
border-bottom: 1px solid #dddddd;
143-
border-left: 1px solid #dddddd;
144-
border-right: 1px solid #dddddd;
145-
}
146-
tbody tr:nth-of-type(even) {
147-
background-color: #f3f3f3;
148-
}
149-
tbody tr:last-of-type
150-
border-bottom: 2px solid #009879;
151-
}
152-
tbody tr.active-row {
153-
font-weight: bold;
154-
color: #009879;
155-
}
156-
.expander {
157-
cursor: pointer;
158-
margin-top: 12px;
159-
font-size: 20px;
160-
float: left;
161-
}
162-
.expander-expanded {
163-
transition: .1s linear;
164-
transform: rotate(90deg);
165-
transform-origin: center center;
166-
}
167-
.nested {
168-
display: none;
169-
margin-left: 9px;
170-
border-left: 1px solid #999999;
171-
}
172-
.active {
173-
display: block;
174-
}
175-
.nodeTree {
176-
list-style-type: none;
177-
}
178-
.treeRoot {
179-
list-style-type: none;
180-
margin-top: 5px;
181-
float: left;
182-
}
183-
.referenceRoles {
184-
margin-top: 5px;
185-
}
186-
.nodeItem {
187-
padding-top: 10px;
188-
}
189-
.nameField {
190-
margin-left: 30px;
191-
padding: 5px;
192-
border: 1px solid;
193-
border-radius: 10px;
194-
width: fit-content;
195-
cursor: pointer;
196-
}
197-
.nameField:hover {
198-
background-color: #e6e6e6;
199-
}
200-
.selectedNameField {
201-
background-color: #c9c9c9;
202-
}
203-
#treeWrapper {
204-
position: absolute;
205-
}
206-
#nodeInspector {
207-
position: fixed;
208-
top: 10%;
209-
left: 65%;
210-
width: 35%;
211-
overflow-scroll;
212-
z-index: 1;
213-
display: none;
214-
background-color: #ffffff;
215-
}
216-
""".trimIndent()
217-
}
218-
script("text/javascript") {
219-
unsafe {
220-
+"""
221-
async function createInspectorDetails(nodeId) {
222-
let response = await window.fetch(window.location.pathname + nodeId + '/');
223-
let nodeInspector = document.getElementById('nodeInspector');
224-
nodeInspector.innerHTML = await response.text();
225-
nodeInspector.style.display = 'block';
226-
}
227-
document.addEventListener('DOMContentLoaded', () => {
228-
var expander = document.getElementsByClassName('expander');
229-
var nameField = document.getElementsByClassName('nameField');
230-
var expandAllBtn = document.getElementById('expandAllBtn');
231-
var collapseAllBtn = document.getElementById('collapseAllBtn');
232-
233-
for (let i = 0; i < nameField.length; i++) {
234-
nameField[i].addEventListener('click', function() {
235-
let isSelected = this.classList.contains('selectedNameField');
236-
if (isSelected) {
237-
document.getElementById('nodeInspector').style.display = 'none';
238-
} else {
239-
createInspectorDetails(this.dataset.nodeid);
240-
}
241-
let selected = document.getElementsByClassName('selectedNameField');
242-
for (let j = 0; j < selected.length; j++) {
243-
selected[j].classList.remove('selectedNameField');
244-
}
245-
if (!isSelected) {
246-
this.classList.add('selectedNameField');
247-
}
248-
});
249-
}
250-
251-
for (let i = 0; i < expander.length; i++) {
252-
expander[i].addEventListener('click', function() {
253-
this.parentElement.querySelector(".nested").classList.toggle('active');
254-
this.classList.toggle('expander-expanded');
255-
});
256-
}
257-
258-
expandAllBtn.addEventListener('click', function () {
259-
var nested = document.getElementsByClassName("nested")
260-
for (let i=0; i < nested.length; i++) {
261-
nested[i].classList.add('active');
262-
}
263-
for (let i = 0; i < expander.length; i++) {
264-
expander[i].classList.add('expander-expanded')
265-
}
266-
});
267-
268-
collapseAllBtn.addEventListener('click', function () {
269-
var nested = document.getElementsByClassName('nested')
270-
for (let i=0; i < nested.length; i++) {
271-
nested[i].classList.remove('active');
272-
}
273-
for (let i = 0; i < expander.length; i++) {
274-
expander[i].classList.remove('expander-expanded')
275-
}
276-
});
277-
});
278-
""".trimIndent()
279-
}
280-
}
281-
}
282-
283108
private fun FlowContent.contentPageBody(rootNode: PNodeAdapter) {
284109
h1 {+"Model Server Content"}
285-
button {
286-
id = "expandAllBtn"
287-
+"Expand all"
288-
}
289-
button {
290-
id = "collapseAllBtn"
291-
+"Collapse all"
110+
div {
111+
style = "display: flex;"
112+
button(classes="btn") {
113+
id = "expandAllBtn"
114+
+"Expand all"
115+
}
116+
button(classes="btn") {
117+
id = "collapseAllBtn"
118+
+"Collapse all"
119+
}
292120
}
293121
div {
294122
id = "treeWrapper"
@@ -370,8 +198,11 @@ class ContentExplorer(private val client: IModelClient, private val repoManager:
370198
}
371199
for (referenceRole in node.getReferenceRoles()) {
372200
tr {
373-
td { +"$referenceRole" }
374-
td { +"Not yet implemented" }
201+
td { +referenceRole }
202+
td {
203+
// TODO MODELIX-387
204+
// +"${node.getReferenceTarget(referenceRole)}"
205+
}
375206
}
376207
}
377208
}

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

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -71,45 +71,45 @@ class DeprecatedLightModelServer(val client: LocalModelClient) {
7171
call.respondHtmlTemplate(PageWithMenuBar("json/", ".."), status=HttpStatusCode.OK) {
7272
headContent {
7373
title("JSON API")
74-
style {
75-
unsafe {
76-
+"""
77-
body {
78-
font-family: sans-serif;
79-
}""".trimMargin()
80-
}
81-
}
8274
}
8375
bodyContent {
8476
h1 { +"JSON API" }
8577
table {
86-
tr {
87-
td { +"GET /{repositoryId}/" }
88-
td { + "Returns the model content of the latest version on the master branch." }
89-
}
90-
tr {
91-
td { +"GET /{repositoryId}/{versionHash}/" }
92-
td { + "Returns the model content of the specified version on the master branch." }
93-
}
94-
tr {
95-
td { +"GET /{repositoryId}/{versionHash}/poll" }
96-
td { + "" }
97-
}
98-
tr {
99-
td { +"POST /{repositoryId}/init" }
100-
td { + "Initializes a new repository." }
101-
}
102-
tr {
103-
td { +"POST /{repositoryId}/{versionHash}/update" }
104-
td {
105-
+ "Applies the delta to the specified version of the model and merges"
106-
+" it into the master branch. Return the model content after the merge."
78+
thead {
79+
tr {
80+
th { +"Route" }
81+
th { +"Description" }
10782
}
10883
}
109-
tr {
110-
td { +"WEBSOCKET /{repositoryId}/ws" }
111-
td {
112-
+ "WebSocket for exchanging model deltas."
84+
tbody {
85+
tr {
86+
td { +"GET /{repositoryId}/" }
87+
td { +"Returns the model content of the latest version on the master branch." }
88+
}
89+
tr {
90+
td { +"GET /{repositoryId}/{versionHash}/" }
91+
td { +"Returns the model content of the specified version on the master branch." }
92+
}
93+
tr {
94+
td { +"GET /{repositoryId}/{versionHash}/poll" }
95+
td { +"" }
96+
}
97+
tr {
98+
td { +"POST /{repositoryId}/init" }
99+
td { +"Initializes a new repository." }
100+
}
101+
tr {
102+
td { +"POST /{repositoryId}/{versionHash}/update" }
103+
td {
104+
+"Applies the delta to the specified version of the model and merges"
105+
+" it into the master branch. Return the model content after the merge."
106+
}
107+
}
108+
tr {
109+
td { +"WEBSOCKET /{repositoryId}/ws" }
110+
td {
111+
+"WebSocket for exchanging model deltas."
112+
}
113113
}
114114
}
115115
}

0 commit comments

Comments
 (0)