Skip to content

Commit

Permalink
Add container tabs on component view
Browse files Browse the repository at this point in the history
  • Loading branch information
LunarN0va committed Apr 25, 2024
1 parent ad91115 commit f4f2d34
Show file tree
Hide file tree
Showing 15 changed files with 262 additions and 131 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.structurizr.Workspace
import com.structurizr.model.Container
import com.structurizr.model.SoftwareSystem
import com.structurizr.view.ViewSet
import nl.avisi.structurizr.site.generatr.site.GeneratorContext

val Workspace.includedSoftwareSystems: List<SoftwareSystem>
get() = model.softwareSystems.filter {
Expand All @@ -13,6 +14,8 @@ val Workspace.includedSoftwareSystems: List<SoftwareSystem>

fun Workspace.hasImageViews(id: String) = views.imageViews.any { it.elementId == id }

fun Workspace.hasComponentDiagrams(container: Container) = views.componentViews.any { it.container == container}

val SoftwareSystem.hasContainers
get() = this.containers.isNotEmpty()

Expand All @@ -22,6 +25,12 @@ val SoftwareSystem.includedProperties
val Container.hasComponents
get() = this.components.isNotEmpty()

fun SoftwareSystem.firstContainerName(generatorContext: GeneratorContext) = containers
.firstOrNull { container ->
generatorContext.workspace.hasComponentDiagrams(container) or
generatorContext.workspace.hasImageViews(container.id) }
?.name?.normalize()

fun SoftwareSystem.hasDecisions() = documentation.decisions.isNotEmpty()

fun SoftwareSystem.hasContainerDecisions() = containers.any { it.hasDecisions() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ private class WriterWithElementLinks(
private fun getUrlToElement(element: Element?, page: String? = null): String {
val path = when (element) {
is SoftwareSystem -> "/${element.name?.normalize()}/${page?.let { page } ?: "container"}/".asUrlToDirectory(url)
is Container -> "/${element.parent?.name?.normalize()}/${page?.let { page } ?: "component"}/".asUrlToDirectory(url)
is Container -> "/${element.parent?.name?.normalize()}/${page?.let { page } ?: "component"}/${element.name?.normalize()}".asUrlToDirectory(url)
is Component -> "/${element.parent?.parent?.name?.normalize()}/${page?.let { page } ?: "code"}/".asUrlToDirectory(url)
else -> throw IllegalStateException("Not supported element")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@ private fun generateHtmlFiles(context: GeneratorContext, branchDir: File) {
add { writeHtmlFile(branchDir, SoftwareSystemHomePageViewModel(context, it)) }
add { writeHtmlFile(branchDir, SoftwareSystemContextPageViewModel(context, it)) }
add { writeHtmlFile(branchDir, SoftwareSystemContainerPageViewModel(context, it)) }
add { writeHtmlFile(branchDir, SoftwareSystemComponentPageViewModel(context, it)) }
add { writeHtmlFile(branchDir, SoftwareSystemCodePageViewModel(context, it)) }
add { writeHtmlFile(branchDir, SoftwareSystemDynamicPageViewModel(context, it)) }
add { writeHtmlFile(branchDir, SoftwareSystemDeploymentPageViewModel(context, it)) }
Expand Down Expand Up @@ -174,6 +173,13 @@ private fun generateHtmlFiles(context: GeneratorContext, branchDir: File) {
}
}

it.containers
.filter { container ->
context.workspace.views.componentViews.any { containerView -> containerView.container == container } or
context.workspace.views.imageViews.any { imageView -> imageView.elementId in container.id } }
.forEach { container ->
add { writeHtmlFile(branchDir, SoftwareSystemContainerComponentsPageViewModel(context, container)) } }

it.documentation.sections.filter { section -> section.order != 1 }.forEach { section ->
add { writeHtmlFile(branchDir, SoftwareSystemSectionPageViewModel(context, it, section)) }
}
Expand All @@ -198,7 +204,7 @@ private fun writeHtmlFile(exportDir: File, viewModel: PageViewModel) {
is SoftwareSystemContainerDecisionsPageViewModel -> softwareSystemContainerDecisionsPage(viewModel)
is SoftwareSystemContainerSectionPageViewModel -> softwareSystemContainerSectionPage(viewModel)
is SoftwareSystemContainerSectionsPageViewModel -> softwareSystemContainerSectionsPage(viewModel)
is SoftwareSystemComponentPageViewModel -> softwareSystemComponentPage(viewModel)
is SoftwareSystemContainerComponentsPageViewModel -> softwareSystemContainerComponentsPage(viewModel)
is SoftwareSystemCodePageViewModel -> softwareSystemCodePage(viewModel)
is SoftwareSystemDynamicPageViewModel -> softwareSystemDynamicPage(viewModel)
is SoftwareSystemDeploymentPageViewModel -> softwareSystemDeploymentPage(viewModel)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package nl.avisi.structurizr.site.generatr.site.model

data class ContainerTabViewModel(val pageViewModel: SoftwareSystemPageViewModel, val title: String, val url: String) {
val link = LinkViewModel(pageViewModel, title, url)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package nl.avisi.structurizr.site.generatr.site.model

import com.structurizr.model.SoftwareSystem
import nl.avisi.structurizr.site.generatr.hasComponentDiagrams
import nl.avisi.structurizr.site.generatr.hasImageViews
import nl.avisi.structurizr.site.generatr.site.GeneratorContext

fun SoftwareSystemPageViewModel.createContainersTabViewModel(
generatorContext: GeneratorContext,
softwareSystem: SoftwareSystem,
) = buildList {
softwareSystem
.containers
.filter { container ->
generatorContext.workspace.hasComponentDiagrams(container) or
generatorContext.workspace.hasImageViews(container.id) }
.map {
ContainerTabViewModel(
this@createContainersTabViewModel,
it.name,
SoftwareSystemContainerComponentsPageViewModel.url(it)
)
}
.forEach { add(it) }
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package nl.avisi.structurizr.site.generatr.site.model

import com.structurizr.model.Container
import nl.avisi.structurizr.site.generatr.normalize
import nl.avisi.structurizr.site.generatr.site.GeneratorContext

class SoftwareSystemContainerComponentsPageViewModel(generatorContext: GeneratorContext, container: Container) :
SoftwareSystemPageViewModel(generatorContext, container.softwareSystem, Tab.COMPONENT) {
override val url = url(container)
val diagrams = generatorContext.workspace.views.componentViews
.filter { it.container == container }
.sortedBy { it.key }
.map { DiagramViewModel.forView(this, it, generatorContext.svgFactory) }
val images = generatorContext.workspace.views.imageViews
.filter { it.elementId in container.id }
.sortedBy { it.key }
.map { ImageViewViewModel(it) }

val visible = diagrams.isNotEmpty() or images.isNotEmpty()
val containerTabs = createContainersTabViewModel(generatorContext, container.softwareSystem)
companion object {
fun url(container: Container) = "${url(container.softwareSystem, Tab.COMPONENT)}/${container.name.normalize()}"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,15 @@ open class SoftwareSystemPageViewModel(
enum class Tab { HOME, SYSTEM_CONTEXT, CONTAINER, COMPONENT, CODE, DYNAMIC, DEPLOYMENT, DEPENDENCIES, DECISIONS, SECTIONS }

inner class TabViewModel(val tab: Tab, match: Match = Match.EXACT) {
val link = LinkViewModel(this@SoftwareSystemPageViewModel, title, url(softwareSystem, tab), match)
val link = when (tab) {
Tab.COMPONENT -> LinkViewModel(
this@SoftwareSystemPageViewModel,
title,
"${url(softwareSystem, tab)}/${softwareSystem.firstContainerName(generatorContext)}",
match
)
else -> LinkViewModel(this@SoftwareSystemPageViewModel, title, url(softwareSystem, tab), match)
}

private val title
get() = when (tab) {
Expand Down Expand Up @@ -50,7 +58,7 @@ open class SoftwareSystemPageViewModel(
TabViewModel(Tab.HOME),
TabViewModel(Tab.SYSTEM_CONTEXT),
TabViewModel(Tab.CONTAINER),
TabViewModel(Tab.COMPONENT),
TabViewModel(Tab.COMPONENT, Match.SIBLING),
TabViewModel(Tab.CODE),
TabViewModel(Tab.DYNAMIC),
TabViewModel(Tab.DEPLOYMENT),
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package nl.avisi.structurizr.site.generatr.site.views

import kotlinx.html.HTML
import kotlinx.html.div
import kotlinx.html.li
import kotlinx.html.ul
import nl.avisi.structurizr.site.generatr.site.model.SoftwareSystemContainerComponentsPageViewModel

fun HTML.softwareSystemContainerComponentsPage(viewModel: SoftwareSystemContainerComponentsPageViewModel) {
if (viewModel.visible) {
softwareSystemPage(viewModel) {
div(classes = "tabs") {
ul(classes = "m-0 is-flex-wrap-wrap is flex-shrink-1 is flex-grow-0") {
viewModel.containerTabs
.forEach {
li(classes = if (it.link.active) "is-active" else null) {
link(it.link)
}
}
}
}
viewModel.diagrams.forEach { diagram(it) }
viewModel.images.forEach { image(it) }
}
} else
redirectUpPage()
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ class PlantUmlExporterTest {
assertThat(diagram.definition.withoutC4HeaderAndFooter()).isEqualTo(
"""
System_Boundary("System1_boundary", "System 1", ${'$'}tags="") {
Container(System1.Container1, "Container 1", ${'$'}techn="", ${'$'}descr="", ${'$'}tags="", ${'$'}link="../system-1/component/")
Container(System1.Container1, "Container 1", ${'$'}techn="", ${'$'}descr="", ${'$'}tags="", ${'$'}link="../system-1/component/container-1/")
}
""".trimIndent()
)
Expand All @@ -157,7 +157,7 @@ class PlantUmlExporterTest {
assertThat(diagram.definition.withoutStructurizrHeaderAndFooter()).isEqualTo(
"""
rectangle "System 1\n<size:10>[Software System]</size>" <<System1>> {
rectangle "==Container 1\n<size:10>[Container]</size>" <<System1.Container1>> as System1.Container1 [[../system-1/component/]]
rectangle "==Container 1\n<size:10>[Container]</size>" <<System1.Container1>> as System1.Container1 [[../system-1/component/container-1/]]
}
""".trimIndent()
)
Expand Down

This file was deleted.

Loading

0 comments on commit f4f2d34

Please sign in to comment.