Skip to content

Commit

Permalink
Merge pull request #340 from jp7677/nested-groups
Browse files Browse the repository at this point in the history
Hide software system not attached to group in menu
  • Loading branch information
jp7677 authored Oct 25, 2023
2 parents 045692e + a0d3e48 commit b83d687
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 32 deletions.
16 changes: 11 additions & 5 deletions docs/example/workspace.dsl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ workspace "Big Bank plc" "This is an example workspace to illustrate the key fea
model {
customer = person "Personal Banking Customer" "A customer of the bank, with personal bank accounts." "Customer"

acquirer = softwaresystem "Acquirer" "Facilitates PIN transactions for merchants."
acquirer = softwaresystem "Acquirer" "Facilitates PIN transactions for merchants." "External System"

enterprise "Big Bank plc" {
supportStaff = person "Customer Service Staff" "Customer service staff within the bank." "Bank Staff" {
Expand Down Expand Up @@ -158,15 +158,18 @@ workspace "Big Bank plc" "This is an example workspace to illustrate the key fea
views {
properties {
"c4plantuml.elementProperties" "true"
"c4plantuml.tags" "true"
"generatr.style.colors.primary" "#485fc7"
"generatr.style.colors.secondary" "#ffffff"
"generatr.style.faviconPath" "site/favicon.ico"
"generatr.style.logoPath" "site/logo.png"

// Absolute URL's like "https://example.com/custom.css" are also supported
"generatr.style.customStylesheet" "site/custom.css"
//"generatr.style.customStylesheet" "https://example.com/custom.css"

"generatr.svglink.target" "_self"

// full list of available "generatr.markdown.flexmark.extensions"
// Full list of available "generatr.markdown.flexmark.extensions"
// "Abbreviation,Admonition,AnchorLink,Aside,Attributes,Autolink,Definition,Emoji,EnumeratedReference,Footnotes,GfmIssues,GfmStrikethroughSubscript,GfmTaskList,GfmUsers,GitLab,Ins,Macros,MediaTags,ResizableImage,Superscript,Tables,TableOfContents,SimulatedTableOfContents,Typographic,WikiLinks,XWikiMacro,YAMLFrontMatter,YouTubeLink"
// see https://github.com/vsch/flexmark-java/wiki/Extensions
// ATTENTION:
Expand Down Expand Up @@ -255,15 +258,18 @@ workspace "Big Bank plc" "This is an example workspace to illustrate the key fea
shape Person
}
element "Customer" {
background #08427b
background #686868
}
element "Bank Staff" {
background #999999
background #08427B
}
element "Software System" {
background #1168bd
color #ffffff
}
element "External System" {
background #686868
}
element "Existing System" {
background #999999
color #ffffff
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,28 @@ class MenuViewModel(generatorContext: GeneratorContext, private val pageViewMode
createMenuItem(it.name, SoftwareSystemPageViewModel.url(it, SoftwareSystemPageViewModel.Tab.HOME), false)
}

private val groupSeparator = generatorContext.workspace.model.properties["structurizr.groupSeparator"]

private val softwareSystemPaths = generatorContext.workspace.model.includedSoftwareSystems
.filter { it.group != null }
.map { it.group + groupSeparator + it.name }
.sortedBy { it.lowercase() }

private fun createMenuItem(title: String, href: String, exact: Boolean = true) =
LinkViewModel(pageViewModel, title, href, exact)

fun softwareSystemNodes(): MenuNodeViewModel {
data class MutableMenuNode(val name: String, val children: MutableList<MutableMenuNode>) {
fun toMenuNode(): MenuNodeViewModel = MenuNodeViewModel(name, children.map { it.toMenuNode() })
}
if (groupSeparator == null)
throw IllegalStateException("Property structurizr.groupSeparator not defined for model") // This is also validated earlier by structurizr when parsing the model

val rootNode = MutableMenuNode("", mutableListOf())

softwareSystemPaths.forEach { path ->
var currentNode = rootNode
path.split(delimiter).forEach { part ->
path.split(groupSeparator).forEach { part ->
val existingNode = currentNode.children.find { it.name == part }
currentNode = if (existingNode == null) {
val newNode = MutableMenuNode(part, mutableListOf())
Expand All @@ -51,10 +60,4 @@ class MenuViewModel(generatorContext: GeneratorContext, private val pageViewMode

return rootNode.toMenuNode()
}

private val softwareSystemPaths = generatorContext.workspace.model.includedSoftwareSystems
.map { it.group + "/" + it.name }
.sortedBy { it.lowercase() }

private val delimiter = '/'
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package nl.avisi.structurizr.site.generatr.site.views

import kotlinx.html.*
import nl.avisi.structurizr.site.generatr.site.GeneratorContext
import nl.avisi.structurizr.site.generatr.site.model.LinkViewModel
import nl.avisi.structurizr.site.generatr.site.model.MenuNodeViewModel
import nl.avisi.structurizr.site.generatr.site.model.MenuViewModel

fun DIV.menu(viewModel: MenuViewModel, nestGroups:Boolean) {
fun DIV.menu(viewModel: MenuViewModel, nestGroups: Boolean) {
aside(classes = "menu p-3") {
generalSection(viewModel.generalItems)
softwareSystemsSection(viewModel, nestGroups)
Expand All @@ -18,10 +17,10 @@ private fun ASIDE.generalSection(items: List<LinkViewModel>) {
menuItemLinks(items)
}

private fun ASIDE.softwareSystemsSection(viewModel: MenuViewModel, nestGroups:Boolean) {
private fun ASIDE.softwareSystemsSection(viewModel: MenuViewModel, nestGroups: Boolean) {
p(classes = "menu-label") { +"Software systems" }
if(nestGroups){
ul(classes = "listree menu-list has-site-branding"){
if (nestGroups) {
ul(classes = "listree menu-list has-site-branding") {
buildHtmlTree(viewModel.softwareSystemNodes(), viewModel).invoke(this)
}
} else {
Expand Down Expand Up @@ -49,21 +48,14 @@ private fun buildHtmlTree(node: MenuNodeViewModel, viewModel: MenuViewModel): UL
}
}

if (node.name.isNotEmpty() && node.children.isNotEmpty()) {
if (node.name.isNotEmpty() && node.children.isNotEmpty()) {
li {
if(node.name == "null"){
div(classes = "listree-submenu-heading") {
+"No Group"
}
} else {
div(classes = "listree-submenu-heading") {
+node.name
}
div(classes = "listree-submenu-heading") {
+node.name
}

ul(classes = "listree-submenu-items") {
for (child in node.children) {
buildHtmlTree(child,viewModel).invoke(this)
buildHtmlTree(child, viewModel).invoke(this)
}
}
}
Expand Down
8 changes: 5 additions & 3 deletions src/main/resources/assets/css/treeview.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,19 @@ ul.listree {
ul.listree-submenu-items {
list-style: none;
white-space: nowrap;
padding-left: 10px
padding-left: 10px;
}

div.listree-submenu-heading.collapsed:before {
content: "\25B6";
margin-right: 4px
display: inline-block;
min-width: 20px;
}

div.listree-submenu-heading.expanded:before {
content: "\25BC";
margin-right: 4px
display: inline-block;
min-width: 20px;
}

.scrollable-menu {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ class MenuViewModelTest : ViewModelTest() {
@Test
fun `show nested groups in software systems list`() {
val generatorContext = generatorContext(branches = listOf("main", "branch-2"), currentBranch = "main")
generatorContext.workspace.views.configuration.addProperty("generatr.site.nestGroups","true")
generatorContext.workspace.views.configuration.addProperty("generatr.site.nestGroups", "true")
generatorContext.workspace.model.addProperty("structurizr.groupSeparator", "/")
generatorContext.workspace.model.addSoftwareSystem("System 1").group = "Group 1"
generatorContext.workspace.model.addSoftwareSystem("System 2").group = "Group 1"
generatorContext.workspace.model.addSoftwareSystem("System 3").group = "Group 2"
Expand Down

0 comments on commit b83d687

Please sign in to comment.