Example Input

---
# Things in the diagram.
#
# This map defines the `ThingId`s and their display names.
things: &things
  t_aws: "☁️ Amazon Web Services"
  t_aws_iam: "🖊️ Identity and Access Management"
  t_aws_iam_ecs_policy: "🗒️ ECS IAM Policy"
  t_aws_ecr: "🗄️ Elastic Container Registry"
  t_aws_ecr_repo: "💽 web_app repo"
  t_aws_ecr_repo_image_1: "💿 Image 1"
  t_aws_ecr_repo_image_2: "💿 Image 2"
  t_aws_ecs: "💻 Elastic Container Service"
  t_aws_ecs_cluster_app: "🎛️ web_app cluster"
  t_aws_ecs_cluster_app_task: "🖨️ web_app task version 1"
  t_github: "🐙 GitHub"
  t_github_user_repo: "azriel91/web_app"
  t_localhost: "🧑‍💻 Localhost"
  t_localhost_repo: "📂 ~/work/web_app"
  t_localhost_repo_src: "📝 src"
  t_localhost_repo_target: "📂 target"
  t_localhost_repo_target_file_zip: "📝 file.zip"
  t_localhost_repo_target_dist_dir: "📁 dist"

# Render a copy text button, and, when clicked, what text to place on the clipboard.
thing_copy_text:
  <<: *things
  t_localhost_repo: "~/work/web_app"
  t_localhost_repo_src: "~/work/web_app/src"
  t_localhost_repo_target: "~/work/web_app/target"
  t_localhost_repo_target_file_zip: "~/work/web_app/target/file.zip"
  t_localhost_repo_target_dist_dir: "~/work/web_app/target/dist"

# Hierarchy of `thing`s.
#
# The `ThingHierarchy` is a tree structure stored as a map of `ThingId` to `ThingHierarchy`. This structure is strictly unidirectional.
#
# This defines the nesting, but perhaps we should use it to define the relative positioning as well.
#
# Do we want users to have control? Probably some, e.g. the order of declaration affects the
# position of the `thing` in a flex box.
#
# Other question, the positioning for a software dependency tree is different to the positioning
# for deployment topology. Maybe we allow the user to specify either "rank" based layout or "flow"
# based layout.
thing_hierarchy:
  t_aws:
    t_aws_iam:
      t_aws_iam_ecs_policy: {}
    t_aws_ecr:
      t_aws_ecr_repo:
        t_aws_ecr_repo_image_1: {}
        t_aws_ecr_repo_image_2: {}

  t_github:
    t_github_user_repo: {}

  t_localhost:
    t_localhost_repo:
      t_localhost_repo_src: {}
      t_localhost_repo_target:
        t_localhost_repo_target_file_zip: {}
        t_localhost_repo_target_dist_dir: {}

# How to position things on the diagram.
#
# Not sure if this is the right approach yet, but ideas:
#
# * `rank`: `thing_dependencies`' edges affect how far a `thing` is from the beginning position.
# * `flex`: `thing_hierarchy` alternates between horizontal and vertical flex axes.
#
# ```yaml
# thing_layout:
#   # one of:
#   flex: "row"
#   # flex: "column"
#   # rank: "horizontal"
#   # rank: "vertical"
# ```

# Dependencies between things can be one way, or cyclic.
#
# Dependencies are static relationships between things, and should be rendered as "on" or "off"
# depending on whether a `thing` is focused / targeted, and whether the user wants to see:
#
# * Predecessors / successors linked to this thing.
# * Immediate dependencies vs transitive (maybe closest `n` neighbours).
#
# * When B depends on A, it means A must exist before B.
# * Changes to A means B is out of date.
#
# How we render dependencies (forward / backward / undirected / bidirectional arrows) can be
# defined separately from the meaning of the dependency.
#
# We want to make it easy to define dependencies between chains of things.
thing_dependencies: &thing_dependencies
  edge_t_localhost__t_github_user_repo__pull:
    # Cyclic dependencies are where the last thing in the list has an edge back to first thing.
    #
    # Should have at least one `thing`.
    cyclic:
      - t_localhost
      - t_github_user_repo
  edge_t_localhost__t_github_user_repo__push:
    # Can have 2 or more things
    sequence:
      - t_localhost
      - t_github_user_repo
  edge_t_localhost__t_localhost__within:
    cyclic:
      - t_localhost
  edge_t_github_user_repo__t_github_user_repo__within:
    cyclic:
      - t_github_user_repo
  edge_t_github_user_repo__t_aws_ecr_repo__push:
    sequence:
      - t_github_user_repo
      - t_aws_ecr_repo
  edge_t_aws_ecr_repo__t_aws_ecs_service__push:
    sequence:
      - t_aws_ecr_repo
      - t_aws_ecs_service

