From 677b4cef884eb646a737799816713683701c6d83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Ga=C5=82uszka?= Date: Thu, 23 Feb 2023 23:30:02 +0100 Subject: [PATCH 01/11] Introduce Container ADRs in Decision Tab --- .../adr/0001-record-architecture-decisions.md | 2 +- .../adr/0001-record-architecture-decisions.md | 19 ++++++++ docs/example/workspace.dsl | 1 + .../site/generatr/StructurizrUtilities.kt | 5 ++ .../site/generatr/site/SiteGenerator.kt | 11 +++++ .../site/model/ContainersTableViewModel.kt | 17 +++++++ ...areSystemContainerDecisionPageViewModel.kt | 20 ++++++++ ...reSystemContainerDecisionsPageViewModel.kt | 24 ++++++++++ .../SoftwareSystemDecisionsPageViewModel.kt | 12 ++++- .../SoftwareSystemSectionPageViewModel.kt | 2 +- .../SoftwareSystemContainerDecisionPage.kt | 11 +++++ .../SoftwareSystemContainerDecisionsPage.kt | 15 ++++++ .../site/views/SoftwareSystemDecisionsPage.kt | 10 +++- .../model/ContainersTableViewModelTest.kt | 47 +++++++++++++++++++ ...ystemContainerDecisionPageViewModelTest.kt | 40 ++++++++++++++++ ...stemContainerDecisionsPageViewModelTest.kt | 45 ++++++++++++++++++ ...oftwareSystemDecisionsPageViewModelTest.kt | 15 ++++++ 17 files changed, 291 insertions(+), 5 deletions(-) create mode 100644 docs/example/internet-banking-system/api-application/adr/0001-record-architecture-decisions.md create mode 100644 src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainersTableViewModel.kt create mode 100644 src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionPageViewModel.kt create mode 100644 src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionsPageViewModel.kt create mode 100644 src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionPage.kt create mode 100644 src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionsPage.kt create mode 100644 src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainersTableViewModelTest.kt create mode 100644 src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionPageViewModelTest.kt create mode 100644 src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionsPageViewModelTest.kt diff --git a/docs/example/internet-banking-system/adr/0001-record-architecture-decisions.md b/docs/example/internet-banking-system/adr/0001-record-architecture-decisions.md index 63f18d4d..498288fe 100644 --- a/docs/example/internet-banking-system/adr/0001-record-architecture-decisions.md +++ b/docs/example/internet-banking-system/adr/0001-record-architecture-decisions.md @@ -1,4 +1,4 @@ -# 1. Record architecture decisions +# 1. Record Internet Banking System architecture decisions Date: 2022-06-21 diff --git a/docs/example/internet-banking-system/api-application/adr/0001-record-architecture-decisions.md b/docs/example/internet-banking-system/api-application/adr/0001-record-architecture-decisions.md new file mode 100644 index 00000000..d9b55b2d --- /dev/null +++ b/docs/example/internet-banking-system/api-application/adr/0001-record-architecture-decisions.md @@ -0,0 +1,19 @@ +# 1. Record API Application architecture decision records + +Date: 2022-06-21 + +## Status + +Accepted + +## Context + +We need to record the architectural decisions made on this project. + +## Decision + +We will use Architecture Decision Records, as [described by Michael Nygard](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions). + +## Consequences + +See Michael Nygard's article, linked above. For a lightweight ADR toolset, see Nat Pryce's [adr-tools](https://github.com/npryce/adr-tools). diff --git a/docs/example/workspace.dsl b/docs/example/workspace.dsl index 3e2801d2..33d09b1a 100644 --- a/docs/example/workspace.dsl +++ b/docs/example/workspace.dsl @@ -42,6 +42,7 @@ workspace "Big Bank plc" "This is an example workspace to illustrate the key fea mobileApp = container "Mobile App" "Provides a limited subset of the Internet banking functionality to customers via their mobile device." "Xamarin" "Mobile App" webApplication = container "Web Application" "Delivers the static content and the Internet banking single page application." "Java and Spring MVC" apiApplication = container "API Application" "Provides Internet banking functionality via a JSON/HTTPS API." "Java and Spring MVC" { + !adrs internet-banking-system/api-application/adr signinController = component "Sign In Controller" "Allows users to sign in to the Internet Banking System." "Spring MVC Rest Controller" accountsSummaryController = component "Accounts Summary Controller" "Provides customers with a summary of their bank accounts." "Spring MVC Rest Controller" resetPasswordController = component "Reset Password Controller" "Allows users to reset their passwords with a single use URL." "Spring MVC Rest Controller" 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 67043ced..f4b924d1 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/StructurizrUtilities.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/StructurizrUtilities.kt @@ -1,5 +1,6 @@ package nl.avisi.structurizr.site.generatr +import com.structurizr.model.Container import com.structurizr.model.Location import com.structurizr.model.Model import com.structurizr.model.SoftwareSystem @@ -13,8 +14,12 @@ val SoftwareSystem.includedSoftwareSystem fun SoftwareSystem.hasDecisions() = documentation.decisions.isNotEmpty() +fun SoftwareSystem.hasContainerDecisions() = containers.flatMap { it.documentation.decisions }.isNotEmpty() + fun SoftwareSystem.hasDocumentationSections() = documentation.sections.size >= 2 +fun Container.hasDecisions() = documentation.decisions.isNotEmpty() + fun ViewSet.hasSystemContextViews(softwareSystem: SoftwareSystem) = systemContextViews.any { it.softwareSystem == softwareSystem } 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 b4aebcba..e35918cf 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 @@ -125,6 +125,15 @@ private fun generateHtmlFiles(context: GeneratorContext, exportDir: File) { add { writeHtmlFile(branchDir, SoftwareSystemDecisionPageViewModel(context, it, decision)) } } + it.containers + .filter { container -> container.documentation.decisions.isNotEmpty() } + .forEach { container -> + add { writeHtmlFile(branchDir, SoftwareSystemContainerDecisionsPageViewModel(context, container)) } + container.documentation.decisions.forEach { decision -> + add { writeHtmlFile(branchDir, SoftwareSystemContainerDecisionPageViewModel(context, container, decision)) } + } + } + it.documentation.sections.filter { section -> section.order != 1 }.forEach { section -> add { writeHtmlFile(branchDir, SoftwareSystemSectionPageViewModel(context, it, section)) } } @@ -144,6 +153,8 @@ private fun writeHtmlFile(exportDir: File, viewModel: PageViewModel) { is SoftwareSystemHomePageViewModel -> softwareSystemHomePage(viewModel) is SoftwareSystemContextPageViewModel -> softwareSystemContextPage(viewModel) is SoftwareSystemContainerPageViewModel -> softwareSystemContainerPage(viewModel) + is SoftwareSystemContainerDecisionPageViewModel -> softwareSystemContainerDecisionPage(viewModel) + is SoftwareSystemContainerDecisionsPageViewModel -> softwareSystemContainerDecisionsPage(viewModel) is SoftwareSystemComponentPageViewModel -> softwareSystemComponentPage(viewModel) is SoftwareSystemDeploymentPageViewModel -> softwareSystemDeploymentPage(viewModel) is SoftwareSystemDependenciesPageViewModel -> softwareSystemDependenciesPage(viewModel) diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainersTableViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainersTableViewModel.kt new file mode 100644 index 00000000..5d776be0 --- /dev/null +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainersTableViewModel.kt @@ -0,0 +1,17 @@ +package nl.avisi.structurizr.site.generatr.site.model + +import com.structurizr.model.Container + +fun PageViewModel.createContainerTableViewModel(containers: Collection, hrefFactory: (Container) -> String) = + TableViewModel.create { + headerRow(headerCell("#"), headerCell("Container Decisions")) + containers + .sortedBy { it.name } + .filter { it.documentation.decisions.isNotEmpty() } + .forEachIndexed { index, container -> + bodyRow( + cellWithIndex((index+1).toString()), + cellWithLink(this@createContainerTableViewModel, container.name, hrefFactory(container)) + ) + } + } diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionPageViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionPageViewModel.kt new file mode 100644 index 00000000..ead2f615 --- /dev/null +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionPageViewModel.kt @@ -0,0 +1,20 @@ +package nl.avisi.structurizr.site.generatr.site.model + +import com.structurizr.documentation.Decision +import com.structurizr.model.SoftwareSystem +import com.structurizr.model.Container +import nl.avisi.structurizr.site.generatr.normalize +import nl.avisi.structurizr.site.generatr.site.GeneratorContext + +class SoftwareSystemContainerDecisionPageViewModel( + generatorContext: GeneratorContext, container: Container, decision: Decision +) : SoftwareSystemPageViewModel(generatorContext, container.softwareSystem, Tab.DECISIONS) { + override val url = url(container, decision) + + val content = markdownToHtml(this, decision.content, generatorContext.svgFactory) + + companion object { + fun url(container: Container, decision: Decision) = + "${url(container.softwareSystem, Tab.DECISIONS)}/${container.name.normalize()}/${decision.id}" + } +} diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionsPageViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionsPageViewModel.kt new file mode 100644 index 00000000..b75fbe11 --- /dev/null +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionsPageViewModel.kt @@ -0,0 +1,24 @@ +package nl.avisi.structurizr.site.generatr.site.model + +import com.structurizr.documentation.Decision +import com.structurizr.model.Container +import com.structurizr.model.SoftwareSystem +import nl.avisi.structurizr.site.generatr.hasContainerDecisions +import nl.avisi.structurizr.site.generatr.hasDecisions +import nl.avisi.structurizr.site.generatr.normalize +import nl.avisi.structurizr.site.generatr.site.GeneratorContext + +class SoftwareSystemContainerDecisionsPageViewModel(generatorContext: GeneratorContext, container: Container) : + SoftwareSystemPageViewModel(generatorContext, container.softwareSystem, Tab.DECISIONS) { + override val url = url(container) + val containerName: String = container.name + val decisionsTable = createDecisionsTableViewModel(container.documentation.decisions) { + "$url/${it.id}" + } + + val visible = container.hasDecisions() + companion object { + fun url(container: Container) = + "${url(container.softwareSystem, Tab.DECISIONS)}/${container.name.normalize()}" + } +} diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDecisionsPageViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDecisionsPageViewModel.kt index 34e393c2..8ea49fb3 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDecisionsPageViewModel.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDecisionsPageViewModel.kt @@ -1,13 +1,23 @@ package nl.avisi.structurizr.site.generatr.site.model import com.structurizr.model.SoftwareSystem +import nl.avisi.structurizr.site.generatr.hasContainerDecisions import nl.avisi.structurizr.site.generatr.hasDecisions +import nl.avisi.structurizr.site.generatr.normalize import nl.avisi.structurizr.site.generatr.site.GeneratorContext class SoftwareSystemDecisionsPageViewModel(generatorContext: GeneratorContext, softwareSystem: SoftwareSystem) : SoftwareSystemPageViewModel(generatorContext, softwareSystem, Tab.DECISIONS) { + + val containerDecisionsTable = createContainerTableViewModel(softwareSystem.containers) { + "$url/${it.name.normalize()}" + } val decisionsTable = createDecisionsTableViewModel(softwareSystem.documentation.decisions) { "$url/${it.id}" } - val visible = softwareSystem.hasDecisions() + + val visibleContainerDecisions = softwareSystem.hasContainerDecisions() + val visibleSoftwareSystemDecisions = softwareSystem.hasDecisions() + + val visible = visibleSoftwareSystemDecisions or visibleContainerDecisions } diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemSectionPageViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemSectionPageViewModel.kt index 49738edf..9553a81e 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemSectionPageViewModel.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemSectionPageViewModel.kt @@ -6,7 +6,7 @@ import nl.avisi.structurizr.site.generatr.site.GeneratorContext class SoftwareSystemSectionPageViewModel( generatorContext: GeneratorContext, softwareSystem: SoftwareSystem, section: Section -) : SoftwareSystemPageViewModel(generatorContext, softwareSystem, Tab.DECISIONS) { +) : SoftwareSystemPageViewModel(generatorContext, softwareSystem, Tab.SECTIONS) { override val url = url(softwareSystem, section) val content = markdownToHtml(this, section.content, generatorContext.svgFactory) diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionPage.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionPage.kt new file mode 100644 index 00000000..85a5f17a --- /dev/null +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionPage.kt @@ -0,0 +1,11 @@ +package nl.avisi.structurizr.site.generatr.site.views + +import kotlinx.html.HTML +import kotlinx.html.h3 +import nl.avisi.structurizr.site.generatr.site.model.SoftwareSystemContainerDecisionPageViewModel + +fun HTML.softwareSystemContainerDecisionPage(viewModel: SoftwareSystemContainerDecisionPageViewModel) { + softwareSystemPage(viewModel) { + rawHtml(viewModel.content) + } +} diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionsPage.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionsPage.kt new file mode 100644 index 00000000..31083ae9 --- /dev/null +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionsPage.kt @@ -0,0 +1,15 @@ +package nl.avisi.structurizr.site.generatr.site.views + +import kotlinx.html.HTML +import kotlinx.html.h3 +import nl.avisi.structurizr.site.generatr.site.model.SoftwareSystemContainerDecisionsPageViewModel + +fun HTML.softwareSystemContainerDecisionsPage(viewModel: SoftwareSystemContainerDecisionsPageViewModel) { + if (viewModel.visible) + softwareSystemPage(viewModel) { + h3 { +(viewModel.containerName + " Decisions") } + table(viewModel.decisionsTable) + } + else + redirectUpPage() +} diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDecisionsPage.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDecisionsPage.kt index a00e8fc0..19f00005 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDecisionsPage.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDecisionsPage.kt @@ -4,10 +4,16 @@ import kotlinx.html.HTML import nl.avisi.structurizr.site.generatr.site.model.SoftwareSystemDecisionsPageViewModel fun HTML.softwareSystemDecisionsPage(viewModel: SoftwareSystemDecisionsPageViewModel) { - if (viewModel.visible) + if (viewModel.visible) { softwareSystemPage(viewModel) { - table(viewModel.decisionsTable) + if (viewModel.visibleContainerDecisions) { + table(viewModel.containerDecisionsTable) + } + if (viewModel.visibleSoftwareSystemDecisions) { + table(viewModel.decisionsTable) + } } + } else redirectUpPage() } diff --git a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainersTableViewModelTest.kt b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainersTableViewModelTest.kt new file mode 100644 index 00000000..5ba00ea3 --- /dev/null +++ b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainersTableViewModelTest.kt @@ -0,0 +1,47 @@ +package nl.avisi.structurizr.site.generatr.site.model + +import assertk.assertThat +import assertk.assertions.isEqualTo +import kotlin.test.Test + +class ContainersTableViewModelTest : ViewModelTest() { + + @Test + fun `no container with decisions available`() { + assertThat(pageViewModel().createContainerTableViewModel(emptySet()) { "href" }) + .isEqualTo( + TableViewModel.create { + containersTableHeaderRow() + } + ) + } + + @Test + fun `many containers shown if they have decisions`() { + val containers = generatorContext().workspace.model.addSoftwareSystem("Mock").also { + it.addContainer("Web Application") + it.addContainer("API Application") + .documentation.addDecision(createDecision("1","API Decision")) + it.addContainer("Mobile Application") + .documentation.addDecision(createDecision("1", "Mobile Decision")) + }.containers + val pageViewModel = pageViewModel() + assertThat(pageViewModel.createContainerTableViewModel(containers) { it.name }).isEqualTo( + TableViewModel.create { + containersTableHeaderRow() + bodyRow( + cellWithIndex("1"), + cellWithLink(pageViewModel, "API Application", "API Application"), + ) + bodyRow( + cellWithIndex("2"), + cellWithLink(pageViewModel, "Mobile Application", "Mobile Application") + ) + } + ) + } + + private fun TableViewModel.TableViewInitializerContext.containersTableHeaderRow() { + headerRow(headerCell("#"), headerCell("Container Decisions")) + } +} diff --git a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionPageViewModelTest.kt b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionPageViewModelTest.kt new file mode 100644 index 00000000..2524b365 --- /dev/null +++ b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionPageViewModelTest.kt @@ -0,0 +1,40 @@ +package nl.avisi.structurizr.site.generatr.site.model + +import assertk.assertThat +import assertk.assertions.isEqualTo +import nl.avisi.structurizr.site.generatr.normalize +import kotlin.test.Test + +class SoftwareSystemContainerDecisionPageViewModelTest : ViewModelTest() { + private val generatorContext = generatorContext() + private val softwareSystem = generatorContext.workspace.model.addSoftwareSystem("Software System").also { + it.addContainer("API Application") + } + private val container = softwareSystem.containers.first() + @Test + fun url() { + val decision = createDecision() + val viewModel = SoftwareSystemContainerDecisionPageViewModel(generatorContext, container, decision) + + assertThat(SoftwareSystemContainerDecisionPageViewModel.url(container, decision)) + .isEqualTo("/${softwareSystem.name.normalize()}/decisions/${container.name.normalize()}/${decision.id}") + assertThat(viewModel.url) + .isEqualTo(SoftwareSystemContainerDecisionPageViewModel.url(container, decision)) + } + + @Test + fun `active tab`() { + val viewModel = SoftwareSystemContainerDecisionPageViewModel(generatorContext, container, createDecision()) + + assertThat(viewModel.tabs.single { it.link.active }.tab) + .isEqualTo(SoftwareSystemPageViewModel.Tab.DECISIONS) + } + + @Test + fun content() { + val decision = createDecision() + val viewModel = SoftwareSystemContainerDecisionPageViewModel(generatorContext, container, decision) + + assertThat(viewModel.content).isEqualTo(markdownToHtml(viewModel, decision.content, svgFactory)) + } +} diff --git a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionsPageViewModelTest.kt b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionsPageViewModelTest.kt new file mode 100644 index 00000000..cd16a069 --- /dev/null +++ b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionsPageViewModelTest.kt @@ -0,0 +1,45 @@ +package nl.avisi.structurizr.site.generatr.site.model + +import assertk.assertThat +import assertk.assertions.isEqualTo +import assertk.assertions.isFalse +import nl.avisi.structurizr.site.generatr.normalize +import kotlin.test.Test + +class SoftwareSystemContainerDecisionsPageViewModelTest : ViewModelTest() { + private val generatorContext = generatorContext() + private val softwareSystem = generatorContext.workspace.model.addSoftwareSystem("Software system").also { + it.addContainer("API Application") + } + private val container = softwareSystem.containers.first() + @Test + fun `active tab`() { + val viewModel = SoftwareSystemContainerDecisionsPageViewModel(generatorContext, container) + assertThat(viewModel.tabs.single { it.link.active }.tab) + .isEqualTo(SoftwareSystemPageViewModel.Tab.DECISIONS) + } + + @Test + fun `decisions table`() { + container.documentation.addDecision(createDecision("1", "Accepted")) + + val viewModel = SoftwareSystemContainerDecisionsPageViewModel(generatorContext, container) + + assertThat(viewModel.decisionsTable) + .isEqualTo( + viewModel.createDecisionsTableViewModel(container.documentation.decisions) { + "/${softwareSystem.name.normalize()}/decisions/${container.name.normalize()}/1" + } + ) + } + + @Test + fun `hidden view`() { + val viewModel = SoftwareSystemContainerDecisionsPageViewModel( + generatorContext, + softwareSystem.addContainer("Container 2") + ) + + assertThat(viewModel.visible).isFalse() + } +} diff --git a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDecisionsPageViewModelTest.kt b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDecisionsPageViewModelTest.kt index 8d410d82..1eb34c60 100644 --- a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDecisionsPageViewModelTest.kt +++ b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDecisionsPageViewModelTest.kt @@ -31,6 +31,21 @@ class SoftwareSystemDecisionsPageViewModelTest : ViewModelTest() { } ) } + @Test + fun `container decision table`() { + softwareSystem.addContainer("API Application").also { + it.documentation.addDecision(createDecision("1", "Rejected")) + } + + val viewModel = SoftwareSystemDecisionsPageViewModel(generatorContext, softwareSystem) + + assertThat(viewModel.containerDecisionsTable) + .isEqualTo( + viewModel.createContainerTableViewModel(softwareSystem.containers) { + "/${softwareSystem.name.normalize()}/decisions/${softwareSystem.containers.first().name.normalize()}" + } + ) + } @Test fun `hidden view`() { From 918df247718882d5eeaab4a958561cf19cb7c8a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Ga=C5=82uszka?= Date: Wed, 17 May 2023 10:22:20 +0200 Subject: [PATCH 02/11] UI Tab support improvements --- .../site/model/DecisionTabViewModel.kt | 28 +++++++++ ...reSystemContainerDecisionsPageViewModel.kt | 3 +- .../SoftwareSystemDecisionsPageViewModel.kt | 9 +-- .../site/model/SoftwareSystemPageViewModel.kt | 10 +-- .../generatr/site/views/RedirectRelative.kt | 19 ++++++ .../SoftwareSystemContainerDecisionsPage.kt | 15 ++++- .../site/views/SoftwareSystemDecisionsPage.kt | 22 ++++++- .../site/model/DecisionTabViewModelTest.kt | 61 +++++++++++++++++++ ...oftwareSystemDecisionsPageViewModelTest.kt | 15 ----- .../model/SoftwareSystemPageViewModelTest.kt | 25 +++++++- 10 files changed, 172 insertions(+), 35 deletions(-) create mode 100644 src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModel.kt create mode 100644 src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/RedirectRelative.kt create mode 100644 src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModelTest.kt diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModel.kt new file mode 100644 index 00000000..7a991bce --- /dev/null +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModel.kt @@ -0,0 +1,28 @@ +package nl.avisi.structurizr.site.generatr.site.model + +import com.structurizr.model.SoftwareSystem +import nl.avisi.structurizr.site.generatr.* + +data class DecisionTabViewModel(val pageViewModel: SoftwareSystemPageViewModel, val title: String, val visible: Boolean, val url: String) { + val link = LinkViewModel(pageViewModel, title, url, true) +} + +fun SoftwareSystemPageViewModel.createDecisionsTabViewModel(softwareSystem: SoftwareSystem, tab: SoftwareSystemPageViewModel.Tab): List { + val softwareTab = DecisionTabViewModel( + this, + "System", + softwareSystem.hasDecisions(), + SoftwareSystemPageViewModel.url(softwareSystem, tab) + ) + val containerTabs = softwareSystem + .containers + .map { + DecisionTabViewModel( + this, + it.name, + it.hasDecisions(), + SoftwareSystemContainerDecisionsPageViewModel.url(it) + ) + } + return listOf(softwareTab).plus(containerTabs) +} diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionsPageViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionsPageViewModel.kt index b75fbe11..38753ca0 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionsPageViewModel.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionsPageViewModel.kt @@ -11,12 +11,13 @@ import nl.avisi.structurizr.site.generatr.site.GeneratorContext class SoftwareSystemContainerDecisionsPageViewModel(generatorContext: GeneratorContext, container: Container) : SoftwareSystemPageViewModel(generatorContext, container.softwareSystem, Tab.DECISIONS) { override val url = url(container) - val containerName: String = container.name val decisionsTable = createDecisionsTableViewModel(container.documentation.decisions) { "$url/${it.id}" } val visible = container.hasDecisions() + val decisionTabs = createDecisionsTabViewModel(container.softwareSystem, Tab.DECISIONS) + companion object { fun url(container: Container) = "${url(container.softwareSystem, Tab.DECISIONS)}/${container.name.normalize()}" diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDecisionsPageViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDecisionsPageViewModel.kt index 8ea49fb3..445aaa14 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDecisionsPageViewModel.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDecisionsPageViewModel.kt @@ -9,15 +9,16 @@ import nl.avisi.structurizr.site.generatr.site.GeneratorContext class SoftwareSystemDecisionsPageViewModel(generatorContext: GeneratorContext, softwareSystem: SoftwareSystem) : SoftwareSystemPageViewModel(generatorContext, softwareSystem, Tab.DECISIONS) { - val containerDecisionsTable = createContainerTableViewModel(softwareSystem.containers) { - "$url/${it.name.normalize()}" - } val decisionsTable = createDecisionsTableViewModel(softwareSystem.documentation.decisions) { "$url/${it.id}" } - val visibleContainerDecisions = softwareSystem.hasContainerDecisions() + private val visibleContainerDecisions = softwareSystem.hasContainerDecisions() val visibleSoftwareSystemDecisions = softwareSystem.hasDecisions() val visible = visibleSoftwareSystemDecisions or visibleContainerDecisions + val visibleOnlyContainersDecisions = !visibleSoftwareSystemDecisions and visibleContainerDecisions + + val decisionTabs = createDecisionsTabViewModel(softwareSystem, Tab.DECISIONS) + } 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 23dc1882..f318c3fb 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 @@ -1,13 +1,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.hasContainerViews -import nl.avisi.structurizr.site.generatr.hasDecisions -import nl.avisi.structurizr.site.generatr.hasDeploymentViews -import nl.avisi.structurizr.site.generatr.hasDocumentationSections -import nl.avisi.structurizr.site.generatr.hasSystemContextViews -import nl.avisi.structurizr.site.generatr.normalize +import nl.avisi.structurizr.site.generatr.* import nl.avisi.structurizr.site.generatr.site.GeneratorContext open class SoftwareSystemPageViewModel( @@ -40,7 +34,7 @@ open class SoftwareSystemPageViewModel( Tab.CONTAINER -> generatorContext.workspace.views.hasContainerViews(softwareSystem) Tab.COMPONENT -> generatorContext.workspace.views.hasComponentViews(softwareSystem) Tab.DEPLOYMENT -> generatorContext.workspace.views.hasDeploymentViews(softwareSystem) - Tab.DECISIONS -> softwareSystem.hasDecisions() + Tab.DECISIONS -> softwareSystem.hasDecisions() or softwareSystem.hasContainerDecisions() Tab.SECTIONS -> softwareSystem.hasDocumentationSections() } } diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/RedirectRelative.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/RedirectRelative.kt new file mode 100644 index 00000000..8bc6a04f --- /dev/null +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/RedirectRelative.kt @@ -0,0 +1,19 @@ +package nl.avisi.structurizr.site.generatr.site.views + +import kotlinx.html.HTML +import kotlinx.html.body +import kotlinx.html.head +import kotlinx.html.meta +import kotlinx.html.title + +fun HTML.redirectRelative(appendUrl: String) { + attributes["lang"] = "en" + head { + meta { + httpEquiv = "refresh" + content = "0; url=./$appendUrl" + } + title { +"Structurizr site generatr" } + } + body() +} diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionsPage.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionsPage.kt index 31083ae9..2cfd4fc1 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionsPage.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionsPage.kt @@ -1,13 +1,22 @@ package nl.avisi.structurizr.site.generatr.site.views -import kotlinx.html.HTML -import kotlinx.html.h3 +import kotlinx.html.* import nl.avisi.structurizr.site.generatr.site.model.SoftwareSystemContainerDecisionsPageViewModel fun HTML.softwareSystemContainerDecisionsPage(viewModel: SoftwareSystemContainerDecisionsPageViewModel) { if (viewModel.visible) softwareSystemPage(viewModel) { - h3 { +(viewModel.containerName + " Decisions") } + div(classes = "tabs") { + ul(classes = "m-0") { + viewModel.decisionTabs + .filter { it.visible } + .forEach { + li(classes = if (it.link.active) "is-active" else null) { + link(it.link) + } + } + } + } table(viewModel.decisionsTable) } else diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDecisionsPage.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDecisionsPage.kt index 19f00005..cacb1fa0 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDecisionsPage.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDecisionsPage.kt @@ -1,13 +1,29 @@ 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.SoftwareSystemDecisionsPageViewModel fun HTML.softwareSystemDecisionsPage(viewModel: SoftwareSystemDecisionsPageViewModel) { - if (viewModel.visible) { + if (viewModel.visibleOnlyContainersDecisions) { + redirectRelative( + viewModel.decisionTabs.filter { it.visible }.first().link.relativeHref + ) + } + else if (viewModel.visible) { softwareSystemPage(viewModel) { - if (viewModel.visibleContainerDecisions) { - table(viewModel.containerDecisionsTable) + div(classes = "tabs") { + ul(classes = "m-0") { + viewModel.decisionTabs + .filter { it.visible } + .forEach { + li(classes = if (it.link.active) "is-active" else null) { + link(it.link) + } + } + } } if (viewModel.visibleSoftwareSystemDecisions) { table(viewModel.decisionsTable) diff --git a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModelTest.kt b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModelTest.kt new file mode 100644 index 00000000..a28ebe3f --- /dev/null +++ b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModelTest.kt @@ -0,0 +1,61 @@ +package nl.avisi.structurizr.site.generatr.site.model + +import assertk.assertThat +import assertk.assertions.isEqualTo +import java.time.LocalDate +import java.time.Month +import kotlin.test.Test + +class DecisionTabViewModelTest : ViewModelTest() { + + @Test + fun `no decision tabs`() { + val context = generatorContext() + val softwareSystem = context.workspace.model.addSoftwareSystem("Software system") + + val softwareSystemPageViewModel = SoftwareSystemPageViewModel(context, softwareSystem, SoftwareSystemPageViewModel.Tab.DECISIONS) + val decisionTabViewModel = softwareSystemPageViewModel.createDecisionsTabViewModel(softwareSystem, SoftwareSystemPageViewModel.Tab.DECISIONS) + + assertThat(decisionTabViewModel.size).isEqualTo(1) + assertThat(decisionTabViewModel[0].visible).isEqualTo(false) + } + + @Test + fun `software system decision tab available`() { + val context = generatorContext() + val softwareSystem = context.workspace.model.addSoftwareSystem("Software system") + softwareSystem.documentation.addDecision(createDecision("1", "Accepted")) + + val softwareSystemPageViewModel = SoftwareSystemPageViewModel(context, softwareSystem, SoftwareSystemPageViewModel.Tab.DECISIONS) + val decisionTabViewModel = softwareSystemPageViewModel.createDecisionsTabViewModel(softwareSystem, SoftwareSystemPageViewModel.Tab.DECISIONS) + + assertThat(decisionTabViewModel.size).isEqualTo(1) + assertThat(decisionTabViewModel[0].visible).isEqualTo(true) + } + + @Test + fun `container decision tab available `() { + val context = generatorContext() + val softwareSystem = context.workspace.model.addSoftwareSystem("Software system") + softwareSystem.addContainer("Some Container").documentation.addDecision(createDecision("2", "Proposed")) + + val softwareSystemPageViewModel = SoftwareSystemPageViewModel(context, softwareSystem, SoftwareSystemPageViewModel.Tab.DECISIONS) + val decisionTabViewModel = softwareSystemPageViewModel.createDecisionsTabViewModel(softwareSystem, SoftwareSystemPageViewModel.Tab.DECISIONS) + + assertThat(decisionTabViewModel.size).isEqualTo(2) + assertThat(decisionTabViewModel[1].visible).isEqualTo(true) + } + @Test + fun `container & system decision tabs available `() { + val context = generatorContext() + val softwareSystem = context.workspace.model.addSoftwareSystem("Software system") + softwareSystem.documentation.addDecision(createDecision("1", "Accepted")) + softwareSystem.addContainer("Some Container").documentation.addDecision(createDecision("2", "Proposed")) + + val softwareSystemPageViewModel = SoftwareSystemPageViewModel(context, softwareSystem, SoftwareSystemPageViewModel.Tab.DECISIONS) + val decisionTabViewModel = softwareSystemPageViewModel.createDecisionsTabViewModel(softwareSystem, SoftwareSystemPageViewModel.Tab.DECISIONS) + + assertThat(decisionTabViewModel.size).isEqualTo(2) + assertThat(decisionTabViewModel.all { it.visible }).isEqualTo(true) + } +} diff --git a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDecisionsPageViewModelTest.kt b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDecisionsPageViewModelTest.kt index 1eb34c60..8d410d82 100644 --- a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDecisionsPageViewModelTest.kt +++ b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDecisionsPageViewModelTest.kt @@ -31,21 +31,6 @@ class SoftwareSystemDecisionsPageViewModelTest : ViewModelTest() { } ) } - @Test - fun `container decision table`() { - softwareSystem.addContainer("API Application").also { - it.documentation.addDecision(createDecision("1", "Rejected")) - } - - val viewModel = SoftwareSystemDecisionsPageViewModel(generatorContext, softwareSystem) - - assertThat(viewModel.containerDecisionsTable) - .isEqualTo( - viewModel.createContainerTableViewModel(softwareSystem.containers) { - "/${softwareSystem.name.normalize()}/decisions/${softwareSystem.containers.first().name.normalize()}" - } - ) - } @Test fun `hidden view`() { 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 f99d96eb..174b46e1 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 @@ -158,7 +158,7 @@ class SoftwareSystemPageViewModelTest : ViewModelTest() { } @Test - fun `decisions views tab only visible when decisions available`() { + fun `decisions views tab visible when software system decisions available`() { val generatorContext = generatorContext() val softwareSystem = generatorContext.workspace.model.addSoftwareSystem("Some software system") val viewModel = SoftwareSystemPageViewModel(generatorContext, softwareSystem, Tab.HOME) @@ -168,6 +168,29 @@ class SoftwareSystemPageViewModelTest : ViewModelTest() { assertThat(getTab(viewModel, Tab.DECISIONS).visible).isTrue() } + @Test + fun `decisions views tab visible when container decisions available in software system`() { + val generatorContext = generatorContext() + val softwareSystem = generatorContext.workspace.model.addSoftwareSystem("Some software system") + val viewModel = SoftwareSystemPageViewModel(generatorContext, softwareSystem, Tab.HOME) + + assertThat(getTab(viewModel, Tab.DECISIONS).visible).isFalse() + softwareSystem.addContainer("Some Container").documentation.addDecision(createDecision("2", "Proposed")) + assertThat(getTab(viewModel, Tab.DECISIONS).visible).isTrue() + } + + @Test + fun `decisions views tab visible when container & software system decisions are available`() { + val generatorContext = generatorContext() + val softwareSystem = generatorContext.workspace.model.addSoftwareSystem("Some software system") + val viewModel = SoftwareSystemPageViewModel(generatorContext, softwareSystem, Tab.HOME) + + assertThat(getTab(viewModel, Tab.DECISIONS).visible).isFalse() + softwareSystem.addContainer("Some Container").documentation.addDecision(createDecision("2", "Proposed")) + softwareSystem.documentation.addDecision(createDecision("1", "Proposed")) + assertThat(getTab(viewModel, Tab.DECISIONS).visible).isTrue() + } + @Test fun `sections views tab only visible when two or more sections available`() { val generatorContext = generatorContext() From e1c403399e45c50cd06a4ccc95f69015a7c32567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Ga=C5=82uszka?= Date: Tue, 23 May 2023 13:57:32 +0200 Subject: [PATCH 03/11] Use Container.hasDecisions() Co-authored-by: Dirk Groot --- .../nl/avisi/structurizr/site/generatr/StructurizrUtilities.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 5898a5c5..dc7dec3d 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/StructurizrUtilities.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/StructurizrUtilities.kt @@ -23,7 +23,7 @@ val SoftwareSystem.includedProperties fun SoftwareSystem.hasDecisions() = documentation.decisions.isNotEmpty() -fun SoftwareSystem.hasContainerDecisions() = containers.flatMap { it.documentation.decisions }.isNotEmpty() +fun SoftwareSystem.hasContainerDecisions() = containers.any { it.hasDecisions() } fun SoftwareSystem.hasDocumentationSections() = documentation.sections.size >= 2 From e3a3094dea1676e0799345080a793e946649e55e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Ga=C5=82uszka?= Date: Fri, 26 May 2023 10:53:02 +0200 Subject: [PATCH 04/11] Simplify first() filtering Co-authored-by: Dirk Groot --- .../site/generatr/site/views/SoftwareSystemDecisionsPage.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDecisionsPage.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDecisionsPage.kt index cacb1fa0..f53eb84f 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDecisionsPage.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDecisionsPage.kt @@ -9,7 +9,7 @@ import nl.avisi.structurizr.site.generatr.site.model.SoftwareSystemDecisionsPage fun HTML.softwareSystemDecisionsPage(viewModel: SoftwareSystemDecisionsPageViewModel) { if (viewModel.visibleOnlyContainersDecisions) { redirectRelative( - viewModel.decisionTabs.filter { it.visible }.first().link.relativeHref + viewModel.decisionTabs.first { it.visible }.link.relativeHref ) } else if (viewModel.visible) { From f40b053d456c09449cfdf6a7c6f104192fd37c2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Ga=C5=82uszka?= Date: Fri, 26 May 2023 11:05:35 +0200 Subject: [PATCH 05/11] Add improvements requested changes by @dirkgroot --- ...eViewModel.kt => ContainerDecisionsTableViewModel.kt} | 4 ++-- .../site/generatr/site/model/DecisionTabViewModel.kt | 2 +- .../SoftwareSystemContainerDecisionPageViewModel.kt | 1 - .../SoftwareSystemContainerDecisionsPageViewModel.kt | 3 --- .../site/model/SoftwareSystemDecisionsPageViewModel.kt | 9 ++++----- 5 files changed, 7 insertions(+), 12 deletions(-) rename src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/{ContainersTableViewModel.kt => ContainerDecisionsTableViewModel.kt} (65%) diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainersTableViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainerDecisionsTableViewModel.kt similarity index 65% rename from src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainersTableViewModel.kt rename to src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainerDecisionsTableViewModel.kt index 5d776be0..808521a0 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainersTableViewModel.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainerDecisionsTableViewModel.kt @@ -2,7 +2,7 @@ package nl.avisi.structurizr.site.generatr.site.model import com.structurizr.model.Container -fun PageViewModel.createContainerTableViewModel(containers: Collection, hrefFactory: (Container) -> String) = +fun PageViewModel.createContainerDecisionsTableViewModel(containers: Collection, hrefFactory: (Container) -> String) = TableViewModel.create { headerRow(headerCell("#"), headerCell("Container Decisions")) containers @@ -11,7 +11,7 @@ fun PageViewModel.createContainerTableViewModel(containers: Collection bodyRow( cellWithIndex((index+1).toString()), - cellWithLink(this@createContainerTableViewModel, container.name, hrefFactory(container)) + cellWithLink(this@createContainerDecisionsTableViewModel, container.name, hrefFactory(container)) ) } } diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModel.kt index 7a991bce..c4e5c022 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModel.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModel.kt @@ -1,7 +1,7 @@ package nl.avisi.structurizr.site.generatr.site.model import com.structurizr.model.SoftwareSystem -import nl.avisi.structurizr.site.generatr.* +import nl.avisi.structurizr.site.generatr.hasDecisions data class DecisionTabViewModel(val pageViewModel: SoftwareSystemPageViewModel, val title: String, val visible: Boolean, val url: String) { val link = LinkViewModel(pageViewModel, title, url, true) diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionPageViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionPageViewModel.kt index ead2f615..1cb49aa9 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionPageViewModel.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionPageViewModel.kt @@ -1,7 +1,6 @@ package nl.avisi.structurizr.site.generatr.site.model import com.structurizr.documentation.Decision -import com.structurizr.model.SoftwareSystem import com.structurizr.model.Container import nl.avisi.structurizr.site.generatr.normalize import nl.avisi.structurizr.site.generatr.site.GeneratorContext diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionsPageViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionsPageViewModel.kt index 38753ca0..8a98dd6a 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionsPageViewModel.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerDecisionsPageViewModel.kt @@ -1,9 +1,6 @@ package nl.avisi.structurizr.site.generatr.site.model -import com.structurizr.documentation.Decision import com.structurizr.model.Container -import com.structurizr.model.SoftwareSystem -import nl.avisi.structurizr.site.generatr.hasContainerDecisions import nl.avisi.structurizr.site.generatr.hasDecisions import nl.avisi.structurizr.site.generatr.normalize import nl.avisi.structurizr.site.generatr.site.GeneratorContext diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDecisionsPageViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDecisionsPageViewModel.kt index 445aaa14..70158f09 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDecisionsPageViewModel.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemDecisionsPageViewModel.kt @@ -3,7 +3,6 @@ package nl.avisi.structurizr.site.generatr.site.model import com.structurizr.model.SoftwareSystem import nl.avisi.structurizr.site.generatr.hasContainerDecisions import nl.avisi.structurizr.site.generatr.hasDecisions -import nl.avisi.structurizr.site.generatr.normalize import nl.avisi.structurizr.site.generatr.site.GeneratorContext class SoftwareSystemDecisionsPageViewModel(generatorContext: GeneratorContext, softwareSystem: SoftwareSystem) : @@ -13,11 +12,11 @@ class SoftwareSystemDecisionsPageViewModel(generatorContext: GeneratorContext, s "$url/${it.id}" } - private val visibleContainerDecisions = softwareSystem.hasContainerDecisions() - val visibleSoftwareSystemDecisions = softwareSystem.hasDecisions() + private val containerDecisionsVisible = softwareSystem.hasContainerDecisions() + val softwareSystemDecisionsVisible = softwareSystem.hasDecisions() - val visible = visibleSoftwareSystemDecisions or visibleContainerDecisions - val visibleOnlyContainersDecisions = !visibleSoftwareSystemDecisions and visibleContainerDecisions + val visible = softwareSystemDecisionsVisible or containerDecisionsVisible + val onlyContainersDecisionsVisible = !softwareSystemDecisionsVisible and containerDecisionsVisible val decisionTabs = createDecisionsTabViewModel(softwareSystem, Tab.DECISIONS) From da8e05adb3ed93e2d20cc5a4572b2a7cb9246755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Ga=C5=82uszka?= Date: Fri, 26 May 2023 11:09:24 +0200 Subject: [PATCH 06/11] Add requested improvement changes by @dirkgroot --- .../site/views/SoftwareSystemContainerDecisionPage.kt | 1 - .../site/views/SoftwareSystemContainerDecisionsPage.kt | 5 ++++- .../site/generatr/site/views/SoftwareSystemDecisionsPage.kt | 4 ++-- ...ModelTest.kt => ContainerDecisionsTableViewModelTest.kt} | 6 +++--- 4 files changed, 9 insertions(+), 7 deletions(-) rename src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/{ContainersTableViewModelTest.kt => ContainerDecisionsTableViewModelTest.kt} (84%) diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionPage.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionPage.kt index 85a5f17a..d4244495 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionPage.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionPage.kt @@ -1,7 +1,6 @@ package nl.avisi.structurizr.site.generatr.site.views import kotlinx.html.HTML -import kotlinx.html.h3 import nl.avisi.structurizr.site.generatr.site.model.SoftwareSystemContainerDecisionPageViewModel fun HTML.softwareSystemContainerDecisionPage(viewModel: SoftwareSystemContainerDecisionPageViewModel) { diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionsPage.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionsPage.kt index 2cfd4fc1..291170da 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionsPage.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionsPage.kt @@ -1,6 +1,9 @@ package nl.avisi.structurizr.site.generatr.site.views -import kotlinx.html.* +import kotlinx.html.HTML +import kotlinx.html.div +import kotlinx.html.li +import kotlinx.html.ul import nl.avisi.structurizr.site.generatr.site.model.SoftwareSystemContainerDecisionsPageViewModel fun HTML.softwareSystemContainerDecisionsPage(viewModel: SoftwareSystemContainerDecisionsPageViewModel) { diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDecisionsPage.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDecisionsPage.kt index f53eb84f..5b576672 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDecisionsPage.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDecisionsPage.kt @@ -7,7 +7,7 @@ import kotlinx.html.ul import nl.avisi.structurizr.site.generatr.site.model.SoftwareSystemDecisionsPageViewModel fun HTML.softwareSystemDecisionsPage(viewModel: SoftwareSystemDecisionsPageViewModel) { - if (viewModel.visibleOnlyContainersDecisions) { + if (viewModel.onlyContainersDecisionsVisible) { redirectRelative( viewModel.decisionTabs.first { it.visible }.link.relativeHref ) @@ -25,7 +25,7 @@ fun HTML.softwareSystemDecisionsPage(viewModel: SoftwareSystemDecisionsPageViewM } } } - if (viewModel.visibleSoftwareSystemDecisions) { + if (viewModel.softwareSystemDecisionsVisible) { table(viewModel.decisionsTable) } } diff --git a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainersTableViewModelTest.kt b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainerDecisionsTableViewModelTest.kt similarity index 84% rename from src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainersTableViewModelTest.kt rename to src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainerDecisionsTableViewModelTest.kt index 5ba00ea3..3194894d 100644 --- a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainersTableViewModelTest.kt +++ b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainerDecisionsTableViewModelTest.kt @@ -4,11 +4,11 @@ import assertk.assertThat import assertk.assertions.isEqualTo import kotlin.test.Test -class ContainersTableViewModelTest : ViewModelTest() { +class ContainerDecisionsTableViewModelTest : ViewModelTest() { @Test fun `no container with decisions available`() { - assertThat(pageViewModel().createContainerTableViewModel(emptySet()) { "href" }) + assertThat(pageViewModel().createContainerDecisionsTableViewModel(emptySet()) { "href" }) .isEqualTo( TableViewModel.create { containersTableHeaderRow() @@ -26,7 +26,7 @@ class ContainersTableViewModelTest : ViewModelTest() { .documentation.addDecision(createDecision("1", "Mobile Decision")) }.containers val pageViewModel = pageViewModel() - assertThat(pageViewModel.createContainerTableViewModel(containers) { it.name }).isEqualTo( + assertThat(pageViewModel.createContainerDecisionsTableViewModel(containers) { it.name }).isEqualTo( TableViewModel.create { containersTableHeaderRow() bodyRow( From 8796e9afe4ce990c3c019fa347673d4fffe9feb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Ga=C5=82uszka?= Date: Fri, 26 May 2023 11:11:57 +0200 Subject: [PATCH 07/11] Add requested improvement changes by @dirkgroot --- .../site/generatr/site/model/DecisionTabViewModelTest.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModelTest.kt b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModelTest.kt index a28ebe3f..6c2fcb02 100644 --- a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModelTest.kt +++ b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModelTest.kt @@ -2,8 +2,6 @@ package nl.avisi.structurizr.site.generatr.site.model import assertk.assertThat import assertk.assertions.isEqualTo -import java.time.LocalDate -import java.time.Month import kotlin.test.Test class DecisionTabViewModelTest : ViewModelTest() { From cd842bd40f53fce451772d65ef6ad1b59b63cad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Ga=C5=82uszka?= Date: Fri, 26 May 2023 11:42:36 +0200 Subject: [PATCH 08/11] Add requested improvement changes by @dirkgroot --- .../site/model/DecisionTabViewModel.kt | 39 ++++++++++--------- .../SoftwareSystemContainerDecisionsPage.kt | 1 - .../site/views/SoftwareSystemDecisionsPage.kt | 3 +- .../site/model/DecisionTabViewModelTest.kt | 15 +++---- 4 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModel.kt index c4e5c022..6c0d1c57 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModel.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModel.kt @@ -3,26 +3,29 @@ package nl.avisi.structurizr.site.generatr.site.model import com.structurizr.model.SoftwareSystem import nl.avisi.structurizr.site.generatr.hasDecisions -data class DecisionTabViewModel(val pageViewModel: SoftwareSystemPageViewModel, val title: String, val visible: Boolean, val url: String) { +data class DecisionTabViewModel(val pageViewModel: SoftwareSystemPageViewModel, val title: String, val url: String) { val link = LinkViewModel(pageViewModel, title, url, true) } fun SoftwareSystemPageViewModel.createDecisionsTabViewModel(softwareSystem: SoftwareSystem, tab: SoftwareSystemPageViewModel.Tab): List { - val softwareTab = DecisionTabViewModel( - this, - "System", - softwareSystem.hasDecisions(), - SoftwareSystemPageViewModel.url(softwareSystem, tab) - ) - val containerTabs = softwareSystem - .containers - .map { - DecisionTabViewModel( - this, - it.name, - it.hasDecisions(), - SoftwareSystemContainerDecisionsPageViewModel.url(it) - ) - } - return listOf(softwareTab).plus(containerTabs) + val tabs = buildList { + if (softwareSystem.hasDecisions()) { + add(DecisionTabViewModel( + this@createDecisionsTabViewModel, + "System", + SoftwareSystemPageViewModel.url(softwareSystem, tab) + )) + } + softwareSystem + .containers + .map { + DecisionTabViewModel( + this@createDecisionsTabViewModel, + it.name, + SoftwareSystemContainerDecisionsPageViewModel.url(it) + ) + } + .forEach { add(it) } + } + return tabs } diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionsPage.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionsPage.kt index 291170da..a9a98a28 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionsPage.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerDecisionsPage.kt @@ -12,7 +12,6 @@ fun HTML.softwareSystemContainerDecisionsPage(viewModel: SoftwareSystemContainer div(classes = "tabs") { ul(classes = "m-0") { viewModel.decisionTabs - .filter { it.visible } .forEach { li(classes = if (it.link.active) "is-active" else null) { link(it.link) diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDecisionsPage.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDecisionsPage.kt index 5b576672..6c23fbf4 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDecisionsPage.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemDecisionsPage.kt @@ -9,7 +9,7 @@ import nl.avisi.structurizr.site.generatr.site.model.SoftwareSystemDecisionsPage fun HTML.softwareSystemDecisionsPage(viewModel: SoftwareSystemDecisionsPageViewModel) { if (viewModel.onlyContainersDecisionsVisible) { redirectRelative( - viewModel.decisionTabs.first { it.visible }.link.relativeHref + viewModel.decisionTabs.first().link.relativeHref ) } else if (viewModel.visible) { @@ -17,7 +17,6 @@ fun HTML.softwareSystemDecisionsPage(viewModel: SoftwareSystemDecisionsPageViewM div(classes = "tabs") { ul(classes = "m-0") { viewModel.decisionTabs - .filter { it.visible } .forEach { li(classes = if (it.link.active) "is-active" else null) { link(it.link) diff --git a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModelTest.kt b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModelTest.kt index 6c2fcb02..d8d4c457 100644 --- a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModelTest.kt +++ b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModelTest.kt @@ -14,8 +14,7 @@ class DecisionTabViewModelTest : ViewModelTest() { val softwareSystemPageViewModel = SoftwareSystemPageViewModel(context, softwareSystem, SoftwareSystemPageViewModel.Tab.DECISIONS) val decisionTabViewModel = softwareSystemPageViewModel.createDecisionsTabViewModel(softwareSystem, SoftwareSystemPageViewModel.Tab.DECISIONS) - assertThat(decisionTabViewModel.size).isEqualTo(1) - assertThat(decisionTabViewModel[0].visible).isEqualTo(false) + assertThat(decisionTabViewModel.size).isEqualTo(0) } @Test @@ -28,7 +27,7 @@ class DecisionTabViewModelTest : ViewModelTest() { val decisionTabViewModel = softwareSystemPageViewModel.createDecisionsTabViewModel(softwareSystem, SoftwareSystemPageViewModel.Tab.DECISIONS) assertThat(decisionTabViewModel.size).isEqualTo(1) - assertThat(decisionTabViewModel[0].visible).isEqualTo(true) + assertThat(decisionTabViewModel.first().title).isEqualTo("System") } @Test @@ -40,11 +39,12 @@ class DecisionTabViewModelTest : ViewModelTest() { val softwareSystemPageViewModel = SoftwareSystemPageViewModel(context, softwareSystem, SoftwareSystemPageViewModel.Tab.DECISIONS) val decisionTabViewModel = softwareSystemPageViewModel.createDecisionsTabViewModel(softwareSystem, SoftwareSystemPageViewModel.Tab.DECISIONS) - assertThat(decisionTabViewModel.size).isEqualTo(2) - assertThat(decisionTabViewModel[1].visible).isEqualTo(true) + assertThat(decisionTabViewModel.size).isEqualTo(1) + assertThat(decisionTabViewModel.first().title).isEqualTo("Some Container") + } @Test - fun `container & system decision tabs available `() { + fun `container & system decision tabs available`() { val context = generatorContext() val softwareSystem = context.workspace.model.addSoftwareSystem("Software system") softwareSystem.documentation.addDecision(createDecision("1", "Accepted")) @@ -54,6 +54,7 @@ class DecisionTabViewModelTest : ViewModelTest() { val decisionTabViewModel = softwareSystemPageViewModel.createDecisionsTabViewModel(softwareSystem, SoftwareSystemPageViewModel.Tab.DECISIONS) assertThat(decisionTabViewModel.size).isEqualTo(2) - assertThat(decisionTabViewModel.all { it.visible }).isEqualTo(true) + assertThat(decisionTabViewModel.first().title).isEqualTo("System") + assertThat(decisionTabViewModel.last().title).isEqualTo("Some Container") } } From 91755e31e17f4823e4094490258a48d1107dfbbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Ga=C5=82uszka?= Date: Fri, 26 May 2023 15:20:19 +0200 Subject: [PATCH 09/11] Add filtering for container with existing decisions. Co-authored-by: Dirk Groot --- .../structurizr/site/generatr/site/model/DecisionTabViewModel.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModel.kt index 6c0d1c57..51a99498 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModel.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModel.kt @@ -18,6 +18,7 @@ fun SoftwareSystemPageViewModel.createDecisionsTabViewModel(softwareSystem: Soft } softwareSystem .containers + .filter { it.hasDecisions() } .map { DecisionTabViewModel( this@createDecisionsTabViewModel, From bab9196f1a513ef580d680f7dcb09ffdb25ea1a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Ga=C5=82uszka?= Date: Fri, 26 May 2023 15:23:25 +0200 Subject: [PATCH 10/11] Add test for bug reported by @dirkgroot --- .../site/model/DecisionTabViewModelTest.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModelTest.kt b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModelTest.kt index d8d4c457..417ba996 100644 --- a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModelTest.kt +++ b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/DecisionTabViewModelTest.kt @@ -57,4 +57,18 @@ class DecisionTabViewModelTest : ViewModelTest() { assertThat(decisionTabViewModel.first().title).isEqualTo("System") assertThat(decisionTabViewModel.last().title).isEqualTo("Some Container") } + + @Test + fun `check container decisions tabs are filtered`() { + val context = generatorContext() + val softwareSystem = context.workspace.model.addSoftwareSystem("Software system") + softwareSystem.addContainer("Some Container").documentation.addDecision(createDecision("2", "Proposed")) + softwareSystem.addContainer("Another Container") + + val softwareSystemPageViewModel = SoftwareSystemPageViewModel(context, softwareSystem, SoftwareSystemPageViewModel.Tab.DECISIONS) + val decisionTabViewModel = softwareSystemPageViewModel.createDecisionsTabViewModel(softwareSystem, SoftwareSystemPageViewModel.Tab.DECISIONS) + + assertThat(decisionTabViewModel.size).isEqualTo(1) + assertThat(decisionTabViewModel.last().title).isEqualTo("Some Container") + } } From 578205509188740a48d414dc2e898db943f185b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Ga=C5=82uszka?= Date: Fri, 26 May 2023 15:24:50 +0200 Subject: [PATCH 11/11] Add improvement suggested by @dirkgroot --- .../generatr/site/model/ContainerDecisionsTableViewModel.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainerDecisionsTableViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainerDecisionsTableViewModel.kt index 808521a0..ed02910d 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainerDecisionsTableViewModel.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/ContainerDecisionsTableViewModel.kt @@ -1,13 +1,14 @@ package nl.avisi.structurizr.site.generatr.site.model import com.structurizr.model.Container +import nl.avisi.structurizr.site.generatr.hasDecisions fun PageViewModel.createContainerDecisionsTableViewModel(containers: Collection, hrefFactory: (Container) -> String) = TableViewModel.create { headerRow(headerCell("#"), headerCell("Container Decisions")) containers .sortedBy { it.name } - .filter { it.documentation.decisions.isNotEmpty() } + .filter { it.hasDecisions() } .forEachIndexed { index, container -> bodyRow( cellWithIndex((index+1).toString()),