archsight 0.3.3 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +7 -1
- data/docs/archimate.md +21 -1
- data/docs/configuration.md +1 -0
- data/docs/diagram.md +15 -3
- data/docs/docker.md +4 -1
- data/docs/icons.md +8 -2
- data/docs/import.md +178 -55
- data/docs/index.md.erb +24 -18
- data/docs/modeling.md +645 -34
- data/docs/pages.md +46 -15
- data/docs/search.md +21 -1
- data/docs/togaf.md +2 -1
- data/lib/archsight/analysis/result.rb +8 -2
- data/lib/archsight/analysis/sandbox.rb +8 -0
- data/lib/archsight/analysis/typst_renderer.rb +245 -0
- data/lib/archsight/analysis.rb +1 -0
- data/lib/archsight/annotations/annotation.rb +30 -3
- data/lib/archsight/annotations/architecture_annotations.rb +47 -0
- data/lib/archsight/annotations/link_annotations.rb +15 -0
- data/lib/archsight/annotations/resource_reference.rb +12 -0
- data/lib/archsight/cli.rb +124 -23
- data/lib/archsight/database.rb +40 -0
- data/lib/archsight/diagram/cli.rb +50 -2
- data/lib/archsight/diagram/formatter.rb +112 -0
- data/lib/archsight/diagram/routing/edge_router/orthogonal_path.rb +38 -10
- data/lib/archsight/diagram/routing/edge_router.rb +29 -4
- data/lib/archsight/diagram/routing/edge_routing.rb +61 -5
- data/lib/archsight/diagram/style/theme.rb +7 -2
- data/lib/archsight/documentation.rb +4 -4
- data/lib/archsight/editor/page_source.rb +13 -1
- data/lib/archsight/export/confluence/analysis_output.rb +100 -0
- data/lib/archsight/export/confluence/client.rb +13 -0
- data/lib/archsight/export/confluence/diagram_links.rb +1 -1
- data/lib/archsight/export/confluence/exporter.rb +43 -14
- data/lib/archsight/export/confluence/labels.rb +25 -0
- data/lib/archsight/export/confluence/page_properties.rb +6 -9
- data/lib/archsight/export/confluence/storage.rb +63 -14
- data/lib/archsight/export/confluence/tables.rb +2 -3
- data/lib/archsight/git_source.rb +81 -0
- data/lib/archsight/helpers/asset_images.rb +3 -4
- data/lib/archsight/helpers/embeds.rb +18 -7
- data/lib/archsight/helpers/resource_resolver.rb +25 -0
- data/lib/archsight/import/executor.rb +140 -16
- data/lib/archsight/import/handler.rb +55 -6
- data/lib/archsight/import/handler_loader.rb +64 -0
- data/lib/archsight/import/handlers/cache_pruner.rb +30 -7
- data/lib/archsight/import/handlers/command.rb +120 -0
- data/lib/archsight/import/handlers/github.rb +4 -1
- data/lib/archsight/import/handlers/gitlab.rb +4 -1
- data/lib/archsight/import/handlers/go_dep_resolver.rb +10 -2
- data/lib/archsight/import/handlers/go_grapher.rb +102 -5
- data/lib/archsight/import/handlers/go_module_parser.rb +88 -0
- data/lib/archsight/import/handlers/grapher.rb +40 -1
- data/lib/archsight/import/handlers/repository.rb +3 -0
- data/lib/archsight/import/handlers/rest_api_index.rb +3 -0
- data/lib/archsight/import/registry.rb +22 -1
- data/lib/archsight/import.rb +89 -1
- data/lib/archsight/linter/structure.rb +239 -0
- data/lib/archsight/linter.rb +123 -16
- data/lib/archsight/markdown.rb +48 -0
- data/lib/archsight/openapi.rb +169 -0
- data/lib/archsight/page_loader.rb +12 -1
- data/lib/archsight/page_tree.rb +2 -3
- data/lib/archsight/query/evaluator.rb +13 -6
- data/lib/archsight/query/parser.rb +73 -6
- data/lib/archsight/query.rb +1 -1
- data/lib/archsight/references.rb +3 -3
- data/lib/archsight/renderer.rb +80 -23
- data/lib/archsight/resources/analysis.rb +3 -2
- data/lib/archsight/resources/application_component.rb +75 -7
- data/lib/archsight/resources/application_interface.rb +12 -0
- data/lib/archsight/resources/application_service.rb +12 -1
- data/lib/archsight/resources/base.rb +58 -5
- data/lib/archsight/resources/business_actor.rb +5 -0
- data/lib/archsight/resources/business_contract.rb +72 -0
- data/lib/archsight/resources/business_product.rb +12 -0
- data/lib/archsight/resources/business_role.rb +1 -0
- data/lib/archsight/resources/implementation_deliverable.rb +1 -0
- data/lib/archsight/resources/implementation_plateau.rb +8 -2
- data/lib/archsight/resources/implementation_work_package.rb +2 -1
- data/lib/archsight/resources/import.rb +37 -11
- data/lib/archsight/resources/location.rb +56 -0
- data/lib/archsight/resources/motivation_requirement.rb +6 -0
- data/lib/archsight/resources/motivation_stakeholder.rb +14 -0
- data/lib/archsight/resources/page.rb +4 -7
- data/lib/archsight/resources/strategy_capability.rb +9 -0
- data/lib/archsight/resources/technology_artifact.rb +11 -4
- data/lib/archsight/resources/technology_communication_network.rb +91 -0
- data/lib/archsight/resources/technology_device.rb +88 -0
- data/lib/archsight/resources/technology_equipment.rb +75 -0
- data/lib/archsight/resources/technology_facility.rb +70 -0
- data/lib/archsight/resources/technology_node.rb +50 -0
- data/lib/archsight/resources/technology_service.rb +33 -0
- data/lib/archsight/resources/technology_system_software.rb +28 -0
- data/lib/archsight/resources.rb +12 -0
- data/lib/archsight/version.rb +1 -1
- data/lib/archsight/web/api/analysis_helpers.rb +55 -0
- data/lib/archsight/web/api/docs.rb +2 -1
- data/lib/archsight/web/api/json_helpers.rb +3 -37
- data/lib/archsight/web/api/openapi/spec.yaml +146 -35
- data/lib/archsight/web/api/page_helpers.rb +1 -8
- data/lib/archsight/web/api/routes.rb +9 -4
- data/lib/archsight/web/application.rb +40 -4
- data/lib/archsight/web/editor/routes.rb +2 -1
- data/lib/archsight/web/public/vendor/redoc/LICENSE +22 -0
- data/lib/archsight/web/public/vendor/redoc/VERSION +1 -0
- data/lib/archsight/web/public/vendor/redoc/api.html +27 -0
- data/lib/archsight/web/public/vendor/redoc/api.js +19 -0
- data/lib/archsight/web/public/vendor/redoc/redoc.standalone.js +1851 -0
- data/lib/archsight/web/public/vendor/redoc/redoc.standalone.js.LICENSE.txt +102 -0
- data/lib/archsight/web/public/vue/DocPage-C2ubTXH7.js +1 -0
- data/lib/archsight/web/public/vue/EditorPage-Dso6PLMn.js +35 -0
- data/lib/archsight/web/public/vue/ErrorPage-DnZ6YJLi.js +2 -0
- data/lib/archsight/web/public/vue/GraphView-CTl03Yre.js +1 -0
- data/lib/archsight/web/public/vue/HomePage-C339nihQ.js +2 -0
- data/lib/archsight/web/public/vue/InstanceRouter-DFW7tOrD.js +1 -0
- data/lib/archsight/web/public/vue/InstanceRouter-ZaCcjlIX.css +1 -0
- data/lib/archsight/web/public/vue/KindList-C0oaM3CF.js +1 -0
- data/lib/archsight/web/public/vue/KindList-yYcRT2BV.css +1 -0
- data/lib/archsight/web/public/vue/PageView-B93woeN3.css +1 -0
- data/lib/archsight/web/public/vue/PageView-OZB6G9Wu.js +1 -0
- data/lib/archsight/web/public/vue/QueryError-C2xLkCEm.js +1 -0
- data/lib/archsight/web/public/vue/ResourceList-D75O87zG.css +1 -0
- data/lib/archsight/web/public/vue/ResourceList-DooWFwQP.js +2 -0
- data/lib/archsight/web/public/vue/SearchResults-BK-HjFnv.js +1 -0
- data/lib/archsight/web/public/vue/{SearchResults-BewvsfOc.css → SearchResults-BV6UHriJ.css} +1 -1
- data/lib/archsight/web/public/vue/WikiPage-B2FYmeHL.js +3 -0
- data/lib/archsight/web/public/vue/WikiPage-TpmM1VAF.css +1 -0
- data/lib/archsight/web/public/vue/architecture-WOLXFQ4H-BGN-TV5r.js +1 -0
- data/lib/archsight/web/public/vue/cynefin-EF2NZ3EQ-CZd6g_tq.js +1 -0
- data/lib/archsight/web/public/vue/eventmodeling-K75KTNOO-CYnbEx8O.js +1 -0
- data/lib/archsight/web/public/vue/gitGraph-VSP46ZUC-DialfQSk.js +1 -0
- data/lib/archsight/web/public/vue/graphviz-1lWBhpEX.js +3 -0
- data/lib/archsight/web/public/vue/index-BLSE5DSv.css +1 -0
- data/lib/archsight/web/public/vue/index-CLuLTE5I.js +3 -0
- data/lib/archsight/web/public/vue/info-OHQRW6UA-BuhOW7ss.js +1 -0
- data/lib/archsight/web/public/vue/katex-B_JcIwqj.js +257 -0
- data/lib/archsight/web/public/vue/mermaid-C3bOamfn.js +3999 -0
- data/lib/archsight/web/public/vue/packet-JDAUHWVQ-CUeRz7w4.js +1 -0
- data/lib/archsight/web/public/vue/pie-XZMESJXO-DnuewJI6.js +1 -0
- data/lib/archsight/web/public/vue/radar-ABXABTNO-Bi9l8bcv.js +1 -0
- data/lib/archsight/web/public/vue/railroad-I3PHUGI6-DSlxFbxk.js +1 -0
- data/lib/archsight/web/public/vue/railroad-abnf-LNEFI6M7-D6Kqu8wu.js +1 -0
- data/lib/archsight/web/public/vue/railroad-ebnf-DWYD2UWJ-MR7uCYT0.js +1 -0
- data/lib/archsight/web/public/vue/railroad-peg-JR7BVNR7-BL7aKIc-.js +1 -0
- data/lib/archsight/web/public/vue/rolldown-runtime-COiEfhsA.js +1 -0
- data/lib/archsight/web/public/vue/treeView-D4JQ5SDB-CamtB04D.js +1 -0
- data/lib/archsight/web/public/vue/treemap-SAJKECNS-DeQxu_HM.js +1 -0
- data/lib/archsight/web/public/vue/{useGraphviz-DlSnFeCL.js → useGraphviz-Dnm2pkon.js} +2 -2
- data/lib/archsight/web/public/vue/useHighlight-BH32C7yt.js +10 -0
- data/lib/archsight/web/public/vue/usePanZoom-HxgEsqq2.js +12 -0
- data/lib/archsight/web/public/vue/wardley-7MLQ67FV-BvKIB6Tv.js +1 -0
- data/lib/archsight/web/public/vue.html +5 -5
- metadata +68 -41
- data/lib/archsight/web/public/vue/ApiDocsPage-BgqnQgwa.js +0 -1
- data/lib/archsight/web/public/vue/ApiDocsPage-DZ0fa5-h.css +0 -1
- data/lib/archsight/web/public/vue/DocPage-CNO71nBH.js +0 -1
- data/lib/archsight/web/public/vue/EditorPage-DR0FCNTz.js +0 -35
- data/lib/archsight/web/public/vue/ErrorPage-BfYArv6s.js +0 -2
- data/lib/archsight/web/public/vue/GraphView-BVTW30Ak.js +0 -1
- data/lib/archsight/web/public/vue/HomePage-Wk9P4Pma.js +0 -2
- data/lib/archsight/web/public/vue/InstanceRouter-BV8ycydz.js +0 -1
- data/lib/archsight/web/public/vue/InstanceRouter-jeavM6PW.css +0 -1
- data/lib/archsight/web/public/vue/KindList-C8yMsN5J.js +0 -1
- data/lib/archsight/web/public/vue/PageView-BaN6TyJB.js +0 -1
- data/lib/archsight/web/public/vue/QueryError-D790wH-a.js +0 -1
- data/lib/archsight/web/public/vue/ResourceList-B0FLaFR3.css +0 -1
- data/lib/archsight/web/public/vue/ResourceList-D-66nas2.js +0 -2
- data/lib/archsight/web/public/vue/SearchResults-CHyqIerQ.js +0 -1
- data/lib/archsight/web/public/vue/WikiPage-D2svpk6B.js +0 -13
- data/lib/archsight/web/public/vue/WikiPage-DoFJ0dbW.css +0 -1
- data/lib/archsight/web/public/vue/architecture-7GRP2DOG-BfA1TPxQ.js +0 -1
- data/lib/archsight/web/public/vue/cynefin-OW5HDTMX-BmgdUKVD.js +0 -1
- data/lib/archsight/web/public/vue/eventmodeling-NTZA5JFV-DbXDvAWF.js +0 -1
- data/lib/archsight/web/public/vue/gitGraph-4MIJSDKK-BkVhrKS1.js +0 -1
- data/lib/archsight/web/public/vue/graphviz-SXWTgZH5.js +0 -3
- data/lib/archsight/web/public/vue/index-BXXkUK1V.js +0 -3
- data/lib/archsight/web/public/vue/index-Cov1SnzY.css +0 -1
- data/lib/archsight/web/public/vue/info-A6RAGUB7-BIlCVuUY.js +0 -1
- data/lib/archsight/web/public/vue/katex-CXMH3UgJ.js +0 -257
- data/lib/archsight/web/public/vue/mermaid-BjEi5URd.js +0 -3334
- data/lib/archsight/web/public/vue/packet-AYTQ26CC-eoQTjY3j.js +0 -1
- data/lib/archsight/web/public/vue/pie-WAS4IAKB-DEOotGhh.js +0 -1
- data/lib/archsight/web/public/vue/radar-RG4KPBEZ-C2yucuUN.js +0 -1
- data/lib/archsight/web/public/vue/railroad-74A4TZTK-CzONK5VY.js +0 -1
- data/lib/archsight/web/public/vue/railroad-abnf-HS5TGJTU-9zRPsDsx.js +0 -1
- data/lib/archsight/web/public/vue/railroad-ebnf-LZEXJU2U-BJ4dkz9l.js +0 -1
- data/lib/archsight/web/public/vue/railroad-peg-WCYAUIDC-DFy_rqAj.js +0 -1
- data/lib/archsight/web/public/vue/treeView-Q6P3EWNA-2cq5CyD2.js +0 -1
- data/lib/archsight/web/public/vue/treemap-WGGIJYW6-DK-e9Ez4.js +0 -1
- data/lib/archsight/web/public/vue/useHighlight-D5Gf8DLl.js +0 -10
- data/lib/archsight/web/public/vue/wardley-WFR3VGLG-BQwqUqfB.js +0 -1
data/lib/archsight/resources.rb
CHANGED
|
@@ -14,6 +14,12 @@ module Archsight
|
|
|
14
14
|
"BusinessConstraint" => "MotivationConstraint"
|
|
15
15
|
}.freeze
|
|
16
16
|
|
|
17
|
+
# Annotations that were renamed: the old key is rewritten to the new one when a document is loaded (see
|
|
18
|
+
# Database#accept_old_names) and reported as deprecated by `archsight lint`.
|
|
19
|
+
ANNOTATION_ALIASES = {
|
|
20
|
+
"page/confluence" => "link/confluence"
|
|
21
|
+
}.freeze
|
|
22
|
+
|
|
17
23
|
# Relation keys (the plural kind names under `spec.<verb>`) that were renamed together with their kind
|
|
18
24
|
RELATION_KEY_ALIASES = {
|
|
19
25
|
"businessRequirements" => "motivationRequirements",
|
|
@@ -28,6 +34,12 @@ module Archsight
|
|
|
28
34
|
DERIVED_VERBS = %i[mentions depicts].freeze
|
|
29
35
|
DERIVED_KEY = :resources
|
|
30
36
|
|
|
37
|
+
# The layers a kind belongs to (Base.layer), top to bottom: why (motivation), what we want to become (strategy),
|
|
38
|
+
# how the change happens (implementation and migration), then the architecture it changes (business, application,
|
|
39
|
+
# technology). `other` holds the tool's own kinds (pages, views, imports, ...) and stays last. Everything that
|
|
40
|
+
# lists or orders layers uses this; the frontend repeats it in frontend/src/composables/useLayers.js.
|
|
41
|
+
LAYERS = %w[motivation strategy implementation business application technology other].freeze
|
|
42
|
+
|
|
31
43
|
# The derived relations of every class, next to the ones it declares: [verb, key, kind]
|
|
32
44
|
DERIVED_RELATIONS = DERIVED_VERBS.map { |verb| [verb, DERIVED_KEY, "Resource"] }.freeze
|
|
33
45
|
|
data/lib/archsight/version.rb
CHANGED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Archsight; end
|
|
4
|
+
module Archsight::Web; end
|
|
5
|
+
module Archsight::Web::API; end
|
|
6
|
+
|
|
7
|
+
# JSON of `POST /api/v1/kinds/Analysis/instances/:name/execute`: the result and its sections
|
|
8
|
+
module Archsight::Web::API::AnalysisHelpers
|
|
9
|
+
def build_analysis_result(result)
|
|
10
|
+
data = {
|
|
11
|
+
name: result.name,
|
|
12
|
+
success: result.success?,
|
|
13
|
+
has_findings: result.has_findings?,
|
|
14
|
+
duration: result.duration,
|
|
15
|
+
sections: result.sections.map { |s| serialize_analysis_section(s) }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if result.failed?
|
|
19
|
+
data[:error] = result.error
|
|
20
|
+
data[:error_backtrace] = result.error_backtrace if result.error_backtrace&.any?
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
data
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def serialize_analysis_section(section)
|
|
27
|
+
case section[:type]
|
|
28
|
+
when :heading
|
|
29
|
+
{ type: "heading", level: section[:level], text: section[:text] }
|
|
30
|
+
when :text
|
|
31
|
+
{ type: "text", content: markdown(section[:content]) }
|
|
32
|
+
# the *_html fields: the values as inline markdown with [[Kind/Name]] links, next to the raw values
|
|
33
|
+
when :message
|
|
34
|
+
{ type: "message", level: section[:level].to_s, message: section[:message],
|
|
35
|
+
message_html: analysis_html(section[:message]) }
|
|
36
|
+
when :table
|
|
37
|
+
{ type: "table", headers: section[:headers], rows: section[:rows],
|
|
38
|
+
rows_html: section[:rows].map { |row| row.map { |cell| analysis_html(cell) } } }
|
|
39
|
+
when :list
|
|
40
|
+
{ type: "list", items: section[:items], items_html: section[:items].map { |item| analysis_html(item) } }
|
|
41
|
+
when :code
|
|
42
|
+
{ type: "code", lang: section[:lang], content: section[:content] }
|
|
43
|
+
else
|
|
44
|
+
{ type: section[:type].to_s }
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# A value of a table cell, list item or message as html: HTML in it stays text (escaped first) except a line
|
|
49
|
+
# break (`<br>` or a newline, the usual way to break a line in a table cell), markdown and [[Kind/Name]] links are
|
|
50
|
+
# rendered; a value without markup is only escaped, so large tables stay cheap
|
|
51
|
+
def analysis_html(value)
|
|
52
|
+
escaped = Rack::Utils.escape_html(value.to_s).gsub(%r{<br\s*/?>}i, "<br>").gsub(/\r?\n/, "<br>")
|
|
53
|
+
escaped.match?(/[*_`\[{]|https?:/) ? inline_markdown(escaped) : escaped
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -11,8 +11,9 @@ module Archsight::Web::API; end
|
|
|
11
11
|
module Archsight::Web::API::Docs
|
|
12
12
|
extend Sinatra::Extension
|
|
13
13
|
|
|
14
|
+
# A page of its own, not the single page app: ReDoc must not get the app's CSS (Pico restyles every <code>)
|
|
14
15
|
get "/docs/api" do
|
|
15
|
-
|
|
16
|
+
send_file File.join(settings.public_folder, "vendor", "redoc", "api.html"), type: :html
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
# GET /api/v1/docs/resources/:filename — auto-generated resource docs
|
|
@@ -66,7 +66,8 @@ module Archsight::Web::API::JsonHelpers
|
|
|
66
66
|
description: klass.description,
|
|
67
67
|
layer: klass.layer,
|
|
68
68
|
icon: klass.icon,
|
|
69
|
-
instance_count: count
|
|
69
|
+
instance_count: count,
|
|
70
|
+
self_relations: Archsight::GraphvisRenderer.self_relations(klass).any?
|
|
70
71
|
}
|
|
71
72
|
end
|
|
72
73
|
kinds.sort_by { |k| k[:kind] }
|
|
@@ -92,6 +93,7 @@ module Archsight::Web::API::JsonHelpers
|
|
|
92
93
|
name: instance.name,
|
|
93
94
|
metadata: { annotations: render_annotations(instance.annotations, base: Archsight::Assets.base_dir_for(instance, resources_dir: Archsight.resources_dir), kind: kind) },
|
|
94
95
|
annotation_formats: Archsight::Resources[kind]&.annotation_formats(instance.annotations.keys) || {},
|
|
96
|
+
annotation_links: Archsight::Helpers::ResourceResolver.new(db).annotation_links(kind, instance.annotations),
|
|
95
97
|
spec: serialize_spec(instance.spec),
|
|
96
98
|
relations: extract_relations(instance),
|
|
97
99
|
references: extract_references(instance),
|
|
@@ -193,42 +195,6 @@ module Archsight::Web::API::JsonHelpers
|
|
|
193
195
|
end
|
|
194
196
|
end
|
|
195
197
|
|
|
196
|
-
def build_analysis_result(result)
|
|
197
|
-
data = {
|
|
198
|
-
name: result.name,
|
|
199
|
-
success: result.success?,
|
|
200
|
-
has_findings: result.has_findings?,
|
|
201
|
-
duration: result.duration,
|
|
202
|
-
sections: result.sections.map { |s| serialize_analysis_section(s) }
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if result.failed?
|
|
206
|
-
data[:error] = result.error
|
|
207
|
-
data[:error_backtrace] = result.error_backtrace if result.error_backtrace&.any?
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
data
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
def serialize_analysis_section(section)
|
|
214
|
-
case section[:type]
|
|
215
|
-
when :heading
|
|
216
|
-
{ type: "heading", level: section[:level], text: section[:text] }
|
|
217
|
-
when :text
|
|
218
|
-
{ type: "text", content: markdown(section[:content]) }
|
|
219
|
-
when :message
|
|
220
|
-
{ type: "message", level: section[:level].to_s, message: section[:message] }
|
|
221
|
-
when :table
|
|
222
|
-
{ type: "table", headers: section[:headers], rows: section[:rows] }
|
|
223
|
-
when :list
|
|
224
|
-
{ type: "list", items: section[:items] }
|
|
225
|
-
when :code
|
|
226
|
-
{ type: "code", lang: section[:lang], content: section[:content] }
|
|
227
|
-
else
|
|
228
|
-
{ type: section[:type].to_s }
|
|
229
|
-
end
|
|
230
|
-
end
|
|
231
|
-
|
|
232
198
|
def extract_references(instance)
|
|
233
199
|
references = {}
|
|
234
200
|
|
|
@@ -254,7 +254,7 @@ paths:
|
|
|
254
254
|
Returns one page with its metadata and its body rendered to HTML.
|
|
255
255
|
|
|
256
256
|
**Metadata** comes from the frontmatter: `title` (falls back to the name), `status`, `author` and
|
|
257
|
-
`owner` (`Name <email>`, split into `name` and `email`), `tags` and the `
|
|
257
|
+
`owner` (`Name <email>`, split into `name` and `email`), `tags` and the `links` (name and URL, e.g. `confluence`).
|
|
258
258
|
|
|
259
259
|
**`html`** is the markdown body rendered once per request:
|
|
260
260
|
- GitHub-flavoured markdown (tables, fenced code, task lists).
|
|
@@ -309,7 +309,7 @@ paths:
|
|
|
309
309
|
owner:
|
|
310
310
|
name: Jane Doe
|
|
311
311
|
email: jane.doe@example.com
|
|
312
|
-
|
|
312
|
+
links: {}
|
|
313
313
|
tags:
|
|
314
314
|
- howto
|
|
315
315
|
- wiki
|
|
@@ -623,12 +623,10 @@ paths:
|
|
|
623
623
|
type: object
|
|
624
624
|
properties:
|
|
625
625
|
html:
|
|
626
|
-
type: string
|
|
627
|
-
nullable: true
|
|
626
|
+
type: [string, "null"]
|
|
628
627
|
description: '`<figure class="asd-diagram">` with the SVG'
|
|
629
628
|
error:
|
|
630
|
-
type: string
|
|
631
|
-
nullable: true
|
|
629
|
+
type: [string, "null"]
|
|
632
630
|
'400':
|
|
633
631
|
description: Body is not JSON with a `source` string
|
|
634
632
|
content:
|
|
@@ -708,9 +706,11 @@ paths:
|
|
|
708
706
|
summary: Requirements of a selection of resources
|
|
709
707
|
description: |
|
|
710
708
|
The requirements that the resources selected by `of` realize (`implemented`), partially realize
|
|
711
|
-
(`partial`) or plan (`planned`), merged over all of them: one entry per requirement with the best status
|
|
712
|
-
the resources it comes from (`by
|
|
713
|
-
rendered HTML.
|
|
709
|
+
(`partial`) or plan (`planned`), merged over all of them: one entry per requirement, with the best status
|
|
710
|
+
any of the resources gives it and the resources it comes from (`by`, each with its own status). Sorted by
|
|
711
|
+
priority (must, should, may, requirements without a priority last), then name. `story` is rendered HTML.
|
|
712
|
+
`priority` and `status` filter the merged entries, so `status=partial` lists requirements whose best
|
|
713
|
+
status is partial.
|
|
714
714
|
operationId: getRequirements
|
|
715
715
|
tags:
|
|
716
716
|
- Search
|
|
@@ -725,14 +725,14 @@ paths:
|
|
|
725
725
|
- name: priority
|
|
726
726
|
in: query
|
|
727
727
|
required: false
|
|
728
|
-
description: Comma separated list, only requirements with one of these priorities
|
|
728
|
+
description: Comma separated list, only requirements with one of these priorities (must, should, may)
|
|
729
729
|
schema:
|
|
730
730
|
type: string
|
|
731
731
|
example: must,should
|
|
732
732
|
- name: status
|
|
733
733
|
in: query
|
|
734
734
|
required: false
|
|
735
|
-
description: Comma separated list, only requirements with one of these statuses
|
|
735
|
+
description: Comma separated list, only requirements with one of these statuses (implemented, partial, planned)
|
|
736
736
|
schema:
|
|
737
737
|
type: string
|
|
738
738
|
example: implemented,partial
|
|
@@ -743,33 +743,42 @@ paths:
|
|
|
743
743
|
application/json:
|
|
744
744
|
schema:
|
|
745
745
|
type: object
|
|
746
|
+
required: [query, total, query_time_ms, requirements]
|
|
746
747
|
properties:
|
|
747
748
|
query:
|
|
748
749
|
type: string
|
|
750
|
+
description: The `of` query as given
|
|
749
751
|
total:
|
|
750
752
|
type: integer
|
|
753
|
+
description: Number of requirements returned
|
|
751
754
|
query_time_ms:
|
|
752
755
|
type: number
|
|
753
756
|
requirements:
|
|
754
757
|
type: array
|
|
755
758
|
items:
|
|
756
759
|
type: object
|
|
760
|
+
required: [name, status, priority, story, by]
|
|
757
761
|
properties:
|
|
758
762
|
name:
|
|
759
763
|
type: string
|
|
764
|
+
description: Name of the MotivationRequirement
|
|
760
765
|
status:
|
|
761
766
|
type: string
|
|
762
767
|
enum: [implemented, partial, planned]
|
|
768
|
+
description: The best status among the resources in `by`
|
|
763
769
|
priority:
|
|
764
|
-
type: string
|
|
765
|
-
|
|
770
|
+
type: [string, "null"]
|
|
771
|
+
enum: [must, should, may, null]
|
|
772
|
+
description: Priority of the requirement, null if it has none
|
|
766
773
|
story:
|
|
767
|
-
type: string
|
|
768
|
-
|
|
774
|
+
type: [string, "null"]
|
|
775
|
+
description: The requirement's story as rendered HTML, null if it has none
|
|
769
776
|
by:
|
|
770
777
|
type: array
|
|
778
|
+
description: The selected resources that realize, partially realize or plan the requirement, best status first
|
|
771
779
|
items:
|
|
772
780
|
type: object
|
|
781
|
+
required: [kind, name, status]
|
|
773
782
|
properties:
|
|
774
783
|
kind:
|
|
775
784
|
type: string
|
|
@@ -778,12 +787,118 @@ paths:
|
|
|
778
787
|
status:
|
|
779
788
|
type: string
|
|
780
789
|
enum: [implemented, partial, planned]
|
|
790
|
+
description: The status this resource gives the requirement
|
|
791
|
+
example:
|
|
792
|
+
query: 'ApplicationService: name =~ "Backup"'
|
|
793
|
+
total: 1
|
|
794
|
+
query_time_ms: 1.4
|
|
795
|
+
requirements:
|
|
796
|
+
- name: "Requirement:Restore"
|
|
797
|
+
status: partial
|
|
798
|
+
priority: must
|
|
799
|
+
story: "<p>As an operator I can restore a backup.</p>"
|
|
800
|
+
by:
|
|
801
|
+
- kind: ApplicationService
|
|
802
|
+
name: Backup
|
|
803
|
+
status: partial
|
|
781
804
|
'400':
|
|
782
|
-
description:
|
|
805
|
+
description: |
|
|
806
|
+
`of` is missing or `priority` or `status` holds an unknown value (`BadRequest`), or `of` is not a valid
|
|
807
|
+
query (`QueryError`, which also returns the query)
|
|
783
808
|
content:
|
|
784
809
|
application/json:
|
|
785
810
|
schema:
|
|
786
|
-
|
|
811
|
+
oneOf:
|
|
812
|
+
- $ref: '#/components/schemas/Error'
|
|
813
|
+
- $ref: '#/components/schemas/QueryError'
|
|
814
|
+
|
|
815
|
+
/api/v1/openapi.yaml:
|
|
816
|
+
get:
|
|
817
|
+
summary: This OpenAPI document
|
|
818
|
+
description: |
|
|
819
|
+
The OpenAPI 3.1 description of this API. The fixed endpoints are written by hand; the schema of every kind
|
|
820
|
+
(its annotations with type, enum and description, its `spec` and its relations), the list of kinds and the
|
|
821
|
+
instance detail are generated from the model, so they always describe the kinds this server has.
|
|
822
|
+
operationId: getOpenApi
|
|
823
|
+
tags:
|
|
824
|
+
- Operations
|
|
825
|
+
responses:
|
|
826
|
+
'200':
|
|
827
|
+
description: The OpenAPI document
|
|
828
|
+
content:
|
|
829
|
+
text/yaml:
|
|
830
|
+
schema:
|
|
831
|
+
type: string
|
|
832
|
+
|
|
833
|
+
/maintenance/restart:
|
|
834
|
+
post:
|
|
835
|
+
summary: Restart the server
|
|
836
|
+
description: |
|
|
837
|
+
Stops the server so that its supervisor (for example a Kubernetes Deployment) starts it again with fresh
|
|
838
|
+
data. Only available when the server was started with `--enable-restart` (or
|
|
839
|
+
`ARCHSIGHT_RESTART_ENABLED=true`); otherwise it answers 404. When a restart token is configured it must be
|
|
840
|
+
sent in the `X-Restart-Token` header.
|
|
841
|
+
operationId: restart
|
|
842
|
+
tags:
|
|
843
|
+
- Operations
|
|
844
|
+
parameters:
|
|
845
|
+
- name: X-Restart-Token
|
|
846
|
+
in: header
|
|
847
|
+
required: false
|
|
848
|
+
description: The configured restart token (required when the server has one)
|
|
849
|
+
schema:
|
|
850
|
+
type: string
|
|
851
|
+
responses:
|
|
852
|
+
'200':
|
|
853
|
+
description: The server shuts down
|
|
854
|
+
content:
|
|
855
|
+
application/json:
|
|
856
|
+
schema:
|
|
857
|
+
type: object
|
|
858
|
+
required: [ok, message]
|
|
859
|
+
properties:
|
|
860
|
+
ok:
|
|
861
|
+
type: boolean
|
|
862
|
+
message:
|
|
863
|
+
type: string
|
|
864
|
+
example:
|
|
865
|
+
ok: true
|
|
866
|
+
message: Server shutting down
|
|
867
|
+
'401':
|
|
868
|
+
description: The restart token is missing or wrong
|
|
869
|
+
content:
|
|
870
|
+
text/html:
|
|
871
|
+
schema:
|
|
872
|
+
type: string
|
|
873
|
+
'404':
|
|
874
|
+
description: The restart endpoint is not enabled
|
|
875
|
+
content:
|
|
876
|
+
text/html:
|
|
877
|
+
schema:
|
|
878
|
+
type: string
|
|
879
|
+
|
|
880
|
+
/kinds/{kind}/dot:
|
|
881
|
+
get:
|
|
882
|
+
summary: Get the graph of a kind as DOT
|
|
883
|
+
description: The GraphViz DOT graph of the resources of a kind and the relations between them.
|
|
884
|
+
operationId: getKindDot
|
|
885
|
+
tags:
|
|
886
|
+
- Graph
|
|
887
|
+
parameters:
|
|
888
|
+
- $ref: '#/components/parameters/kind'
|
|
889
|
+
responses:
|
|
890
|
+
'200':
|
|
891
|
+
description: GraphViz DOT source
|
|
892
|
+
content:
|
|
893
|
+
text/plain:
|
|
894
|
+
schema:
|
|
895
|
+
type: string
|
|
896
|
+
'404':
|
|
897
|
+
description: Unknown kind
|
|
898
|
+
content:
|
|
899
|
+
text/plain:
|
|
900
|
+
schema:
|
|
901
|
+
type: string
|
|
787
902
|
|
|
788
903
|
/dot:
|
|
789
904
|
get:
|
|
@@ -1343,13 +1458,11 @@ components:
|
|
|
1343
1458
|
items:
|
|
1344
1459
|
type: string
|
|
1345
1460
|
format:
|
|
1346
|
-
type: string
|
|
1347
|
-
nullable: true
|
|
1461
|
+
type: [string, "null"]
|
|
1348
1462
|
description: Rendering hint of the annotation (tag_word, tag_list, markdown, link, ...)
|
|
1349
1463
|
example: tag_word
|
|
1350
1464
|
type:
|
|
1351
|
-
type: string
|
|
1352
|
-
nullable: true
|
|
1465
|
+
type: [string, "null"]
|
|
1353
1466
|
description: Short name of the value type when the annotation declares one (Integer, Float, Time, Person, ...)
|
|
1354
1467
|
example: Integer
|
|
1355
1468
|
|
|
@@ -1489,7 +1602,7 @@ components:
|
|
|
1489
1602
|
description: Whether the analysis executed successfully
|
|
1490
1603
|
has_findings:
|
|
1491
1604
|
type: boolean
|
|
1492
|
-
description: Whether the
|
|
1605
|
+
description: Whether the script produced any output (tables, lists, text, ...). Output is not a problem; errors and warnings the script reports are message sections
|
|
1493
1606
|
duration:
|
|
1494
1607
|
type: number
|
|
1495
1608
|
format: float
|
|
@@ -1684,26 +1797,22 @@ components:
|
|
|
1684
1797
|
type: object
|
|
1685
1798
|
properties:
|
|
1686
1799
|
yaml:
|
|
1687
|
-
type: string
|
|
1688
|
-
nullable: true
|
|
1800
|
+
type: [string, "null"]
|
|
1689
1801
|
description: Generated source text, YAML or (for pages) markdown with frontmatter (null if validation failed)
|
|
1690
1802
|
format:
|
|
1691
1803
|
type: string
|
|
1692
1804
|
enum: [yaml, markdown]
|
|
1693
1805
|
description: Format of `yaml`. Pages (kind Page) are stored as markdown files and replaced as a whole file
|
|
1694
1806
|
errors:
|
|
1695
|
-
type: array
|
|
1696
|
-
nullable: true
|
|
1807
|
+
type: [array, "null"]
|
|
1697
1808
|
items:
|
|
1698
1809
|
type: string
|
|
1699
1810
|
description: Validation errors (null if valid)
|
|
1700
1811
|
path_ref:
|
|
1701
|
-
type: string
|
|
1702
|
-
nullable: true
|
|
1812
|
+
type: [string, "null"]
|
|
1703
1813
|
description: "File path reference (edit mode only, e.g., path/file.yaml:5; just the file for markdown pages)"
|
|
1704
1814
|
content_hash:
|
|
1705
|
-
type: string
|
|
1706
|
-
nullable: true
|
|
1815
|
+
type: [string, "null"]
|
|
1707
1816
|
description: Content hash (edit mode only, for optimistic locking)
|
|
1708
1817
|
|
|
1709
1818
|
SaveRequest:
|
|
@@ -1869,7 +1978,7 @@ components:
|
|
|
1869
1978
|
|
|
1870
1979
|
PageResponse:
|
|
1871
1980
|
type: object
|
|
1872
|
-
required: [name, title, status, author, owner, created, updated, properties,
|
|
1981
|
+
required: [name, title, status, author, owner, created, updated, properties, links, tags, toc, breadcrumb, html, backlinks]
|
|
1873
1982
|
properties:
|
|
1874
1983
|
name:
|
|
1875
1984
|
type: string
|
|
@@ -1909,10 +2018,12 @@ components:
|
|
|
1909
2018
|
html:
|
|
1910
2019
|
type: string
|
|
1911
2020
|
description: The value rendered as inline markdown (links, emphasis, `{macros}`, `[[wiki links]]`), without a paragraph around it
|
|
1912
|
-
|
|
1913
|
-
type:
|
|
1914
|
-
|
|
1915
|
-
|
|
2021
|
+
links:
|
|
2022
|
+
type: object
|
|
2023
|
+
description: Links of the page to other systems, by name (`confluence`, `jira`, ...)
|
|
2024
|
+
additionalProperties:
|
|
2025
|
+
type: string
|
|
2026
|
+
format: uri
|
|
1916
2027
|
tags:
|
|
1917
2028
|
type: array
|
|
1918
2029
|
items:
|
|
@@ -41,7 +41,7 @@ module Archsight::Web::API::PageHelpers
|
|
|
41
41
|
created: annotations["page/created"],
|
|
42
42
|
updated: annotations["page/updated"],
|
|
43
43
|
properties: page.properties.map { |key, value| { key: key, value: value, html: inline_markdown(value, page) } },
|
|
44
|
-
|
|
44
|
+
links: annotations.select { |key, _| key.start_with?("link/") }.transform_keys { |key| key.delete_prefix("link/") },
|
|
45
45
|
tags: Archsight::Resources::Page.annotation_matching("page/tags")&.value_for(page) || [],
|
|
46
46
|
toc: annotations["page/toc"] == "yes" ? Archsight::PageTree.toc(body) : [],
|
|
47
47
|
breadcrumb: tree.breadcrumb(page),
|
|
@@ -50,13 +50,6 @@ module Archsight::Web::API::PageHelpers
|
|
|
50
50
|
}
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
-
# A short text (a page property) rendered as inline markdown: links, emphasis, `{macros}`, [[wiki links]], without the
|
|
54
|
-
# paragraph around it
|
|
55
|
-
def inline_markdown(text, page)
|
|
56
|
-
html = markdown(text.to_s, base: Archsight::Assets.base_dir_for(page, resources_dir: Archsight.resources_dir), page: page)
|
|
57
|
-
html.strip.sub(%r{\A<p>(.*)</p>\z}m, '\1')
|
|
58
|
-
end
|
|
59
|
-
|
|
60
53
|
# The header already shows the title, so a leading "# Title" that repeats it is dropped
|
|
61
54
|
# (Confluence exports and hand-written pages usually start with one).
|
|
62
55
|
def strip_duplicate_title(body, page)
|
|
@@ -5,7 +5,9 @@ require "sinatra/extension"
|
|
|
5
5
|
require_relative "json_helpers"
|
|
6
6
|
require_relative "page_helpers"
|
|
7
7
|
require_relative "requirements_helpers"
|
|
8
|
+
require_relative "analysis_helpers"
|
|
8
9
|
require_relative "../../assets"
|
|
10
|
+
require_relative "../../openapi"
|
|
9
11
|
|
|
10
12
|
module Archsight; end
|
|
11
13
|
module Archsight::Web; end
|
|
@@ -18,6 +20,7 @@ module Archsight::Web::API::Routes
|
|
|
18
20
|
helpers Archsight::Web::API::JsonHelpers
|
|
19
21
|
helpers Archsight::Web::API::PageHelpers
|
|
20
22
|
helpers Archsight::Web::API::RequirementsHelpers
|
|
23
|
+
helpers Archsight::Web::API::AnalysisHelpers
|
|
21
24
|
|
|
22
25
|
# Rendering is CPU work, previews are typed, not pasted
|
|
23
26
|
MAX_DIAGRAM_SOURCE = 100_000
|
|
@@ -67,10 +70,13 @@ module Archsight::Web::API::Routes
|
|
|
67
70
|
klass = Archsight::Resources[kind]
|
|
68
71
|
json_error("Kind '#{kind}' not found", status: 404, error_type: "NotFound") unless klass
|
|
69
72
|
|
|
70
|
-
|
|
73
|
+
# an alias finds the one resource that has it; the response carries the real name
|
|
74
|
+
instance = db.instance_by_kind(kind, name) || db.instance_by_alias(kind, name)
|
|
71
75
|
json_error("Instance '#{name}' not found", status: 404, error_type: "NotFound") unless instance
|
|
72
76
|
|
|
73
|
-
|
|
77
|
+
# graph_layers: the layers its dependency graph follows when the page opens
|
|
78
|
+
json_response(build_instance_response(kind, instance)
|
|
79
|
+
.merge(graph_layers: Archsight::GraphvisRenderer.default_graph_layers(instance.class.layer)))
|
|
74
80
|
end
|
|
75
81
|
|
|
76
82
|
# GET /api/v1/pages - Page tree built from PageMenu resources, page tags and filters and the home page
|
|
@@ -215,8 +221,7 @@ module Archsight::Web::API::Routes
|
|
|
215
221
|
# GET /api/v1/openapi.yaml - OpenAPI specification
|
|
216
222
|
get "/api/v1/openapi.yaml" do
|
|
217
223
|
content_type "text/yaml"
|
|
218
|
-
|
|
219
|
-
File.read(spec_path)
|
|
224
|
+
Archsight::OpenAPI.document.to_yaml
|
|
220
225
|
end
|
|
221
226
|
|
|
222
227
|
# Convenience aliases with .json suffix
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "sinatra/base"
|
|
4
|
-
|
|
4
|
+
require_relative "../markdown"
|
|
5
5
|
require "erb"
|
|
6
6
|
require "fast_mcp"
|
|
7
7
|
|
|
@@ -25,17 +25,25 @@ class Archsight::Web::Application < Sinatra::Base
|
|
|
25
25
|
attr_accessor :db
|
|
26
26
|
|
|
27
27
|
def database
|
|
28
|
-
@database ||= Archsight::Database.new(Archsight.resources_dir).tap(&:reload!)
|
|
28
|
+
@database ||= Archsight::Database.new(Archsight.resources_dir).tap(&:reload!).tap { |db| load_import_handlers(db) }
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def reload!
|
|
32
32
|
start = Time.new
|
|
33
33
|
puts "== Reloading ..." if database.verbose
|
|
34
34
|
database.reload!
|
|
35
|
+
load_import_handlers(database)
|
|
35
36
|
dur = (Time.new - start) * 1000
|
|
36
37
|
puts format("== done %0.2f ms", dur) if database.verbose
|
|
37
38
|
end
|
|
38
39
|
|
|
40
|
+
# The import handlers, built-in and of the resources repository (import/handlerPath), so the editor knows the
|
|
41
|
+
# same handler names as `archsight lint`. A file that does not load is reported, the server keeps running.
|
|
42
|
+
def load_import_handlers(db)
|
|
43
|
+
require "archsight/import"
|
|
44
|
+
Archsight::Import::HandlerLoader.load(db).each { |problem| warn "Import handler: #{problem}" }
|
|
45
|
+
end
|
|
46
|
+
|
|
39
47
|
# Configure application for the given environment
|
|
40
48
|
# @param env [Symbol] :development or :production
|
|
41
49
|
# @param logging [Boolean, nil] Override default logging setting
|
|
@@ -135,13 +143,22 @@ class Archsight::Web::Application < Sinatra::Base
|
|
|
135
143
|
settings.environment == :development
|
|
136
144
|
end
|
|
137
145
|
|
|
146
|
+
# A short text (a page property, an analysis table cell) rendered as inline markdown: links, emphasis,
|
|
147
|
+
# `{macros}`, [[wiki links]], without the paragraph around it
|
|
148
|
+
# @param page [Archsight::Resources::Page, nil] the page the text belongs to, for its relative images and macros
|
|
149
|
+
def inline_markdown(text, page = nil)
|
|
150
|
+
base = page && Archsight::Assets.base_dir_for(page, resources_dir: Archsight.resources_dir)
|
|
151
|
+
html = markdown(text.to_s, base: base, page: page)
|
|
152
|
+
html.strip.sub(%r{\A<p>(.*)</p>\z}m, '\1')
|
|
153
|
+
end
|
|
154
|
+
|
|
138
155
|
# Render markdown to HTML with optional URL resolution for repository content
|
|
139
156
|
# @param data [String] Markdown content
|
|
140
157
|
# @param git_url [String, nil] Git URL for resolving relative paths (e.g., for README images)
|
|
141
158
|
# @param base [String, nil] directory of the file the markdown comes from, relative to the resources
|
|
142
159
|
# directory ("" for the root): its relative images become assets (see Archsight::Assets)
|
|
143
160
|
def markdown(data, git_url: nil, base: nil, page: nil)
|
|
144
|
-
html =
|
|
161
|
+
html = Archsight::Markdown.document(data).to_html
|
|
145
162
|
html = Archsight::Helpers::AssetImages.rewrite(html, base_dir: base, resources_dir: Archsight.resources_dir) if base
|
|
146
163
|
# ```asd blocks become placeholders until the text passes below are done (see DiagramBlocks)
|
|
147
164
|
html, diagrams = Archsight::Helpers::DiagramBlocks.extract(html, resolver: Archsight::Helpers::ResourceResolver.new(db))
|
|
@@ -282,14 +299,33 @@ class Archsight::Web::Application < Sinatra::Base
|
|
|
282
299
|
serve_vue
|
|
283
300
|
end
|
|
284
301
|
|
|
302
|
+
# The resources of a kind and the relations between them (see GraphvisRenderer#create_graph_kind)
|
|
303
|
+
get "/kinds/:kind/dot" do
|
|
304
|
+
halt 404, "kind #{params["kind"]} unknown" unless Archsight::Resources[params["kind"]]
|
|
305
|
+
|
|
306
|
+
content_type "text/plain"
|
|
307
|
+
create_graph_kind(db, params["kind"])
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# An alias in the URL redirects to the resource's real name (`:` stays readable, the rest is escaped)
|
|
285
311
|
get "/kinds/:kind/instances/:instance" do
|
|
312
|
+
kind = params["kind"]
|
|
313
|
+
name = params["instance"]
|
|
314
|
+
if Archsight::Resources[kind] && !db.instance_by_kind(kind, name) && (instance = db.instance_by_alias(kind, name))
|
|
315
|
+
redirect "/kinds/#{kind}/instances/#{ERB::Util.url_encode(instance.name).gsub("%3A", ":")}"
|
|
316
|
+
end
|
|
317
|
+
|
|
286
318
|
serve_vue
|
|
287
319
|
end
|
|
288
320
|
|
|
321
|
+
# `depth`: steps from the instance (a positive number; missing or `all`: every step), `layers`: the layers it
|
|
322
|
+
# follows, comma separated (missing or none known: every layer)
|
|
289
323
|
get "/kinds/:kind/instances/:instance/dot" do
|
|
290
324
|
@kind = params["kind"]
|
|
291
325
|
@instance = params["instance"]
|
|
326
|
+
depth = params["depth"].to_s.match?(/\A[1-9]\d*\z/) ? params["depth"].to_i : nil
|
|
327
|
+
layers = params["layers"].to_s.split(",").map(&:strip) & Archsight::Resources::LAYERS
|
|
292
328
|
content_type "text/plain"
|
|
293
|
-
create_graph_one(db, @kind, @instance)
|
|
329
|
+
create_graph_one(db, @kind, @instance, max_depth: depth, layers: layers.empty? ? nil : layers)
|
|
294
330
|
end
|
|
295
331
|
end
|
|
@@ -57,7 +57,8 @@ module Archsight
|
|
|
57
57
|
data = build_form_metadata(kind, klass)
|
|
58
58
|
data[:mode] = "edit"
|
|
59
59
|
data[:name] = instance.name
|
|
60
|
-
|
|
60
|
+
# defaults are not in the file, a save leaves them out
|
|
61
|
+
data[:annotations] = instance.annotations.reject { |key, _| instance.defaulted?(key) }
|
|
61
62
|
data[:relations] = extract_instance_relations(instance)
|
|
62
63
|
data[:path_ref] = source_ref(instance)
|
|
63
64
|
data[:content_hash] = source_content_hash(instance)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015-present, Rebilly, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.5.4
|