# Descriptions to render next to each node, edge group, or edge.
#
# This is intended to take markdown text.
#
# # Notes
#
# 1. Edge group IDs are from either `thing_dependencies` or `thing_interactions`.
# 2. Edge IDs are their edge group IDs, suffixed with "__" and the zero-based index of that edge in its group.
# 3. Descriptions for processes are not currently supported.
# 4. Descriptions for process steps are defined within the `process`'s `step_descs`.
entity_descs:
  # things
  t_localhost: "User's computer"

  # edge groups
  #
  # Shown when any of the edges in this group are focused.
  edge_t_localhost__t_github_user_repo__pull: |-
    Fetch from GitHub
  edge_t_localhost__t_github_user_repo__push: |-
    Push to GitHub

  # edges
  edge_t_localhost__t_github_user_repo__pull__0: |-
    `git pull`
  edge_t_localhost__t_github_user_repo__push__0: |-
    `git push`

# Interactions between things can be one way, or cyclic.
#
# Interactions have the same data structure as dependencies, but are conceptually different:
# `thing_dependencies` is intended to represent dependencies between software libraries,
# while interactions are communication between applications.
#
# There *are* ordering dependencies between interactions, but *when* it is useful to render
# `thing_dependencies` and `thing_interactions` differ. Dependencies are static at a point in time,
# so it is useful to render the links between multiple `thing`s; interactions are present when a
# step in a process is executing, so they are rendered when the step is focused.
#
# IDs here can be the same as the ones in `thing_dependencies`.
#
# We want to make it easy to define interactions between chains of things.
thing_interactions: *thing_dependencies # cheat and use yaml reference

