From ed6c8ecd12143d4f5a49d066bd342a2527c07050 Mon Sep 17 00:00:00 2001 From: Declan Lynch Date: Fri, 20 Oct 2023 14:21:57 -0400 Subject: [PATCH 1/7] Initial code attempts --- .../site/generatr/site/SiteGenerator.kt | 2 ++ .../SoftwareSystemDynamicPageViewModel.kt | 20 +++++++++++++++++++ .../site/views/SoftwareSystemDynamicPage.kt | 15 ++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDynamicPageViewModel.kt create mode 100644 src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDynamicPage.kt diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/SiteGenerator.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/SiteGenerator.kt index 5f8a15cf..aa1c76c2 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/SiteGenerator.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/SiteGenerator.kt @@ -133,6 +133,7 @@ private fun generateHtmlFiles(context: GeneratorContext, branchDir: File) { add { writeHtmlFile(branchDir, SoftwareSystemContextPageViewModel(context, it)) } add { writeHtmlFile(branchDir, SoftwareSystemContainerPageViewModel(context, it)) } add { writeHtmlFile(branchDir, SoftwareSystemComponentPageViewModel(context, it)) } + add { writeHtmlFile(branchDir, SoftwareSystemDynamicPageViewModel(context, it)) } add { writeHtmlFile(branchDir, SoftwareSystemDeploymentPageViewModel(context, it)) } add { writeHtmlFile(branchDir, SoftwareSystemDependenciesPageViewModel(context, it)) } add { writeHtmlFile(branchDir, SoftwareSystemDecisionsPageViewModel(context, it)) } @@ -185,6 +186,7 @@ private fun writeHtmlFile(exportDir: File, viewModel: PageViewModel) { is SoftwareSystemContainerSectionPageViewModel -> softwareSystemContainerSectionPage(viewModel) is SoftwareSystemContainerSectionsPageViewModel -> softwareSystemContainerSectionsPage(viewModel) is SoftwareSystemComponentPageViewModel -> softwareSystemComponentPage(viewModel) + is SoftwareSystemDynamicPageViewModel -> softwareSystemDynamicPage(viewModel) is SoftwareSystemDeploymentPageViewModel -> softwareSystemDeploymentPage(viewModel) is SoftwareSystemDependenciesPageViewModel -> softwareSystemDependenciesPage(viewModel) is SoftwareSystemDecisionPageViewModel -> softwareSystemDecisionPage(viewModel) diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDynamicPageViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDynamicPageViewModel.kt new file mode 100644 index 00000000..9e2c10ad --- /dev/null +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDynamicPageViewModel.kt @@ -0,0 +1,20 @@ +package nl.avisi.structurizr.site.generatr.site.model + +import com.structurizr.model.SoftwareSystem +import nl.avisi.structurizr.site.generatr.hasComponentViews +import nl.avisi.structurizr.site.generatr.site.GeneratorContext + +class SoftwareSystemDynamicPageViewModel(generatorContext: GeneratorContext, softwareSystem: SoftwareSystem) : + SoftwareSystemPageViewModel(generatorContext, softwareSystem, Tab.COMPONENT) { + + var diagrams = List() + + var dia = generatorContext.workspace.model.getSoftwareSystemWithName(softwareSystem.name)?.containers?.forEach(){ container -> + diagrams = diagrams + generatorContext.workspace.views.dynamicViews + .filter { it.softwareSystem.name == container.name } + .sortedBy { it.key } + .map { DiagramViewModel.forView(this, it, generatorContext.svgFactory) } + } + + val visible = diagrams.isNotEmpty() +} diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDynamicPage.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDynamicPage.kt new file mode 100644 index 00000000..588e4f73 --- /dev/null +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDynamicPage.kt @@ -0,0 +1,15 @@ +package nl.avisi.structurizr.site.generatr.site.views + +import kotlinx.html.HTML +import nl.avisi.structurizr.site.generatr.site.model.SoftwareSystemDynamicPageViewModel + +fun HTML.softwareSystemDynamicPage(viewModel: SoftwareSystemDynamicPageViewModel) { + if (viewModel.visible) + softwareSystemPage(viewModel) { + viewModel.diagrams.forEach { + diagram(it) + } + } + else + redirectUpPage() +} From bcb190a40118ae401009b2b8eae1e8cef4392741 Mon Sep 17 00:00:00 2001 From: Declan Lynch Date: Fri, 20 Oct 2023 15:09:29 -0400 Subject: [PATCH 2/7] Expose dynamic views for software systems. --- .../site/generatr/StructurizrUtilities.kt | 3 +++ .../SoftwareSystemDynamicPageViewModel.kt | 18 ++++++------------ .../site/model/SoftwareSystemPageViewModel.kt | 6 +++++- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/StructurizrUtilities.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/StructurizrUtilities.kt index e9e37bf8..5ef8234c 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/StructurizrUtilities.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/StructurizrUtilities.kt @@ -42,5 +42,8 @@ fun ViewSet.hasContainerViews(softwareSystem: SoftwareSystem) = fun ViewSet.hasComponentViews(softwareSystem: SoftwareSystem) = componentViews.any { it.softwareSystem == softwareSystem } +fun ViewSet.hasDynamicViews(softwareSystem: SoftwareSystem) = + dynamicViews.any { it.softwareSystem == softwareSystem } + fun ViewSet.hasDeploymentViews(softwareSystem: SoftwareSystem) = deploymentViews.any { it.softwareSystem == softwareSystem } diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDynamicPageViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDynamicPageViewModel.kt index 9e2c10ad..61107892 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDynamicPageViewModel.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDynamicPageViewModel.kt @@ -5,16 +5,10 @@ import nl.avisi.structurizr.site.generatr.hasComponentViews import nl.avisi.structurizr.site.generatr.site.GeneratorContext class SoftwareSystemDynamicPageViewModel(generatorContext: GeneratorContext, softwareSystem: SoftwareSystem) : - SoftwareSystemPageViewModel(generatorContext, softwareSystem, Tab.COMPONENT) { - - var diagrams = List() - - var dia = generatorContext.workspace.model.getSoftwareSystemWithName(softwareSystem.name)?.containers?.forEach(){ container -> - diagrams = diagrams + generatorContext.workspace.views.dynamicViews - .filter { it.softwareSystem.name == container.name } - .sortedBy { it.key } - .map { DiagramViewModel.forView(this, it, generatorContext.svgFactory) } - } - - val visible = diagrams.isNotEmpty() + SoftwareSystemPageViewModel(generatorContext, softwareSystem, Tab.DYNAMIC) { + val diagrams = generatorContext.workspace.views.dynamicViews + .filter { it.softwareSystem == softwareSystem } + .sortedBy { it.key } + .map { DiagramViewModel.forView(this, it, generatorContext.svgFactory) } + val visible = generatorContext.workspace.views.hasComponentViews(softwareSystem) } diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemPageViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemPageViewModel.kt index 81288c2d..c163e39d 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemPageViewModel.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemPageViewModel.kt @@ -9,7 +9,7 @@ open class SoftwareSystemPageViewModel( private val softwareSystem: SoftwareSystem, tab: Tab ) : PageViewModel(generatorContext) { - enum class Tab { HOME, SYSTEM_CONTEXT, CONTAINER, COMPONENT, DEPLOYMENT, DEPENDENCIES, DECISIONS, SECTIONS } + enum class Tab { HOME, SYSTEM_CONTEXT, CONTAINER, COMPONENT, DYNAMIC, DEPLOYMENT, DEPENDENCIES, DECISIONS, SECTIONS } inner class TabViewModel(val tab: Tab, exactLink: Boolean = true) { val link = LinkViewModel(this@SoftwareSystemPageViewModel, title, url(softwareSystem, tab), exactLink) @@ -20,6 +20,7 @@ open class SoftwareSystemPageViewModel( Tab.SYSTEM_CONTEXT -> "Context views" Tab.CONTAINER -> "Container views" Tab.COMPONENT -> "Component views" + Tab.DYNAMIC -> "Dynamic views" Tab.DEPLOYMENT -> "Deployment views" Tab.DEPENDENCIES -> "Dependencies" Tab.DECISIONS -> "Decisions" @@ -33,6 +34,7 @@ open class SoftwareSystemPageViewModel( Tab.SYSTEM_CONTEXT -> generatorContext.workspace.views.hasSystemContextViews(softwareSystem) Tab.CONTAINER -> generatorContext.workspace.views.hasContainerViews(softwareSystem) Tab.COMPONENT -> generatorContext.workspace.views.hasComponentViews(softwareSystem) + Tab.DYNAMIC -> generatorContext.workspace.views.hasDynamicViews(softwareSystem) Tab.DEPLOYMENT -> generatorContext.workspace.views.hasDeploymentViews(softwareSystem) Tab.DECISIONS -> softwareSystem.hasDecisions() or softwareSystem.hasContainerDecisions() Tab.SECTIONS -> softwareSystem.hasDocumentationSections() or softwareSystem.hasContainerDocumentationSections() @@ -47,6 +49,7 @@ open class SoftwareSystemPageViewModel( TabViewModel(Tab.SYSTEM_CONTEXT), TabViewModel(Tab.CONTAINER), TabViewModel(Tab.COMPONENT), + TabViewModel(Tab.DYNAMIC), TabViewModel(Tab.DEPLOYMENT), TabViewModel(Tab.DEPENDENCIES), TabViewModel(Tab.DECISIONS, exactLink = false), @@ -63,6 +66,7 @@ open class SoftwareSystemPageViewModel( Tab.SYSTEM_CONTEXT -> "$home/context" Tab.CONTAINER -> "$home/container" Tab.COMPONENT -> "$home/component" + Tab.DYNAMIC -> "$home/dynamic" Tab.DEPLOYMENT -> "$home/deployment" Tab.DEPENDENCIES -> "$home/dependencies" Tab.DECISIONS -> "$home/decisions" From fdebc9f189c0b8e99cff0d03bef2c90423fea8de Mon Sep 17 00:00:00 2001 From: Declan Lynch Date: Fri, 20 Oct 2023 15:12:17 -0400 Subject: [PATCH 3/7] Added tests for dynamic views tab --- .../site/model/SoftwareSystemPageViewModelTest.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemPageViewModelTest.kt b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemPageViewModelTest.kt index f48b718a..c9431aff 100644 --- a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemPageViewModelTest.kt +++ b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemPageViewModelTest.kt @@ -61,6 +61,7 @@ class SoftwareSystemPageViewModelTest : ViewModelTest() { Tab.SYSTEM_CONTEXT, Tab.CONTAINER, Tab.COMPONENT, + Tab.DYNAMIC, Tab.DEPLOYMENT, Tab.DEPENDENCIES, Tab.DECISIONS, @@ -72,6 +73,7 @@ class SoftwareSystemPageViewModelTest : ViewModelTest() { "Context views", "Container views", "Component views", + "Dynamic views", "Deployment views", "Dependencies", "Decisions", @@ -146,6 +148,18 @@ class SoftwareSystemPageViewModelTest : ViewModelTest() { assertThat(getTab(viewModel, Tab.COMPONENT).visible).isTrue() } + @Test + fun `dynamic views tab only visible when component diagrams available`() { + val generatorContext = generatorContext() + val softwareSystem = generatorContext.workspace.model.addSoftwareSystem("Some software system") + val container = softwareSystem.addContainer("Backend") + val viewModel = SoftwareSystemPageViewModel(generatorContext, softwareSystem, Tab.HOME) + + assertThat(getTab(viewModel, Tab.COMPONENT).visible).isFalse() + generatorContext.workspace.views.createDynamicView(container, "component", "description") + assertThat(getTab(viewModel, Tab.DYNAMIC).visible).isTrue() + } + @Test fun `deployment views tab only visible when deployment diagrams available`() { val generatorContext = generatorContext() From a7b31b32eec944ea15e8a1cf7269a7af197f20d6 Mon Sep 17 00:00:00 2001 From: Declan Lynch Date: Fri, 20 Oct 2023 15:18:51 -0400 Subject: [PATCH 4/7] minor code update --- .../generatr/site/model/SoftwareSystemDynamicPageViewModel.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDynamicPageViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDynamicPageViewModel.kt index 61107892..cfb16b6d 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDynamicPageViewModel.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDynamicPageViewModel.kt @@ -2,6 +2,7 @@ package nl.avisi.structurizr.site.generatr.site.model import com.structurizr.model.SoftwareSystem import nl.avisi.structurizr.site.generatr.hasComponentViews +import nl.avisi.structurizr.site.generatr.hasDynamicViews import nl.avisi.structurizr.site.generatr.site.GeneratorContext class SoftwareSystemDynamicPageViewModel(generatorContext: GeneratorContext, softwareSystem: SoftwareSystem) : @@ -10,5 +11,5 @@ class SoftwareSystemDynamicPageViewModel(generatorContext: GeneratorContext, sof .filter { it.softwareSystem == softwareSystem } .sortedBy { it.key } .map { DiagramViewModel.forView(this, it, generatorContext.svgFactory) } - val visible = generatorContext.workspace.views.hasComponentViews(softwareSystem) + val visible = generatorContext.workspace.views.hasDynamicViews(softwareSystem) } From 1013079ae751c2a6b12608a6099285359442217b Mon Sep 17 00:00:00 2001 From: Declan Lynch Date: Fri, 20 Oct 2023 16:52:26 -0400 Subject: [PATCH 5/7] Fixed minor error in the dynamic tab test --- .../generatr/site/model/SoftwareSystemPageViewModelTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemPageViewModelTest.kt b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemPageViewModelTest.kt index c9431aff..d1b35d19 100644 --- a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemPageViewModelTest.kt +++ b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemPageViewModelTest.kt @@ -149,13 +149,13 @@ class SoftwareSystemPageViewModelTest : ViewModelTest() { } @Test - fun `dynamic views tab only visible when component diagrams available`() { + fun `dynamic views tab only visible when dynamic diagrams available`() { val generatorContext = generatorContext() val softwareSystem = generatorContext.workspace.model.addSoftwareSystem("Some software system") val container = softwareSystem.addContainer("Backend") val viewModel = SoftwareSystemPageViewModel(generatorContext, softwareSystem, Tab.HOME) - assertThat(getTab(viewModel, Tab.COMPONENT).visible).isFalse() + assertThat(getTab(viewModel, Tab.DYNAMIC).visible).isFalse() generatorContext.workspace.views.createDynamicView(container, "component", "description") assertThat(getTab(viewModel, Tab.DYNAMIC).visible).isTrue() } From e6dead313d90eeaa17787235438dcbf0e9ba2a91 Mon Sep 17 00:00:00 2001 From: Declan Lynch Date: Sat, 21 Oct 2023 10:04:59 -0400 Subject: [PATCH 6/7] Added additional tests for the Dynamic PageView Model --- .../SoftwareSystemDynamicPageViewModelTest.kt | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDynamicPageViewModelTest.kt diff --git a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDynamicPageViewModelTest.kt b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDynamicPageViewModelTest.kt new file mode 100644 index 00000000..ba69bc42 --- /dev/null +++ b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDynamicPageViewModelTest.kt @@ -0,0 +1,63 @@ +package nl.avisi.structurizr.site.generatr.site.model + +import assertk.assertThat +import assertk.assertions.containsExactly +import assertk.assertions.isEqualTo +import assertk.assertions.isFalse +import com.structurizr.model.SoftwareSystem +import kotlin.test.Test + +class SoftwareSystemDynamicPageViewModelTest : ViewModelTest() { + private val generatorContext = generatorContext() + private val softwareSystem: SoftwareSystem = generatorContext.workspace.model + .addSoftwareSystem("Software system").also { + val backend = it.addContainer("Backend") + val frontend = it.addContainer("Frontend") + generatorContext.workspace.views.createDynamicView(backend, "backend-dynamic", "Dynamic view 1") + generatorContext.workspace.views.createDynamicView(frontend, "frontend-dynamic", "Dynamic view 2") + } + + @Test + fun `active tab`() { + val viewModel = SoftwareSystemDynamicPageViewModel(generatorContext, softwareSystem) + + assertThat(viewModel.tabs.single { it.link.active }.tab) + .isEqualTo(SoftwareSystemPageViewModel.Tab.DYNAMIC) + } + + @Test + fun `diagrams sorted by key`() { + val viewModel = SoftwareSystemDynamicPageViewModel(generatorContext, softwareSystem) + + assertThat(viewModel.diagrams).containsExactly( + DiagramViewModel( + "backend-dynamic", + "Backend - Dynamic", + """""", + 800, + ImageViewModel(viewModel, "/svg/backend-dynamic.svg"), + ImageViewModel(viewModel, "/png/backend-dynamic.png"), + ImageViewModel(viewModel, "/puml/backend-dynamic.puml") + ), + DiagramViewModel( + "frontend-dynamic", + "Frontend - Dynamic", + """""", + 800, + ImageViewModel(viewModel, "/svg/frontend-dynamic.svg"), + ImageViewModel(viewModel, "/png/frontend-dynamic.png"), + ImageViewModel(viewModel, "/puml/frontend-dynamic.puml") + ) + ) + } + + @Test + fun `hidden view`() { + val viewModel = SoftwareSystemDynamicPageViewModel( + generatorContext, + generatorContext.workspace.model.addSoftwareSystem("Software system 2") + ) + + assertThat(viewModel.visible).isFalse() + } +} From 41aaca2685909857bf703d1dc289ca07e83a5bb3 Mon Sep 17 00:00:00 2001 From: Declan Lynch Date: Sun, 22 Oct 2023 09:20:22 -0400 Subject: [PATCH 7/7] Remove unused import --- .../generatr/site/model/SoftwareSystemDynamicPageViewModel.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDynamicPageViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDynamicPageViewModel.kt index cfb16b6d..8e9264ca 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDynamicPageViewModel.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDynamicPageViewModel.kt @@ -1,7 +1,6 @@ package nl.avisi.structurizr.site.generatr.site.model import com.structurizr.model.SoftwareSystem -import nl.avisi.structurizr.site.generatr.hasComponentViews import nl.avisi.structurizr.site.generatr.hasDynamicViews import nl.avisi.structurizr.site.generatr.site.GeneratorContext