diff --git a/docs/example/atm/atm-example.png b/docs/example/atm/atm-example.png new file mode 100644 index 00000000..4d3783ff Binary files /dev/null and b/docs/example/atm/atm-example.png differ diff --git a/docs/example/internet-banking-system/database-erd-example.jpg b/docs/example/internet-banking-system/database-erd-example.jpg new file mode 100644 index 00000000..fd67ed93 Binary files /dev/null and b/docs/example/internet-banking-system/database-erd-example.jpg differ diff --git a/docs/example/internet-banking-system/uml-class-diagram.png b/docs/example/internet-banking-system/uml-class-diagram.png new file mode 100644 index 00000000..f00a9dcb Binary files /dev/null and b/docs/example/internet-banking-system/uml-class-diagram.png differ diff --git a/docs/example/workspace.dsl b/docs/example/workspace.dsl index 25503dee..337d1231 100644 --- a/docs/example/workspace.dsl +++ b/docs/example/workspace.dsl @@ -14,7 +14,6 @@ workspace "Big Bank plc" "This is an example workspace to illustrate the key fea } customer = person "Personal Banking Customer" "A customer of the bank, with personal bank accounts." "Customer" - acquirer = softwaresystem "Acquirer" "Facilitates PIN transactions for merchants." "External System" group "Big Bank plc" { @@ -115,7 +114,6 @@ workspace "Big Bank plc" "This is an example workspace to illustrate the key fea softwareSystemInstance mainframe } } - } deploymentEnvironment "Live" { @@ -127,7 +125,6 @@ workspace "Big Bank plc" "This is an example workspace to illustrate the key fea liveSinglePageApplicationInstance = containerInstance singlePageApplication } } - deploymentNode "Big Bank plc" "" "Big Bank plc data center" { deploymentNode "bigbank-web***" "" "Ubuntu 16.04 LTS" "" 4 { deploymentNode "Apache Tomcat" "" "Apache Tomcat 8.x" { @@ -139,7 +136,6 @@ workspace "Big Bank plc" "This is an example workspace to illustrate the key fea liveApiApplicationInstance = containerInstance apiApplication } } - deploymentNode "bigbank-db01" "" "Ubuntu 16.04 LTS" { primaryDatabaseServer = deploymentNode "Oracle - Primary" "" "Oracle 12c" { livePrimaryDatabaseInstance = containerInstance database @@ -154,7 +150,6 @@ workspace "Big Bank plc" "This is an example workspace to illustrate the key fea softwareSystemInstance mainframe } } - primaryDatabaseServer -> secondaryDatabaseServer "Replicates data to" } } @@ -167,19 +162,10 @@ workspace "Big Bank plc" "This is an example workspace to illustrate the key fea "generatr.style.colors.secondary" "#ffffff" "generatr.style.faviconPath" "site/favicon.ico" "generatr.style.logoPath" "site/logo.png" - - // Absolute URL's like "https://example.com/custom.css" are also supported "generatr.style.customStylesheet" "site/custom.css" - + "generatr.search.language" "en" "generatr.svglink.target" "_self" - - // Full list of available "generatr.markdown.flexmark.extensions" - // "Abbreviation,Admonition,AnchorLink,Aside,Attributes,Autolink,Definition,Emoji,EnumeratedReference,Footnotes,GfmIssues,GfmStrikethroughSubscript,GfmTaskList,GfmUsers,GitLab,Ins,Macros,MediaTags,ResizableImage,Superscript,Tables,TableOfContents,SimulatedTableOfContents,Typographic,WikiLinks,XWikiMacro,YAMLFrontMatter,YouTubeLink" - // see https://github.com/vsch/flexmark-java/wiki/Extensions - // ATTENTION: - // * "generatr.markdown.flexmark.extensions" values must be separated by comma - // * it's not possible to use "GitLab" and "ResizableImage" extensions together - // default behaviour, if no generatr.markdown.flexmark.extensions property is specified, is to load the Tables extension only + "generatr.site.nestGroups" "false" "generatr.markdown.flexmark.extensions" "Abbreviation,Admonition,AnchorLink,Attributes,Autolink,Definition,Emoji,Footnotes,GfmTaskList,GitLab,MediaTags,Tables,TableOfContents,Typographic" "generatr.site.exporter" "c4" @@ -187,43 +173,30 @@ workspace "Big Bank plc" "This is an example workspace to illustrate the key fea "generatr.site.nestGroups" "false" } - systemlandscape "SystemLandscape" { - include * - autoLayout + !script groovy { + workspace.views.createDefaultViews() } - systemcontext internetBankingSystem "SystemContext" { - include * - animation { - internetBankingSystem - customer - mainframe - email - } - autoLayout + image atm { + image atm/atm-example.png + title "ATM System" + description "Image View to show how the ATM system works internally" } - container internetBankingSystem "Containers" { - include * - animation { - customer mainframe email - webApplication - singlePageApplication - mobileApp - apiApplication - database - } - autoLayout + image database { + image internet-banking-system/database-erd-example.jpg + title "Database Entity Relationship Diagram" + description "Image View to show the ERD diagram for the database container" + } + + image accountsSummaryController { + image internet-banking-system/uml-class-diagram.png + title "Sample ImageView - accountsSummaryController Component" + description "This is a sample imageView for code of a component" } - component apiApplication "Components" { + systemlandscape "SystemLandscape" { include * - animation { - singlePageApplication mobileApp database email mainframe - signinController securityComponent - accountsSummaryController mainframeBankingSystemFacade - resetPasswordController emailComponent - } autoLayout } @@ -237,28 +210,6 @@ workspace "Big Bank plc" "This is an example workspace to illustrate the key fea autoLayout } - deployment internetBankingSystem "Development" "DevelopmentDeployment" { - include * - animation { - developerSinglePageApplicationInstance - developerWebApplicationInstance developerApiApplicationInstance - developerDatabaseInstance - } - autoLayout - } - - deployment internetBankingSystem "Live" "LiveDeployment" { - include * - animation { - liveSinglePageApplicationInstance - liveMobileAppInstance - liveWebApplicationInstance liveApiApplicationInstance - livePrimaryDatabaseInstance - liveSecondaryDatabaseInstance - } - autoLayout - } - styles { element "Person" { color #ffffff 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 22b58559..5b69a3a1 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/StructurizrUtilities.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/StructurizrUtilities.kt @@ -4,7 +4,9 @@ import com.structurizr.Workspace import com.structurizr.model.Container import com.structurizr.model.Location import com.structurizr.model.SoftwareSystem +import com.structurizr.view.ImageView import com.structurizr.view.ViewSet +import nl.avisi.structurizr.site.generatr.site.GeneratorContext val Workspace.includedSoftwareSystems: List get() = model.softwareSystems.filter { @@ -36,14 +38,49 @@ fun Container.hasSections() = documentation.sections.isNotEmpty() fun ViewSet.hasSystemContextViews(softwareSystem: SoftwareSystem) = systemContextViews.any { it.softwareSystem == softwareSystem } -fun ViewSet.hasContainerViews(softwareSystem: SoftwareSystem) = - containerViews.any { it.softwareSystem == softwareSystem } +fun ViewSet.hasContainerViews(generatorContext: GeneratorContext, softwareSystem: SoftwareSystem) = + containerViews.any { it.softwareSystem == softwareSystem } || getImagesForSystem(generatorContext.workspace, softwareSystem).isNotEmpty() -fun ViewSet.hasComponentViews(softwareSystem: SoftwareSystem) = - componentViews.any { it.softwareSystem == softwareSystem } +fun ViewSet.hasComponentViews(generatorContext: GeneratorContext, softwareSystem: SoftwareSystem) = + componentViews.any { it.softwareSystem == softwareSystem } || getImagesForContainer(generatorContext.workspace, softwareSystem).isNotEmpty() + +fun ViewSet.hasCodeViews(generatorContext: GeneratorContext, softwareSystem: SoftwareSystem) = + componentViews.any { it.softwareSystem == softwareSystem } || getImagesForComponent(generatorContext, softwareSystem).isNotEmpty() fun ViewSet.hasDynamicViews(softwareSystem: SoftwareSystem) = dynamicViews.any { it.softwareSystem == softwareSystem } fun ViewSet.hasDeploymentViews(softwareSystem: SoftwareSystem) = deploymentViews.any { it.softwareSystem == softwareSystem } + +fun getImageViewsForId(workspace: Workspace, id: String): List { + return workspace.views.imageViews + .filter { it.elementId == id } + .sortedBy { it.key } +} + +fun getImagesForSystem(workspace: Workspace, softwareSystem: SoftwareSystem): List { + return workspace.views.imageViews + .filter { it.elementId == softwareSystem.id } + .sortedBy { it.key } +} + +fun getImagesForContainer(workspace: Workspace, softwareSystem: SoftwareSystem): List { + val images = mutableListOf() + softwareSystem.containers.forEach{ container -> + images += workspace.views.imageViews + .filter { it.elementId == container.id } + } + return images +} + +fun getImagesForComponent(generatorContext: GeneratorContext, softwareSystem: SoftwareSystem): List { + val images = mutableListOf() + softwareSystem.containers.forEach { container -> + container.components.forEach { component -> + images += generatorContext.workspace.views.imageViews + .filter { it.elementId == component.id } + } + } + return images +} diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/PlantUmlExporter.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/PlantUmlExporter.kt index 78e83fec..8ca39213 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/PlantUmlExporter.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/PlantUmlExporter.kt @@ -5,6 +5,7 @@ import com.structurizr.export.Diagram import com.structurizr.export.IndentingWriter import com.structurizr.export.plantuml.C4PlantUMLExporter import com.structurizr.export.plantuml.StructurizrPlantUMLExporter +import com.structurizr.model.Component import com.structurizr.model.Container import com.structurizr.model.Element import com.structurizr.model.SoftwareSystem @@ -78,9 +79,10 @@ private class WriterWithElementLinks( writeElementFn: (view: ModelView?, element: Element?, writer: IndentingWriter?) -> Unit ) { val url = when { - needsLinkToSoftwareSystem(element, view) -> getUrlToSoftwareSystem(element) - needsLinkToContainerViews(element, view) -> getUrlToContainerViews(element) - needsLinkToComponentViews(element, view) -> getUrlToComponentViews(element) + needsLinkToSoftwareSystem(element, view) -> getUrlToViewsPage(element?.name?.normalize(), "context") + needsLinkToContainerViews(element, view, workspace) -> getUrlToViewsPage(element?.name?.normalize(), "container") + needsLinkToComponentViews(element, view, workspace) -> getUrlToViewsPage(element?.parent?.name?.normalize(), "component") + needsLinkToCodeViews(element, workspace) -> getUrlToViewsPage(element?.parent?.parent?.name?.normalize(), "code") else -> null } @@ -93,24 +95,23 @@ private class WriterWithElementLinks( private fun needsLinkToSoftwareSystem(element: Element?, view: ModelView?) = element is SoftwareSystem && workspace.includedSoftwareSystems.contains(element) && element != view?.softwareSystem - private fun getUrlToSoftwareSystem(element: Element?): String { - val path = "/${element?.name?.normalize()}/context/".asUrlToDirectory(url) - return "$TEMP_URI$path" - } + private fun needsLinkToContainerViews(element: Element?, view: ModelView?, workspace: Workspace) = + element is SoftwareSystem + && workspace.includedSoftwareSystems.contains(element) + && element == view?.softwareSystem + && ( element.hasContainers || getImageViewsForId(workspace, element.id).isNotEmpty()) - private fun needsLinkToContainerViews(element: Element?, view: ModelView?) = - element is SoftwareSystem && workspace.includedSoftwareSystems.contains(element) && element == view?.softwareSystem && element.hasContainers + private fun needsLinkToComponentViews(element: Element?, view: ModelView?, workspace: Workspace) = + element is Container + && ( element.hasComponents || getImageViewsForId(workspace, element.id).isNotEmpty()) + && view !is ComponentView - private fun getUrlToContainerViews(element: Element?): String { - val path = "/${element?.name?.normalize()}/container/".asUrlToDirectory(url) - return "$TEMP_URI$path" - } + private fun needsLinkToCodeViews(element: Element?, workspace: Workspace) = + element is Component + && getImageViewsForId(workspace, element.id).isNotEmpty() - private fun needsLinkToComponentViews(element: Element?, view: ModelView?) = - element is Container && element.hasComponents && view !is ComponentView - - private fun getUrlToComponentViews(element: Element?): String { - val path = "/${element?.parent?.name?.normalize()}/component/".asUrlToDirectory(url) + private fun getUrlToViewsPage(systemName: String?, page: String): String { + val path = "/$systemName/$page/".asUrlToDirectory(url) return "$TEMP_URI$path" } @@ -147,7 +148,7 @@ class C4PlantUmlExporterWithElementLinks(workspace: Workspace, url: String) : C4 withElementLinks.writeHeader(view, writer) { v, w -> super.writeHeader(v, w) } } - override fun writeElement(view: ModelView?, element: Element?, writer: IndentingWriter?) { + override fun writeElement(view: ModelView?, element: Element?, writer: IndentingWriter?) { withElementLinks.writeElement(view, element, writer) { v, e, w -> super.writeElement(v, e, w) } } } @@ -162,4 +163,5 @@ class StructurizrPlantUmlExporterWithElementLinks(workspace: Workspace, url: Str override fun writeElement(view: ModelView?, element: Element?, writer: IndentingWriter?) { withElementLinks.writeElement(view, element, writer) { v, e, w -> super.writeElement(v, e, w) } } + } 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 badf0261..d146fcf1 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 @@ -136,6 +136,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, SoftwareSystemCodePageViewModel(context, it)) } add { writeHtmlFile(branchDir, SoftwareSystemDynamicPageViewModel(context, it)) } add { writeHtmlFile(branchDir, SoftwareSystemDeploymentPageViewModel(context, it)) } add { writeHtmlFile(branchDir, SoftwareSystemDependenciesPageViewModel(context, it)) } @@ -189,6 +190,7 @@ private fun writeHtmlFile(exportDir: File, viewModel: PageViewModel) { is SoftwareSystemContainerSectionPageViewModel -> softwareSystemContainerSectionPage(viewModel) is SoftwareSystemContainerSectionsPageViewModel -> softwareSystemContainerSectionsPage(viewModel) is SoftwareSystemComponentPageViewModel -> softwareSystemComponentPage(viewModel) + is SoftwareSystemCodePageViewModel -> softwareSystemCodePage(viewModel) is SoftwareSystemDynamicPageViewModel -> softwareSystemDynamicPage(viewModel) is SoftwareSystemDeploymentPageViewModel -> softwareSystemDeploymentPage(viewModel) is SoftwareSystemDependenciesPageViewModel -> softwareSystemDependenciesPage(viewModel) diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemCodePageViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemCodePageViewModel.kt new file mode 100644 index 00000000..6e89f4ae --- /dev/null +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemCodePageViewModel.kt @@ -0,0 +1,13 @@ +package nl.avisi.structurizr.site.generatr.site.model + +import com.structurizr.model.SoftwareSystem +import nl.avisi.structurizr.site.generatr.getImagesForComponent +import nl.avisi.structurizr.site.generatr.site.GeneratorContext + +class SoftwareSystemCodePageViewModel(generatorContext: GeneratorContext, softwareSystem: SoftwareSystem) : + SoftwareSystemPageViewModel(generatorContext, softwareSystem, Tab.CODE) { + val images = getImagesForComponent(generatorContext,softwareSystem) + val imagesVisible = images.isNotEmpty() +} + + diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemComponentPageViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemComponentPageViewModel.kt index c0caddae..815d3625 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemComponentPageViewModel.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemComponentPageViewModel.kt @@ -1,6 +1,7 @@ package nl.avisi.structurizr.site.generatr.site.model import com.structurizr.model.SoftwareSystem +import nl.avisi.structurizr.site.generatr.getImagesForContainer import nl.avisi.structurizr.site.generatr.hasComponentViews import nl.avisi.structurizr.site.generatr.site.GeneratorContext @@ -10,5 +11,9 @@ class SoftwareSystemComponentPageViewModel(generatorContext: GeneratorContext, s .filter { it.softwareSystem == softwareSystem } .sortedBy { it.key } .map { DiagramViewModel.forView(this, it, generatorContext.svgFactory) } - val visible = generatorContext.workspace.views.hasComponentViews(softwareSystem) + val images = getImagesForContainer(generatorContext.workspace,softwareSystem) + val diagramsVisible = generatorContext.workspace.views.hasComponentViews(generatorContext, softwareSystem) + val imagesVisible = images.isNotEmpty() } + + diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerPageViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerPageViewModel.kt index 89867ba3..aa28cb9b 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerPageViewModel.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerPageViewModel.kt @@ -1,6 +1,7 @@ package nl.avisi.structurizr.site.generatr.site.model import com.structurizr.model.SoftwareSystem +import nl.avisi.structurizr.site.generatr.getImagesForSystem import nl.avisi.structurizr.site.generatr.hasContainerViews import nl.avisi.structurizr.site.generatr.site.GeneratorContext @@ -10,5 +11,7 @@ class SoftwareSystemContainerPageViewModel(generatorContext: GeneratorContext, s .filter { it.softwareSystem == softwareSystem } .sortedBy { it.key } .map { DiagramViewModel.forView(this, it, generatorContext.svgFactory) } - val visible = generatorContext.workspace.views.hasContainerViews(softwareSystem) + val images = getImagesForSystem(generatorContext.workspace,softwareSystem) + val diagramsVisible = generatorContext.workspace.views.hasContainerViews(generatorContext, softwareSystem) + val imagesVisible = images.isNotEmpty() } 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 c163e39d..bef139f9 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, DYNAMIC, DEPLOYMENT, DEPENDENCIES, DECISIONS, SECTIONS } + enum class Tab { HOME, SYSTEM_CONTEXT, CONTAINER, COMPONENT, CODE, 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.CODE -> "Code views" Tab.DYNAMIC -> "Dynamic views" Tab.DEPLOYMENT -> "Deployment views" Tab.DEPENDENCIES -> "Dependencies" @@ -32,8 +33,9 @@ open class SoftwareSystemPageViewModel( Tab.HOME -> true Tab.DEPENDENCIES -> true Tab.SYSTEM_CONTEXT -> generatorContext.workspace.views.hasSystemContextViews(softwareSystem) - Tab.CONTAINER -> generatorContext.workspace.views.hasContainerViews(softwareSystem) - Tab.COMPONENT -> generatorContext.workspace.views.hasComponentViews(softwareSystem) + Tab.CONTAINER -> generatorContext.workspace.views.hasContainerViews(generatorContext, softwareSystem) + Tab.COMPONENT -> generatorContext.workspace.views.hasComponentViews(generatorContext, softwareSystem) + Tab.CODE -> generatorContext.workspace.views.hasCodeViews(generatorContext, softwareSystem) Tab.DYNAMIC -> generatorContext.workspace.views.hasDynamicViews(softwareSystem) Tab.DEPLOYMENT -> generatorContext.workspace.views.hasDeploymentViews(softwareSystem) Tab.DECISIONS -> softwareSystem.hasDecisions() or softwareSystem.hasContainerDecisions() @@ -49,6 +51,7 @@ open class SoftwareSystemPageViewModel( TabViewModel(Tab.SYSTEM_CONTEXT), TabViewModel(Tab.CONTAINER), TabViewModel(Tab.COMPONENT), + TabViewModel(Tab.CODE), TabViewModel(Tab.DYNAMIC), TabViewModel(Tab.DEPLOYMENT), TabViewModel(Tab.DEPENDENCIES), @@ -66,6 +69,7 @@ open class SoftwareSystemPageViewModel( Tab.SYSTEM_CONTEXT -> "$home/context" Tab.CONTAINER -> "$home/container" Tab.COMPONENT -> "$home/component" + Tab.CODE -> "$home/code" Tab.DYNAMIC -> "$home/dynamic" Tab.DEPLOYMENT -> "$home/deployment" Tab.DEPENDENCIES -> "$home/dependencies" diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/Image.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/Image.kt new file mode 100644 index 00000000..30177e7c --- /dev/null +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/Image.kt @@ -0,0 +1,16 @@ +package nl.avisi.structurizr.site.generatr.site.views + +import com.structurizr.view.ImageView +import kotlinx.html.* + +fun FlowContent.image(image: ImageView) { + figure { + p(classes = "has-text-weight-bold"){+image.title} + img { + src = image.content + } + figcaption { + +image.description + } + } +} diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemCodePage.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemCodePage.kt new file mode 100644 index 00000000..da0d2c97 --- /dev/null +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemCodePage.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.SoftwareSystemCodePageViewModel + +fun HTML.softwareSystemCodePage(viewModel: SoftwareSystemCodePageViewModel) { + if (viewModel.imagesVisible) { + softwareSystemPage(viewModel) { + viewModel.images.forEach { + image(it) + } + } + } else + redirectUpPage() +} diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemComponentPage.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemComponentPage.kt index e61bddcd..e35ce9ad 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemComponentPage.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemComponentPage.kt @@ -4,10 +4,17 @@ import kotlinx.html.HTML import nl.avisi.structurizr.site.generatr.site.model.SoftwareSystemComponentPageViewModel fun HTML.softwareSystemComponentPage(viewModel: SoftwareSystemComponentPageViewModel) { - if (viewModel.visible) + if (viewModel.diagramsVisible || viewModel.imagesVisible) softwareSystemPage(viewModel) { - viewModel.diagrams.forEach { - diagram(it) + if (viewModel.diagramsVisible) { + viewModel.diagrams.forEach { + diagram(it) + } + } + if (viewModel.imagesVisible) { + viewModel.images.forEach { + image(it) + } } } else diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerPage.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerPage.kt index 3a414c60..183e2146 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerPage.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/SoftwareSystemContainerPage.kt @@ -4,10 +4,17 @@ import kotlinx.html.HTML import nl.avisi.structurizr.site.generatr.site.model.SoftwareSystemContainerPageViewModel fun HTML.softwareSystemContainerPage(viewModel: SoftwareSystemContainerPageViewModel) { - if (viewModel.visible) + if (viewModel.diagramsVisible || viewModel.imagesVisible) softwareSystemPage(viewModel) { - viewModel.diagrams.forEach { - diagram(it) + if (viewModel.diagramsVisible) { + viewModel.diagrams.forEach { + diagram(it) + } + } + if (viewModel.imagesVisible) { + viewModel.images.forEach { + image(it) + } } } else diff --git a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemCodePageViewModelTest.kt b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemCodePageViewModelTest.kt new file mode 100644 index 00000000..d99ec087 --- /dev/null +++ b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemCodePageViewModelTest.kt @@ -0,0 +1,47 @@ +package nl.avisi.structurizr.site.generatr.site.model + +import assertk.assertThat +import assertk.assertions.hasSize +import assertk.assertions.isEqualTo +import assertk.assertions.isFalse +import com.structurizr.model.SoftwareSystem +import kotlin.test.Test + +class SoftwareSystemCodePageViewModelTest : ViewModelTest() { + private val generatorContext = generatorContext() + private val softwareSystem: SoftwareSystem = generatorContext.workspace.model.addSoftwareSystem("Software system") + private val container = softwareSystem.addContainer("container") + private val component = container.addComponent("component") + private val imageView = generatorContext.workspace.views.createImageView(component, "imageview-001").also { + it.description = "Image View Description" + it.title = "Image View Title" + it.contentType = "image/png" + it.content = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" + } + + @Test + fun `active tab`() { + val viewModel = SoftwareSystemCodePageViewModel(generatorContext, softwareSystem) + + assertThat(viewModel.tabs.single { it.link.active }.tab) + .isEqualTo(SoftwareSystemPageViewModel.Tab.CODE) + } + + @Test + fun `check code page model has 1 image and it matches the above imageView`() { + val viewModel = SoftwareSystemCodePageViewModel(generatorContext, softwareSystem) + + assertThat(viewModel.images).hasSize(1) + assertThat(viewModel.images[0]).isEqualTo(imageView) + } + + @Test + fun `hidden view`() { + val viewModel = SoftwareSystemCodePageViewModel( + generatorContext, + generatorContext.workspace.model.addSoftwareSystem("Software system 2") + ) + + assertThat(viewModel.imagesVisible).isFalse() + } +} diff --git a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemComponentPageViewModelTest.kt b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemComponentPageViewModelTest.kt index b9e145c4..062aae35 100644 --- a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemComponentPageViewModelTest.kt +++ b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemComponentPageViewModelTest.kt @@ -57,6 +57,6 @@ class SoftwareSystemComponentPageViewModelTest : ViewModelTest() { generatorContext.workspace.model.addSoftwareSystem("Software system 2") ) - assertThat(viewModel.visible).isFalse() + assertThat(viewModel.diagramsVisible).isFalse() } } diff --git a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerPageViewModelTest.kt b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerPageViewModelTest.kt index ee336b98..55f3d3ee 100644 --- a/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerPageViewModelTest.kt +++ b/src/test/kotlin/nl/avisi/structurizr/site/generatr/site/model/SoftwareSystemContainerPageViewModelTest.kt @@ -56,6 +56,6 @@ class SoftwareSystemContainerPageViewModelTest : ViewModelTest() { generatorContext.workspace.model.addSoftwareSystem("Software system 2") ) - assertThat(viewModel.visible).isFalse() + assertThat(viewModel.diagramsVisible).isFalse() } } 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 d1b35d19..15378f57 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.CODE, Tab.DYNAMIC, Tab.DEPLOYMENT, Tab.DEPENDENCIES, @@ -73,6 +74,7 @@ class SoftwareSystemPageViewModelTest : ViewModelTest() { "Context views", "Container views", "Component views", + "Code views", "Dynamic views", "Deployment views", "Dependencies",