# Processes are groupings of interactions between things sequenced over time.
#
# We want to make it easy to see which things are involved (in each step of) a process. By
# highlighting the things / edges when a user focuses on a step in a process, it brings clarity to
# the user.
processes:
  proc_app_dev:
    name: "App Development"
    desc: |-
      Development of the web application.

      * [🐙 Repo](https://github.com/azriel91/web_app)
    steps:
      proc_app_dev_step_repository_clone: "Clone repository"
      proc_app_dev_step_project_build: "Build project"
    step_descs:
      proc_app_dev_step_repository_clone: |-
        ```bash
        git clone https://github.com/azriel91/web_app.git
        ```

      proc_app_dev_step_project_build: |-
        Develop the app:

        * Always link to issue.
        * Open PR.

    # Thing interactions that should be actively highlighted when this step is focused.
    #
    # The things associated with all of the interaction IDs in the list should be highlighted.
    #
    # optional, references IDs in `thing_interactions` top level element.
    step_thing_interactions:
      proc_app_dev_step_repository_clone: [edge_t_localhost__t_github_user_repo__pull]
      proc_app_dev_step_project_build: [edge_t_localhost__t_localhost__within]

  proc_app_release:
    name: "App Release"
    steps:
      proc_app_release_step_crate_version_update: "Update crate versions"
      proc_app_release_step_pull_request_open: "Open PR"
      proc_app_release_step_tag_and_push: "Tag and push"
      proc_app_release_step_gh_actions_build: "Github Actions build"
      proc_app_release_step_gh_actions_publish: "Github Actions publish"

    step_descs:
      proc_app_release_step_crate_version_update: |-
        ```bash
        sd -s 'version = "0.3.0"' 'version = "0.3.0"' $(fd -tf -F toml) README.md src/lib.rs
        ```
      proc_app_release_step_pull_request_open: |-
        Create a pull request as usual.
      proc_app_release_step_gh_actions_build: |-
        Github Actions will build the image.
      proc_app_release_step_tag_and_push: |-
        When the PR is merged, tag the commit and push the tag to GitHub.

        ```bash
        git tag 0.3.0
        git push origin 0.3.0
        ```

        The build will push the new version to ECR automatically.
      proc_app_release_step_gh_actions_publish: |-
        Github Actions will publish the image to AWS ECR.

    step_thing_interactions:
      proc_app_release_step_crate_version_update: [edge_t_localhost__t_localhost__within]
      proc_app_release_step_pull_request_open: [edge_t_localhost__t_github_user_repo__pull]
      proc_app_release_step_tag_and_push: [edge_t_localhost__t_github_user_repo__push]
      proc_app_release_step_gh_actions_build: [edge_t_github_user_repo__t_github_user_repo__within]
      proc_app_release_step_gh_actions_publish: [edge_t_github_user_repo__t_aws_ecr_repo__push]

  # Some processes not defined yet.
  #
  # proc_i12e_global_deploy: {}
  # proc_i12e_region_mgmt_deploy: {}
  # proc_i12e_region_tier_subnets_deploy: {}
  proc_i12e_region_tier_app_deploy:
    name: "Prod App Deploy"
    steps:
      proc_i12e_region_tier_app_deploy_step_ecs_service_update: "Update ECS service"

    step_descs:
      proc_i12e_region_tier_app_deploy_step_ecs_service_update: |-
        Deploy or update the existing ECS service with the new image.
    step_thing_interactions:
      proc_i12e_region_tier_app_deploy_step_ecs_service_update:
        [edge_t_aws_ecr_repo__t_aws_ecs_service__push]

# Tags are labels that can be associated with things, so that the things can be highlighted when
# the tag is focused.
tags:
  tag_app_development: "Application Development"
  tag_deployment: "Deployment"

# Things associated with each tag.
#
# It probably makes sense to specify the `things` for each tag, than the tags associated with each
# thing. i.e. the key being the tag, instead of the key being the `thing` IDs.
tag_things:
  tag_app_development:
    - t_github_user_repo
    - t_localhost
  tag_deployment:
    - t_aws_ecr_repo
    - t_github_user_repo

# `Type`s are automatically attached to each entity:
#
# * `things`
# * `thing_dependencies`
# * `tags`
# * `processes`
# * `process_steps`
#
# These allow us to apply a common set of styles to the entities in the diagram with less
# duplication.
#
# Note: these do not actually appear in the diagram schema, but are listed so we know what default
# types are available.
#
# ```yaml
# types:
#   - type_thing_default
#   - type_tag_default
#   - type_process_default
#   - type_process_step_default
#   - type_edge_dependency_sequence_request_default
#   - type_edge_dependency_sequence_response_default
#   - type_edge_dependency_cyclic_default
#   - type_edge_interaction_sequence_request_default
#   - type_edge_interaction_sequence_response_default
#   - type_edge_interaction_cyclic_default
# ```
#
# Additional `type`s we attach to `things` / `thing_dependencies` / `tags`, so they can be styled
# in common.
#
# This is like a tag, but doesn't require the user to click on the tag to apply the style.
#
# Built-in types that are automatically attached to entities unless overridden:
#
# * `type_thing_default`
# * `type_tag_default`
# * `type_process_default`
# * `type_process_step_default`
#
# For edges, multiple edges are generated for each dependency / interaction,
# and each edge is assigned a type from the following:
#
# * `type_edge_dependency_sequence_request_default`
# * `type_edge_dependency_sequence_response_default`
# * `type_edge_dependency_cyclic_default`
# * `type_edge_interaction_sequence_request_default`
# * `type_edge_interaction_sequence_response_default`
# * `type_edge_interaction_cyclic_default`
#
# The edge ID will be the edge group ID specified in `thing_dependencies` /
# `thing_interactions`, suffixed with the zero-based index of the edge like
# so:
#
# ```text
# edge_id = edge_group_id + "__" + edge_index
# ```
entity_types:
  t_aws: "type_organisation"
  t_aws_iam: "type_service"
  # t_aws_iam_ecs_policy: ~
  t_aws_ecr: "type_service"
  # t_aws_ecr_repo: ~
  t_aws_ecr_repo_image_1: "type_docker_image"
  t_aws_ecr_repo_image_2: "type_docker_image"
  t_aws_ecs: "type_service"
  # t_aws_ecs_cluster_app: ~
  # t_aws_ecs_cluster_app_task: ~
  t_github: "type_organisation"
  # t_github_user_repo: ~
  # t_localhost: ~
  # t_localhost_repo: ~
  # t_localhost_repo_src: ~
  # t_localhost_repo_target: ~
  # t_localhost_repo_target_file_zip: ~
  # t_localhost_repo_target_dist_dir: ~

  # edge_t_localhost__t_github_user_repo__pull__0: "type_edge_dependency_sequence_request_default"
  # edge_t_localhost__t_github_user_repo__pull__1: "type_edge_dependency_sequence_response_default"
  # edge_t_localhost__t_github_user_repo__push: ~
  # edge_t_localhost__t_localhost__within: ~
  # edge_t_github_user_repo__t_github_user_repo__within: ~
  # edge_t_github_user_repo__t_aws_ecr_repo__push: ~
  # edge_t_aws_ecr_repo__t_aws_ecs_service__push: ~

  # tag_app_development: "tag_type_default"
  # tag_deployment: "tag_type_default"

# Styles when the diagram has no user interaction.
#
# It's important for UX that the field nesting level (and hence indentation level) is consistent
# with the other `theme_*` data.
#
# `style_aliases` here are available to all the other `theme_*` data.
theme_default:
  # `StyleAliases` will have well-known keys, and is extendable to have custom keys.
  #
  # i.e. a `StyleAlias` enum, with a final variant of `Custom(String)`.
  style_aliases:
    padding_none:
      padding: "0"
    padding_tight:
      padding: "2"
    padding_normal:
      padding: "4"
    padding_wide:
      padding: "6"
    shade_pale:
      fill_shade_hover: "50"
      fill_shade_normal: "100"
      fill_shade_focus: "200"
      fill_shade_active: "300"
      stroke_shade_hover: "100"
      stroke_shade_normal: "200"
      stroke_shade_focus: "300"
      stroke_shade_active: "400"
      text_shade: "800"
    shade_light:
      fill_shade_hover: "200"
      fill_shade_normal: "300"
      fill_shade_focus: "400"
      fill_shade_active: "500"
      stroke_shade_hover: "300"
      stroke_shade_normal: "400"
      stroke_shade_focus: "500"
      stroke_shade_active: "600"
      text_shade: "900"
    shade_medium:
      fill_shade_hover: "400"
      fill_shade_normal: "500"
      fill_shade_focus: "600"
      fill_shade_active: "700"
      stroke_shade_hover: "500"
      stroke_shade_normal: "600"
      stroke_shade_focus: "700"
      stroke_shade_active: "800"
      text_shade: "950"
    shade_dark:
      fill_shade_hover: "600"
      fill_shade_normal: "700"
      fill_shade_focus: "800"
      fill_shade_active: "900"
      stroke_shade_hover: "700"
      stroke_shade_normal: "800"
      stroke_shade_focus: "900"
      stroke_shade_active: "950"
      text_shade: "50"
    stroke_dashed_animated:
      stroke_style: "dashed"
      stroke_width: "2"
      animate: "[stroke-dashoffset-move_2s_linear_infinite]"

  # The keys in this map can be:
  #
  # * `node_defaults`: Applies to all things.
  # * `edge_defaults`: Applies to all edges.
  # * `thing_id`: Applies to the particular thing.
  # * `edge_id`: Applies to the particular edge.
  # * `tag_id`: Applies to the tag.
  base_styles:
    node_defaults:
      # Vector of style aliases to apply.
      style_aliases_applied: [shade_light]
      # Used for both fill and stroke colors.
      shape_color: "slate"
      stroke_style: "solid"
      stroke_width: "1"
      text_color: "neutral"
      visibility: "visible"
    edge_defaults:
      stroke_width: "1"
      text_color: "neutral"
      visibility: "visible"
    edge_t_localhost__t_github_user_repo__pull:
      style_aliases_applied: [shade_light]
      shape_color: "blue"
    t_aws:
      shape_color: "yellow"
    t_github:
      shape_color: "neutral"

# Styles applied to things / edges of a particular `type` specified in `thing_types`.
theme_types_styles:
  # These are default styles that are built into `disposition`, but may be overridden by users.
  type_thing_default:
    node_defaults:
      style_aliases_applied: [shade_light]
      stroke_style: "solid"
      shape_color: "slate"
      stroke_width: "1"
  type_tag_default:
    node_defaults:
      style_aliases_applied: [shade_medium]
      stroke_style: "solid"
      shape_color: "emerald"
      stroke_width: "1"
  type_process_default:
    node_defaults:
      style_aliases_applied: [shade_medium]
      stroke_style: "solid"
      shape_color: "blue"
      stroke_width: "1"
  type_process_step_default:
    node_defaults:
      style_aliases_applied: [shade_medium]
      stroke_style: "solid"
      shape_color: "sky"
      stroke_width: "1"
  type_edge_dependency_sequence_request_default:
    edge_defaults:
      style_aliases_applied: [shade_dark]
      stroke_style: solid
      shape_color: "neutral"
      stroke_width: "1"
  type_edge_dependency_sequence_response_default:
    edge_defaults:
      style_aliases_applied: [shade_dark]
      stroke_style: solid
      shape_color: "neutral"
      stroke_width: "1"
  type_edge_dependency_cyclic_default:
    edge_defaults:
      style_aliases_applied: [shade_dark]
      stroke_style: solid
      shape_color: "neutral"
      stroke_width: "1"
  type_edge_interaction_sequence_request_default:
    edge_defaults:
      style_aliases_applied: [shade_dark]
      stroke_style: "dasharray:0,80,12,2,4,2,2,2,1,2,1,120"
      shape_color: "violet"
      stroke_width: "2"
  type_edge_interaction_sequence_response_default:
    edge_defaults:
      style_aliases_applied: [shade_dark]
      stroke_style: "dasharray:0,120,1,2,1,2,2,2,4,2,8,2,20,80"
      shape_color: "violet"
      stroke_width: "2"
  type_edge_interaction_cyclic_default:
    edge_defaults:
      style_aliases_applied: [shade_dark]
      stroke_style: "dasharray:0,80,12,2,4,2,2,2,1,2,1,120"
      shape_color: "violet"
      stroke_width: "2"

  # custom styles that users can provide
  type_organisation:
    node_defaults:
      style_aliases_applied: [shade_pale]
      stroke_style: "dotted"
  type_service:
    node_defaults:
      stroke_style: "dashed"

  type_docker_image:
    node_defaults:
      shape_color: "sky"

# Styles when a `thing` is focused.
#
# Depending on which button is pressed, when a `thing` is focused, these same styles may be used to
# show:
#
# * Predecessors / successors linked to this `thing`.
# * Immediate dependencies vs transitive (maybe closest `n` neighbours).
theme_thing_dependencies_styles:
  things_excluded_styles:
    node_defaults:
      visibility: "hidden"
    edge_defaults:
      visibility: "hidden"
  things_included_styles:
    node_defaults:
      visibility: "visible"

# When a tag is focused, things and edges associated with the tag are highlighted.
#
# We also want to allow things that are not associated with the tag to be styled, but having one
# layer with the tag ID, and one layer of `things_included_styles` and `things_excluded_styles`
# makes it one nesting level deeper than the other `theme_*` keys.
#
# So we have a `theme_tag_things_focus` map that applies to all tags' styles, and if the consumer
# wants to style things differently per tag, they can do so in the
# `theme_tag_things_focus_specific` map.
theme_tag_things_focus:
  things_included_styles:
    node_defaults:
      style_aliases_applied: [shade_pale, stroke_dashed_animated]
  things_excluded_styles:
    node_defaults:
      opacity: "0.5"

theme_tag_things_focus_specific:
  tag_app_development:
    node_defaults:
      style_aliases_applied: [stroke_dashed_animated]

# Additional CSS to place in the SVG's inline `<styles>` section.
css: |-
  @keyframes stroke-dashoffset-move {
    0%   { stroke-dashoffset: 30; }
    100% { stroke-dashoffset: 0; }
  }
  @keyframes stroke-dashoffset-move-request {
    0%   { stroke-dashoffset: 0; }
    100% { stroke-dashoffset: 228; }
  }