@@ -5,9 +5,11 @@ import io.ktor.server.application.Application
5
5
import io.ktor.server.application.call
6
6
import io.ktor.server.html.respondHtml
7
7
import io.ktor.server.html.respondHtmlTemplate
8
+ import io.ktor.server.request.receive
8
9
import io.ktor.server.response.respondRedirect
9
10
import io.ktor.server.response.respondText
10
11
import io.ktor.server.routing.get
12
+ import io.ktor.server.routing.post
11
13
import io.ktor.server.routing.routing
12
14
import kotlinx.html.BODY
13
15
import kotlinx.html.FlowContent
@@ -24,6 +26,7 @@ import kotlinx.html.li
24
26
import kotlinx.html.link
25
27
import kotlinx.html.script
26
28
import kotlinx.html.small
29
+ import kotlinx.html.stream.appendHTML
27
30
import kotlinx.html.style
28
31
import kotlinx.html.table
29
32
import kotlinx.html.td
@@ -67,20 +70,46 @@ class ContentExplorer(private val client: IModelClient, private val repoManager:
67
70
get(" /content/{versionHash}/" ) {
68
71
val versionHash = call.parameters[" versionHash" ]
69
72
if (versionHash.isNullOrEmpty()) {
70
- call.respondText(" version not found" , status = HttpStatusCode .InternalServerError )
73
+ call.respondText(" version not found" , status = HttpStatusCode .BadRequest )
71
74
return @get
72
75
}
76
+
73
77
val tree = CLVersion .loadFromHash(versionHash, client.storeCache).getTree()
74
78
val rootNode = PNodeAdapter (ITree .ROOT_ID , TreePointer (tree))
79
+
75
80
call.respondHtmlTemplate(PageWithMenuBar (" repos/" , " ../.." )) {
76
81
headContent {
77
82
title(" Content Explorer" )
78
83
link(" ../../public/content-explorer.css" , rel = " stylesheet" )
79
84
script(" text/javascript" , src = " ../../public/content-explorer.js" ) {}
80
85
}
81
- bodyContent { contentPageBody(rootNode, versionHash) }
86
+ bodyContent { contentPageBody(rootNode, versionHash, emptySet() ) }
82
87
}
83
88
}
89
+ post(" /content/{versionHash}/" ) {
90
+ val versionHash = call.parameters[" versionHash" ]
91
+ if (versionHash.isNullOrEmpty()) {
92
+ call.respondText(" version not found" , status = HttpStatusCode .BadRequest )
93
+ return @post
94
+ }
95
+ val expandedNodes = call.receive<ContentExplorerExpandedNodes >()
96
+
97
+ val tree = CLVersion .loadFromHash(versionHash, client.storeCache).getTree()
98
+ val rootNode = PNodeAdapter (ITree .ROOT_ID , TreePointer (tree))
99
+
100
+ var expandedNodeIds = expandedNodes.expandedNodeIds
101
+ if (expandedNodes.expandAll) {
102
+ expandedNodeIds = expandedNodeIds + collectExpandableChildNodes(rootNode, expandedNodes.expandedNodeIds)
103
+ }
104
+
105
+ call.respondText(
106
+ buildString {
107
+ appendHTML().ul(" treeRoot" ) {
108
+ nodeItem(rootNode, expandedNodeIds)
109
+ }
110
+ },
111
+ )
112
+ }
84
113
get(" /content/{versionHash}/{nodeId}/" ) {
85
114
val id = call.parameters[" nodeId" ]!! .toLong()
86
115
var found: PNodeAdapter ? = null
@@ -100,7 +129,21 @@ class ContentExplorer(private val client: IModelClient, private val repoManager:
100
129
}
101
130
}
102
131
103
- private fun FlowContent.contentPageBody (rootNode : PNodeAdapter , versionHash : String ) {
132
+ private fun collectExpandableChildNodes (node : PNodeAdapter , expandedNodeIds : Set <String >): Set <String > {
133
+ if (expandedNodeIds.contains(node.nodeId.toString())) {
134
+ val newIds = mutableSetOf<String >()
135
+ for (child in node.allChildren) {
136
+ newIds.addAll(collectExpandableChildNodes(child as PNodeAdapter , expandedNodeIds))
137
+ }
138
+ return newIds
139
+ }
140
+ if (node.allChildren.toList().isNotEmpty()) {
141
+ return setOf (node.nodeId.toString())
142
+ }
143
+ return emptySet()
144
+ }
145
+
146
+ private fun FlowContent.contentPageBody (rootNode : PNodeAdapter , versionHash : String , expandedNodeIds : Set <String >) {
104
147
h1 { + " Model Server Content" }
105
148
small {
106
149
style = " color: #888; text-align: center; margin-bottom: 15px;"
@@ -120,18 +163,19 @@ class ContentExplorer(private val client: IModelClient, private val repoManager:
120
163
div {
121
164
id = " treeWrapper"
122
165
ul(" treeRoot" ) {
123
- nodeItem(rootNode)
166
+ nodeItem(rootNode, expandedNodeIds )
124
167
}
125
168
}
126
169
div {
127
170
id = " nodeInspector"
128
171
}
129
172
}
130
173
131
- private fun UL.nodeItem (node : PNodeAdapter ) {
174
+ private fun UL.nodeItem (node : PNodeAdapter , expandedNodeIds : Set < String > ) {
132
175
li(" nodeItem" ) {
176
+ val expanded = expandedNodeIds.contains(node.nodeId.toString())
133
177
if (node.allChildren.toList().isNotEmpty()) {
134
- div(" expander" ) { unsafe { + " ▶" } }
178
+ div(if (expanded) " expander expander-expanded " else " expander" ) { unsafe { + " ▶" } }
135
179
}
136
180
div(" nameField" ) {
137
181
attributes[" data-nodeid" ] = node.nodeId.toString()
@@ -157,10 +201,12 @@ class ContentExplorer(private val client: IModelClient, private val repoManager:
157
201
}
158
202
}
159
203
}
160
- div(" nested" ) {
161
- ul(" nodeTree" ) {
162
- for (child in node.allChildren) {
163
- nodeItem(child as PNodeAdapter )
204
+ div(if (expanded) " nested active" else " nested" ) {
205
+ if (expanded) {
206
+ ul(" nodeTree" ) {
207
+ for (child in node.allChildren) {
208
+ nodeItem(child as PNodeAdapter , expandedNodeIds)
209
+ }
164
210
}
165
211
}
166
212
}
0 commit comments