Skip to content

Commit

Permalink
Detect external systems by tag
Browse files Browse the repository at this point in the history
Replace our own heuristics based on groups. Therefore add
a property "generatr.site.excludedTag" to define the name of
the tag that identifies external systems.

Also adjust example.
  • Loading branch information
jp7677 committed Nov 3, 2023
1 parent 2f1612d commit 57d3ec7
Show file tree
Hide file tree
Showing 12 changed files with 150 additions and 64 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ is generated from the example workspace in this repository.
- Generates diagrams in SVG, PNG and PlantUML format, which can be viewed and downloaded from the generated site.
- Easy browsing through the site by clicking on software system and container elements in the diagrams. Note that
external software systems are excluded from the menu. A software system is considered external when it lives outside
the (deprecated) enterprise boundary or when groups are used and the software system is outside of any group.
the (deprecated) enterprise boundary or when it contains the tag that is defined in "generatr.site.excludedTag".
See (Customizing the generated website).
- Start a development server which generates a site, serves it and updates the site automatically whenever a file that's
part of the Structurizr workspace changes.
- Include documentation (in Markdown or AsciiDoc format) in the generated site. Both workspace level documentation and software
Expand Down Expand Up @@ -266,8 +267,8 @@ architecture model:
| `generatr.search.language` | Indexing/stemming language for the search index. See [Lunr language support](https://github.com/olivernn/lunr-languages) | `en` | `nl` |
| `generatr.markdown.flexmark.extensions` | Additional extensions to the markdown generator to add new markdown capabilities. [More Details](https://avisi-cloud.github.io/structurizr-site-generatr/main/extended-markdown-features/) | Tables | `Tables,Admonition` |
| `generatr.svglink.target` | Specifies the link target for element links in the exported svg | `_top` | `_self` |
| `generatr.site.nestGroups` | Will show software systems in the left side navigator in collapsable groups | `false` | `true` |

| `generatr.site.excludedTag` | Software systems containing this tag name will be considered external | | |
| `generatr.site.nestGroups` | Will show software systems in the left side navigator in collapsable ~~~~groups | `false` | `true` |

See the included example for usage of some those properties in the
[C4 architecture model example](https://github.com/avisi-cloud/structurizr-site-generatr/blob/main/docs/example/workspace.dsl#L163).
Expand Down
1 change: 1 addition & 0 deletions docs/example/workspace.dsl
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ workspace "Big Bank plc" "This is an example workspace to illustrate the key fea
// default behaviour, if no generatr.markdown.flexmark.extensions property is specified, is to load the Tables extension only
"generatr.markdown.flexmark.extensions" "Abbreviation,Admonition,AnchorLink,Attributes,Autolink,Definition,Emoji,Footnotes,GfmTaskList,GitLab,MediaTags,Tables,TableOfContents,Typographic"

"generatr.site.excludedTag" "External System"
"generatr.site.nestGroups" "false"
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
package nl.avisi.structurizr.site.generatr

import com.structurizr.Workspace
import com.structurizr.model.Container
import com.structurizr.model.Location
import com.structurizr.model.Model
import com.structurizr.model.SoftwareSystem
import com.structurizr.view.ViewSet

val Model.includedSoftwareSystems: List<SoftwareSystem>
get() = if (softwareSystems.any { it.group != null })
softwareSystems.filter { it.group != null }
else
softwareSystems.filter { it.location != Location.External }

val Container.hasComponents
get() = this.components.isNotEmpty()
val Workspace.includedSoftwareSystems: List<SoftwareSystem>
get() = model.softwareSystems.filter {
val excludedTag = views.configuration.properties.getOrDefault("generatr.site.excludedTag", null)
it.location != Location.External && if (excludedTag != null) !it.tags.contains(excludedTag) else true
}

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

val SoftwareSystem.includedProperties
get() = this.properties.filterNot { (name, _) -> name == "structurizr.dsl.identifier" }

val Container.hasComponents
get() = this.components.isNotEmpty()

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

fun SoftwareSystem.hasContainerDecisions() = containers.any { it.hasDecisions() }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package nl.avisi.structurizr.site.generatr.site

import com.structurizr.Workspace
import com.structurizr.export.Diagram
import com.structurizr.export.IndentingWriter
import com.structurizr.export.plantuml.C4PlantUMLExporter
Expand All @@ -10,6 +11,7 @@ import com.structurizr.view.*
import nl.avisi.structurizr.site.generatr.*

class C4PlantUmlExporterWithElementLinks(
private val workspace: Workspace,
private val url: String
) : C4PlantUMLExporter() {
companion object {
Expand Down Expand Up @@ -48,15 +50,15 @@ class C4PlantUmlExporterWithElementLinks(
}

private fun needsLinkToSoftwareSystem(element: Element?, view: ModelView?) =
element is SoftwareSystem && view != null && view.model.includedSoftwareSystems.contains(element) && element != view.softwareSystem
element is SoftwareSystem && view != null && 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?) =
element is SoftwareSystem && view != null && view.model.includedSoftwareSystems.contains(element) && element == view.softwareSystem && element.hasContainers
element is SoftwareSystem && view != null && workspace.includedSoftwareSystems.contains(element) && element == view.softwareSystem && element.hasContainers

private fun getUrlToContainerViews(element: Element?): String {
val path = "/${element?.name?.normalize()}/container/".asUrlToDirectory(url)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.structurizr.view.View
import net.sourceforge.plantuml.FileFormat
import net.sourceforge.plantuml.FileFormatOption
import net.sourceforge.plantuml.SourceStringReader
import nl.avisi.structurizr.site.generatr.includedSoftwareSystems
import nl.avisi.structurizr.site.generatr.site.C4PlantUmlExporterWithElementLinks.Companion.export
import java.io.ByteArrayOutputStream
import java.io.File
Expand Down Expand Up @@ -83,7 +84,7 @@ private fun saveAsPng(diagram: Diagram, pngDir: File) {
}

private fun generatePlantUMLDiagramWithElementLinks(workspace: Workspace, view: View, url: String): Diagram {
val plantUMLExporter = C4PlantUmlExporterWithElementLinks(url)
val plantUMLExporter = C4PlantUmlExporterWithElementLinks(workspace, url)

if (workspace.views.configuration.properties.containsKey("generatr.svglink.target")) {
plantUMLExporter.addSkinParam(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ private fun generateHtmlFiles(context: GeneratorContext, branchDir: File) {
add { writeHtmlFile(branchDir, WorkspaceDecisionPageViewModel(context, it)) }
}

context.workspace.model.includedSoftwareSystems.forEach {
context.workspace.includedSoftwareSystems.forEach {
add { writeHtmlFile(branchDir, SoftwareSystemHomePageViewModel(context, it)) }
add { writeHtmlFile(branchDir, SoftwareSystemContextPageViewModel(context, it)) }
add { writeHtmlFile(branchDir, SoftwareSystemContainerPageViewModel(context, it)) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ abstract class PageViewModel(protected val generatorContext: GeneratorContext) {
val flexmarkConfig by lazy { buildFlexmarkConfig(generatorContext) }
val includeAdmonition = flexmarkConfig.selectedExtensionMap.containsKey("Admonition")
val includeKatex = flexmarkConfig.selectedExtensionMap.containsKey("GitLab")
val includedSoftwareSystems = generatorContext.workspace.model.includedSoftwareSystems
val includedSoftwareSystems = generatorContext.workspace.includedSoftwareSystems
val configuration = generatorContext.workspace.views.configuration.properties
val includeTreeview = configuration.getOrDefault("generatr.site.nestGroups", "false").toBoolean()

Expand Down
Loading

0 comments on commit 57d3ec7

Please sign in to comment.