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 ddc76a4 commit 9950bc0
Show file tree
Hide file tree
Showing 14 changed files with 254 additions and 120 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,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 @@ -13,7 +13,7 @@ import nl.avisi.structurizr.site.generatr.site.model.HomePageViewModel
import nl.avisi.structurizr.site.generatr.site.model.PageViewModel
import nl.avisi.structurizr.site.generatr.site.model.SearchViewModel
import nl.avisi.structurizr.site.generatr.site.model.SoftwareSystemCodePageViewModel
import nl.avisi.structurizr.site.generatr.site.model.SoftwareSystemComponentPageViewModel
import nl.avisi.structurizr.site.generatr.site.model.SoftwareSystemContainerComponentsPageViewModel
import nl.avisi.structurizr.site.generatr.site.model.SoftwareSystemContainerDecisionPageViewModel
import nl.avisi.structurizr.site.generatr.site.model.SoftwareSystemContainerDecisionsPageViewModel
import nl.avisi.structurizr.site.generatr.site.model.SoftwareSystemContainerPageViewModel
Expand All @@ -35,7 +35,7 @@ import nl.avisi.structurizr.site.generatr.site.model.WorkspaceDocumentationSecti
import nl.avisi.structurizr.site.generatr.site.views.homePage
import nl.avisi.structurizr.site.generatr.site.views.searchPage
import nl.avisi.structurizr.site.generatr.site.views.softwareSystemCodePage
import nl.avisi.structurizr.site.generatr.site.views.softwareSystemComponentPage
import nl.avisi.structurizr.site.generatr.site.views.softwareSystemContainerComponentsPage
import nl.avisi.structurizr.site.generatr.site.views.softwareSystemContainerDecisionPage
import nl.avisi.structurizr.site.generatr.site.views.softwareSystemContainerDecisionsPage
import nl.avisi.structurizr.site.generatr.site.views.softwareSystemContainerPage
Expand Down Expand Up @@ -191,7 +191,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 @@ -221,6 +220,13 @@ private fun generateHtmlFiles(context: GeneratorContext, branchDir: File) {
}
}

it.containers
.filter { container ->
container.hasComponents() 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 @@ -245,7 +251,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 ComponentTabViewModel(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,23 @@
package nl.avisi.structurizr.site.generatr.site.model

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

fun SoftwareSystemPageViewModel.createComponentsTabViewModel(
generatorContext: GeneratorContext,
softwareSystem: SoftwareSystem,
) = buildList {
softwareSystem
.containers
.filter { container ->
container.hasComponents() or
generatorContext.workspace.views.imageViews.any { it.elementId in container.id } }
.map {
ComponentTabViewModel(
this@createComponentsTabViewModel,
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 = container.hasComponents() or images.isNotEmpty()
val containerTabs = createComponentsTabViewModel(generatorContext, container.softwareSystem)
companion object {
fun url(container: Container) = "${url(container.softwareSystem, Tab.COMPONENT)}/${container.name.normalize()}"
}
}

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
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,28 @@ class LinkViewModelTest : ViewModelTest() {
val viewModel = LinkViewModel(pageViewModel, "Some other page", "/some-other-page")
assertThat(viewModel.relativeHref).isEqualTo("../../some-other-page/")
}

@ParameterizedTest
@ValueSource(strings = ["/some-page/sibling-page-1/", "/some-page/sibling-page-2/"])
fun `sibling links are active when the previous url path matches`(pageHref: String) {
val pageViewModel = pageViewModel(pageHref)
val viewModel = LinkViewModel(pageViewModel, "Some page", "/some-page/sibling-page-3/", Match.SIBLING)
assertThat(viewModel.active).isTrue()
}

@ParameterizedTest
@ValueSource(strings = ["/some-other-page/sibling-page-1/", "/some-other-page/sibling-page-2/"])
fun `sibling links are not active when the previous url path doesn't match`(pageHref: String) {
val pageViewModel = pageViewModel(pageHref)
val viewModel = LinkViewModel(pageViewModel, "Some page", "/some-page/sibling-page-1", Match.SIBLING)
assertThat(viewModel.active).isFalse()
}

@Test
fun `sibling links are only active when previous page url path matches previous href path url`() {
val expectInactiveSiblingMatch = LinkViewModel(pageViewModel("/page/two/"), "Some page", "/some-page/", Match.SIBLING)
val expectActiveSiblingMatch = LinkViewModel(pageViewModel("/page/two"), "Some page", "/page/one", Match.SIBLING)
assertThat(expectInactiveSiblingMatch.active).isFalse()
assertThat(expectActiveSiblingMatch.active).isTrue()
}
}

This file was deleted.

Loading

0 comments on commit 9950bc0

Please sign in to comment.