archsight 0.1.5 → 0.2.0
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/Dockerfile +5 -4
- data/README.md +17 -65
- data/chart/archsight/README.md +1 -158
- data/docs/architecture.md +39 -0
- data/docs/docker.md +49 -0
- data/{lib/archsight/web/doc → docs}/index.md.erb +3 -1
- data/docs/kubernetes.md +149 -0
- data/docs/licenses.md +307 -0
- data/lib/archsight/cli.rb +1 -1
- data/lib/archsight/graph.rb +1 -51
- data/lib/archsight/helpers.rb +0 -20
- data/lib/archsight/import/handlers/github.rb +3 -1
- data/lib/archsight/import/handlers/gitlab.rb +15 -5
- data/lib/archsight/import/handlers/repository.rb +53 -5
- data/lib/archsight/import/handlers/rest_api.rb +13 -1
- data/lib/archsight/import/license_analyzer.rb +650 -0
- data/lib/archsight/linter.rb +1 -1
- data/lib/archsight/mcp/base.rb +11 -0
- data/lib/archsight/renderer.rb +4 -4
- data/lib/archsight/resources/business_actor.rb +17 -2
- data/lib/archsight/resources/technology_artifact.rb +48 -0
- data/lib/archsight/version.rb +1 -1
- data/lib/archsight/web/api/docs.rb +37 -2
- data/lib/archsight/web/api/json_helpers.rb +79 -13
- data/lib/archsight/web/api/openapi/spec.yaml +699 -0
- data/lib/archsight/web/api/routes.rb +23 -0
- data/lib/archsight/web/application.rb +40 -128
- data/lib/archsight/web/editor/helpers.rb +150 -0
- data/lib/archsight/web/editor/routes.rb +85 -212
- data/lib/archsight/web/public/vue/ApiDocsPage-B1RqTNqh.js +1 -0
- data/lib/archsight/web/public/vue/ApiDocsPage-DhNTOH4o.css +1 -0
- data/lib/archsight/web/public/vue/DocPage-DzwBgBd4.js +1 -0
- data/lib/archsight/web/public/vue/EditorPage-D_miHSv4.js +34 -0
- data/lib/archsight/web/public/vue/EditorPage-Dq0MuTnp.css +1 -0
- data/lib/archsight/web/public/vue/ErrorPage-CQQtPey3.js +2 -0
- data/lib/archsight/web/public/vue/ErrorPage-CwPT3JUr.css +1 -0
- data/lib/archsight/web/public/vue/GraphView-DRcIqAiR.css +1 -0
- data/lib/archsight/web/public/vue/GraphView-T9jFH_qg.js +1 -0
- data/lib/archsight/web/public/vue/InstanceRouter-1Sm-CRhf.js +2 -0
- data/lib/archsight/web/public/vue/InstanceRouter-BJkDRXZY.css +1 -0
- data/lib/archsight/web/public/vue/KindList-JA_L_-Cz.js +1 -0
- data/lib/archsight/web/public/vue/ResourceList-8iqavWdg.js +1 -0
- data/lib/archsight/web/public/vue/ResourceList-DP-z-j71.css +1 -0
- data/lib/archsight/web/public/vue/SearchResults-BGHbg48-.css +1 -0
- data/lib/archsight/web/public/vue/SearchResults-BdgFeHcm.js +1 -0
- data/lib/archsight/web/public/vue/_basePickBy-CVgieyx-.js +1 -0
- data/lib/archsight/web/public/vue/_baseUniq-BNfrOSaP.js +1 -0
- data/lib/archsight/web/public/vue/architectureDiagram-VXUJARFQ-CJXNpTr5.js +36 -0
- data/lib/archsight/web/public/vue/blockDiagram-VD42YOAC-B5488Hes.js +122 -0
- data/lib/archsight/web/public/vue/c4Diagram-YG6GDRKO-eYY3hprM.js +10 -0
- data/lib/archsight/web/public/vue/chunk-4BX2VUAB-ZoXeL4D1.js +1 -0
- data/lib/archsight/web/public/vue/chunk-55IACEB6-rNtQYnu_.js +1 -0
- data/lib/archsight/web/public/vue/chunk-B4BG7PRW-DolAeVV9.js +165 -0
- data/lib/archsight/web/public/vue/chunk-DI55MBZ5-DnN0f_hj.js +220 -0
- data/lib/archsight/web/public/vue/chunk-FMBD7UC4-BQWOCMuR.js +15 -0
- data/lib/archsight/web/public/vue/chunk-QN33PNHL-DId301Kb.js +1 -0
- data/lib/archsight/web/public/vue/chunk-QZHKN3VN-xbY0NLgv.js +1 -0
- data/lib/archsight/web/public/vue/chunk-TZMSLE5B-CgF9_37b.js +1 -0
- data/lib/archsight/web/public/vue/classDiagram-2ON5EDUG-jGlvI-Za.js +1 -0
- data/lib/archsight/web/public/vue/classDiagram-v2-WZHVMYZB-jGlvI-Za.js +1 -0
- data/lib/archsight/web/public/vue/clone-6iRPe1-W.js +1 -0
- data/lib/archsight/web/public/vue/cose-bilkent-S5V4N54A-CB9Zfu50.js +1 -0
- data/lib/archsight/web/public/vue/cytoscape.esm-5J0xJHOV.js +321 -0
- data/lib/archsight/web/public/vue/dagre-6UL2VRFP-BqkmE-LI.js +4 -0
- data/lib/archsight/web/public/vue/diagram-PSM6KHXK-CKBfqtw3.js +24 -0
- data/lib/archsight/web/public/vue/diagram-QEK2KX5R-B78rOlvK.js +43 -0
- data/lib/archsight/web/public/vue/diagram-S2PKOQOG-BlXC6Cia.js +24 -0
- data/lib/archsight/web/public/vue/erDiagram-Q2GNP2WA-BnliyziJ.js +60 -0
- data/lib/archsight/web/public/vue/flowDiagram-NV44I4VS-wuqPowTd.js +162 -0
- data/lib/archsight/web/public/vue/ganttDiagram-JELNMOA3-GSffAIH3.js +267 -0
- data/lib/archsight/web/public/vue/gitGraphDiagram-V2S2FVAM-OA7VyugW.js +65 -0
- data/lib/archsight/web/public/vue/graph-BXHAtA0S.js +1 -0
- data/lib/archsight/web/public/vue/graphviz-CJms5bxZ.js +13 -0
- data/lib/archsight/web/public/vue/index-DsEsN0_K.js +2 -0
- data/lib/archsight/web/public/vue/index-Tiu4C-Sb.css +1 -0
- data/lib/archsight/web/public/vue/infoDiagram-HS3SLOUP-nlVe2qgv.js +2 -0
- data/lib/archsight/web/public/vue/journeyDiagram-XKPGCS4Q-CtTIcKwf.js +139 -0
- data/lib/archsight/web/public/vue/kanban-definition-3W4ZIXB7-837KX0sW.js +89 -0
- data/lib/archsight/web/public/vue/katex-C-M49wc6.js +261 -0
- data/lib/archsight/web/public/vue/layout-DtE0QdL6.js +1 -0
- data/lib/archsight/web/public/vue/mermaid-DpPHPFQh.js +250 -0
- data/lib/archsight/web/public/vue/mindmap-definition-VGOIOE7T-9gLF2AoY.js +68 -0
- data/lib/archsight/web/public/vue/pieDiagram-ADFJNKIX-CyCNgw3u.js +30 -0
- data/lib/archsight/web/public/vue/quadrantDiagram-AYHSOK5B-CkPh8g02.js +7 -0
- data/lib/archsight/web/public/vue/requirementDiagram-UZGBJVZJ-Dkt6OSlY.js +64 -0
- data/lib/archsight/web/public/vue/sankeyDiagram-TZEHDZUN-BqprTk8x.js +10 -0
- data/lib/archsight/web/public/vue/sequenceDiagram-WL72ISMW-CTmTe1FQ.js +145 -0
- data/lib/archsight/web/public/vue/stateDiagram-FKZM4ZOC-CphqmkEU.js +1 -0
- data/lib/archsight/web/public/vue/stateDiagram-v2-4FDKWEC3-CxaDW5sW.js +1 -0
- data/lib/archsight/web/public/vue/timeline-definition-IT6M3QCI-CSQUZkyE.js +61 -0
- data/lib/archsight/web/public/vue/treemap-GDKQZRPO-DTojm7Yr.js +162 -0
- data/lib/archsight/web/public/{css/graph.css → vue/useGraphviz-A5s4h76R.js} +2 -1
- data/lib/archsight/web/public/vue/useHighlight-C6Kb5G3l.js +10 -0
- data/lib/archsight/web/public/vue/useMermaid-DqxTrLRB.js +1 -0
- data/lib/archsight/web/public/vue/usePanZoom-BybZ_rfh.js +11 -0
- data/lib/archsight/web/public/vue/xychartDiagram-PRI3JC2R-B1ZJZtDC.js +7 -0
- data/lib/archsight/web/public/vue.html +15 -0
- data/media/artifact.jpg +0 -0
- data/media/service.jpg +0 -0
- metadata +86 -84
- data/lib/archsight/web/public/css/artifact.css +0 -995
- data/lib/archsight/web/public/css/base.css +0 -201
- data/lib/archsight/web/public/css/editor.css +0 -863
- data/lib/archsight/web/public/css/highlight.min.css +0 -10
- data/lib/archsight/web/public/css/iconoir.css +0 -22
- data/lib/archsight/web/public/css/instance.css +0 -824
- data/lib/archsight/web/public/css/layout.css +0 -421
- data/lib/archsight/web/public/css/mermaid-layers.css +0 -188
- data/lib/archsight/web/public/css/pico.min.css +0 -4
- data/lib/archsight/web/public/img/archimate.png +0 -0
- data/lib/archsight/web/public/img/togaf-high-level.png +0 -0
- data/lib/archsight/web/public/js/editor.js +0 -421
- data/lib/archsight/web/public/js/graph-zoom.js +0 -18
- data/lib/archsight/web/public/js/highlight.min.js +0 -3899
- data/lib/archsight/web/public/js/htmx.min.js +0 -1
- data/lib/archsight/web/public/js/lexical-editor.js +0 -308
- data/lib/archsight/web/public/js/mermaid-init.js +0 -88
- data/lib/archsight/web/public/js/mermaid.min.js +0 -2811
- data/lib/archsight/web/public/js/sparkline.js +0 -42
- data/lib/archsight/web/public/js/svg-pan-zoom.min.js +0 -3
- data/lib/archsight/web/public/js/svg-zoom-controls.js +0 -93
- data/lib/archsight/web/views/api_docs.erb +0 -19
- data/lib/archsight/web/views/index.haml +0 -12
- data/lib/archsight/web/views/partials/artifact/_activity.haml +0 -55
- data/lib/archsight/web/views/partials/artifact/_agentic.haml +0 -25
- data/lib/archsight/web/views/partials/artifact/_deployment.haml +0 -29
- data/lib/archsight/web/views/partials/artifact/_git_info.haml +0 -16
- data/lib/archsight/web/views/partials/artifact/_language_stats.haml +0 -53
- data/lib/archsight/web/views/partials/artifact/_links.haml +0 -24
- data/lib/archsight/web/views/partials/artifact/_project_estimate.haml +0 -32
- data/lib/archsight/web/views/partials/artifact/_repositories.haml +0 -55
- data/lib/archsight/web/views/partials/artifact/_team.haml +0 -83
- data/lib/archsight/web/views/partials/artifact/_workflow.haml +0 -69
- data/lib/archsight/web/views/partials/components/_activity.haml +0 -37
- data/lib/archsight/web/views/partials/components/_git.haml +0 -17
- data/lib/archsight/web/views/partials/components/_jira.haml +0 -18
- data/lib/archsight/web/views/partials/components/_languages.haml +0 -29
- data/lib/archsight/web/views/partials/components/_owner.haml +0 -15
- data/lib/archsight/web/views/partials/components/_repositories.haml +0 -37
- data/lib/archsight/web/views/partials/components/_status.haml +0 -23
- data/lib/archsight/web/views/partials/editor/_field.haml +0 -80
- data/lib/archsight/web/views/partials/editor/_form.haml +0 -131
- data/lib/archsight/web/views/partials/editor/_relations.haml +0 -39
- data/lib/archsight/web/views/partials/editor/_yaml_output.haml +0 -33
- data/lib/archsight/web/views/partials/instance/_analysis_detail.haml +0 -67
- data/lib/archsight/web/views/partials/instance/_analysis_result.haml +0 -64
- data/lib/archsight/web/views/partials/instance/_detail.haml +0 -107
- data/lib/archsight/web/views/partials/instance/_graph.haml +0 -6
- data/lib/archsight/web/views/partials/instance/_import_detail.haml +0 -87
- data/lib/archsight/web/views/partials/instance/_list.haml +0 -84
- data/lib/archsight/web/views/partials/instance/_relations.haml +0 -43
- data/lib/archsight/web/views/partials/instance/_requirements.haml +0 -41
- data/lib/archsight/web/views/partials/instance/_view_detail.haml +0 -57
- data/lib/archsight/web/views/partials/layout/_content.haml +0 -50
- data/lib/archsight/web/views/partials/layout/_error.haml +0 -22
- data/lib/archsight/web/views/partials/layout/_head.haml +0 -26
- data/lib/archsight/web/views/partials/layout/_navigation.haml +0 -21
- data/lib/archsight/web/views/partials/layout/_sidebar.haml +0 -27
- data/lib/archsight/web/views/search.haml +0 -53
- /data/{lib/archsight/web/doc → docs}/archimate.md +0 -0
- /data/{lib/archsight/web/doc → docs}/computed_annotations.md +0 -0
- /data/{lib/archsight/web/doc → docs}/icons.md +0 -0
- /data/{lib/archsight/web/doc → docs}/import.md +0 -0
- /data/{lib/archsight/web/doc → docs}/modeling.md +0 -0
- /data/{lib/archsight/web/doc → docs}/search.md +0 -0
- /data/{lib/archsight/web/doc → docs}/togaf.md +0 -0
- /data/{lib/archsight/web/doc → docs}/tool.md +0 -0
|
@@ -4,6 +4,7 @@ require "sinatra/base"
|
|
|
4
4
|
require "sinatra/extension"
|
|
5
5
|
require_relative "../../editor"
|
|
6
6
|
require_relative "form_builder"
|
|
7
|
+
require_relative "helpers"
|
|
7
8
|
|
|
8
9
|
module Archsight
|
|
9
10
|
module Web
|
|
@@ -12,220 +13,124 @@ module Archsight
|
|
|
12
13
|
module Routes
|
|
13
14
|
extend Sinatra::Extension
|
|
14
15
|
|
|
15
|
-
helpers
|
|
16
|
-
# Get form fields for a resource kind
|
|
17
|
-
def editor_fields(kind)
|
|
18
|
-
FormBuilder.fields_for(kind)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# Get relation verbs for a resource kind
|
|
22
|
-
def relation_verbs(kind)
|
|
23
|
-
Archsight::Editor.relation_verbs(kind)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# Get available relations for a resource kind
|
|
27
|
-
def available_relations(kind)
|
|
28
|
-
Archsight::Editor.available_relations(kind)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Extract annotations from form params
|
|
32
|
-
def extract_annotations(params)
|
|
33
|
-
annotations = params["annotations"] || {}
|
|
34
|
-
annotations.transform_values { |v| v.is_a?(String) ? v.strip : v }
|
|
35
|
-
end
|
|
16
|
+
helpers Archsight::Web::Editor::Helpers
|
|
36
17
|
|
|
37
|
-
|
|
38
|
-
# Relations come in as arrays: verb[], kind[], name[]
|
|
39
|
-
def parse_form_relations(params)
|
|
40
|
-
relations = []
|
|
41
|
-
relation_data = params["relations"] || []
|
|
18
|
+
# --- HTML routes (serve Vue SPA) ---
|
|
42
19
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
kind = rel["kind"]&.strip
|
|
48
|
-
name = rel["name"]&.strip
|
|
49
|
-
|
|
50
|
-
next if verb.nil? || verb.empty?
|
|
51
|
-
next if kind.nil? || kind.empty?
|
|
52
|
-
next if name.nil? || name.empty?
|
|
53
|
-
|
|
54
|
-
# Find existing relation group or create new one
|
|
55
|
-
existing = relations.find { |r| r[:verb] == verb && r[:kind] == kind }
|
|
56
|
-
if existing
|
|
57
|
-
existing[:names] << name unless existing[:names].include?(name)
|
|
58
|
-
else
|
|
59
|
-
relations << { verb: verb, kind: kind, names: [name] }
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
relations
|
|
64
|
-
end
|
|
20
|
+
get "/kinds/:kind/new" do
|
|
21
|
+
halt 404, "Kind not found" unless Archsight::Resources[params["kind"]]
|
|
22
|
+
serve_vue
|
|
23
|
+
end
|
|
65
24
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
start_line: instance.path_ref.line_no,
|
|
71
|
-
expected_hash: expected_hash
|
|
72
|
-
)
|
|
73
|
-
end
|
|
25
|
+
get "/kinds/:kind/instances/:name/edit" do
|
|
26
|
+
halt 404, "Kind not found" unless Archsight::Resources[params["kind"]]
|
|
27
|
+
halt 404, "Instance not found" unless db.instance_by_kind(params["kind"], params["name"])
|
|
28
|
+
serve_vue
|
|
74
29
|
end
|
|
75
30
|
|
|
76
|
-
#
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
@klass = Archsight::Resources[@kind]
|
|
80
|
-
halt 404, "Kind not found" unless @klass
|
|
31
|
+
# Legacy POST generate routes — Vue SPA handles these now
|
|
32
|
+
post("/kinds/:kind/generate") { serve_vue }
|
|
33
|
+
post("/kinds/:kind/instances/:name/generate") { serve_vue }
|
|
81
34
|
|
|
82
|
-
|
|
83
|
-
@mode = :create
|
|
84
|
-
@name = ""
|
|
85
|
-
@annotations = {}
|
|
86
|
-
@relations = []
|
|
87
|
-
@fields = editor_fields(@kind)
|
|
88
|
-
@errors = {}
|
|
35
|
+
# --- JSON API routes ---
|
|
89
36
|
|
|
90
|
-
|
|
91
|
-
|
|
37
|
+
get "/api/v1/editor/kinds/:kind/form" do
|
|
38
|
+
content_type :json
|
|
39
|
+
kind = params["kind"]
|
|
40
|
+
klass = Archsight::Resources[kind]
|
|
41
|
+
halt 404, JSON.generate({ error: "Kind not found" }) unless klass
|
|
92
42
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
halt 404, "Kind not found" unless @klass
|
|
43
|
+
data = build_form_metadata(kind, klass)
|
|
44
|
+
data[:mode] = "create"
|
|
45
|
+
JSON.generate(data)
|
|
46
|
+
end
|
|
98
47
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
@fields = editor_fields(@kind)
|
|
48
|
+
get "/api/v1/editor/kinds/:kind/instances/:name/form" do
|
|
49
|
+
content_type :json
|
|
50
|
+
kind = params["kind"]
|
|
51
|
+
klass = Archsight::Resources[kind]
|
|
52
|
+
halt 404, JSON.generate({ error: "Kind not found" }) unless klass
|
|
105
53
|
|
|
106
|
-
|
|
107
|
-
|
|
54
|
+
instance = db.instance_by_kind(kind, params["name"])
|
|
55
|
+
halt 404, JSON.generate({ error: "Instance not found" }) unless instance
|
|
108
56
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
57
|
+
data = build_form_metadata(kind, klass)
|
|
58
|
+
data[:mode] = "edit"
|
|
59
|
+
data[:name] = instance.name
|
|
60
|
+
data[:annotations] = instance.annotations.dup
|
|
61
|
+
data[:relations] = extract_instance_relations(instance)
|
|
62
|
+
data[:path_ref] = "#{instance.path_ref.path}:#{instance.path_ref.line_no}"
|
|
113
63
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
kind: @kind,
|
|
117
|
-
name: @name,
|
|
118
|
-
annotations: @annotations,
|
|
119
|
-
relations: @relations
|
|
64
|
+
original_content = Archsight::Editor::FileWriter.read_document(
|
|
65
|
+
path: instance.path_ref.path, start_line: instance.path_ref.line_no
|
|
120
66
|
)
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
@errors = {}
|
|
124
|
-
|
|
125
|
-
haml :index
|
|
67
|
+
data[:content_hash] = Archsight::Editor::ContentHasher.hash(original_content)
|
|
68
|
+
JSON.generate(data)
|
|
126
69
|
end
|
|
127
70
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
@klass = Archsight::Resources[@kind]
|
|
133
|
-
halt 404, "Kind not found" unless @klass
|
|
71
|
+
post "/api/v1/editor/kinds/:kind/generate" do
|
|
72
|
+
content_type :json
|
|
73
|
+
kind = params["kind"]
|
|
74
|
+
halt 404, JSON.generate({ error: "Kind not found" }) unless Archsight::Resources[kind]
|
|
134
75
|
|
|
135
|
-
|
|
136
|
-
|
|
76
|
+
body = parse_json_body
|
|
77
|
+
name = (body["name"] || "").strip
|
|
78
|
+
annotations = extract_annotations(body)
|
|
79
|
+
relations = parse_json_relations(body["relations"] || [])
|
|
137
80
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
@name = instance.name
|
|
141
|
-
@annotations = instance.annotations.dup
|
|
142
|
-
@relations = extract_instance_relations(instance)
|
|
143
|
-
@fields = editor_fields(@kind)
|
|
144
|
-
@errors = {}
|
|
81
|
+
validation = Archsight::Editor.validate(kind, name: name, annotations: annotations)
|
|
82
|
+
return JSON.generate({ yaml: nil, errors: validation[:errors] }) unless validation[:valid]
|
|
145
83
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
path: instance.path_ref.path,
|
|
149
|
-
start_line: instance.path_ref.line_no
|
|
84
|
+
resource = Archsight::Editor.build_resource(
|
|
85
|
+
kind: kind, name: name, annotations: annotations, relations: relations
|
|
150
86
|
)
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
haml :index
|
|
87
|
+
JSON.generate({ yaml: Archsight::Editor.to_yaml(resource), errors: nil })
|
|
154
88
|
end
|
|
155
89
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
halt 404, "Kind not found" unless @klass
|
|
162
|
-
|
|
163
|
-
# Get original instance for path_ref (for inline save)
|
|
164
|
-
original_instance = db.instance_by_kind(@kind, @instance_name)
|
|
165
|
-
@path_ref = original_instance&.path_ref
|
|
166
|
-
|
|
167
|
-
@editor_mode = true
|
|
168
|
-
@mode = :edit
|
|
169
|
-
@name = (params["name_field"] || @instance_name).strip
|
|
170
|
-
@annotations = extract_annotations(params)
|
|
171
|
-
@relations = parse_form_relations(params)
|
|
172
|
-
@fields = editor_fields(@kind)
|
|
173
|
-
@content_hash = params["content_hash"]
|
|
90
|
+
post "/api/v1/editor/kinds/:kind/instances/:name/generate" do
|
|
91
|
+
content_type :json
|
|
92
|
+
kind = params["kind"]
|
|
93
|
+
instance_name = params["name"]
|
|
94
|
+
halt 404, JSON.generate({ error: "Kind not found" }) unless Archsight::Resources[kind]
|
|
174
95
|
|
|
175
|
-
|
|
176
|
-
|
|
96
|
+
body = parse_json_body
|
|
97
|
+
name = (body["name"] || instance_name).strip
|
|
98
|
+
annotations = extract_annotations(body)
|
|
99
|
+
relations = parse_json_relations(body["relations"] || [])
|
|
177
100
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
return haml :index
|
|
181
|
-
end
|
|
101
|
+
validation = Archsight::Editor.validate(kind, name: name, annotations: annotations)
|
|
102
|
+
return JSON.generate({ yaml: nil, errors: validation[:errors] }) unless validation[:valid]
|
|
182
103
|
|
|
183
|
-
# Build and render YAML
|
|
184
104
|
resource = Archsight::Editor.build_resource(
|
|
185
|
-
kind:
|
|
186
|
-
name: @name,
|
|
187
|
-
annotations: @annotations,
|
|
188
|
-
relations: @relations
|
|
105
|
+
kind: kind, name: name, annotations: annotations, relations: relations
|
|
189
106
|
)
|
|
190
107
|
|
|
191
|
-
|
|
192
|
-
|
|
108
|
+
original = db.instance_by_kind(kind, instance_name)
|
|
109
|
+
path_ref = original&.path_ref ? "#{original.path_ref.path}:#{original.path_ref.line_no}" : nil
|
|
193
110
|
|
|
194
|
-
|
|
111
|
+
JSON.generate({
|
|
112
|
+
yaml: Archsight::Editor.to_yaml(resource), errors: nil,
|
|
113
|
+
path_ref: path_ref, content_hash: body["content_hash"]
|
|
114
|
+
})
|
|
195
115
|
end
|
|
196
116
|
|
|
197
|
-
# Save YAML to source file (inline edit)
|
|
198
117
|
post "/api/v1/editor/kinds/:kind/instances/:name/save" do
|
|
199
118
|
content_type :json
|
|
200
|
-
|
|
201
|
-
# Check if inline edit is enabled
|
|
202
119
|
halt 403, JSON.generate({ success: false, error: "Inline edit is disabled. Start server with --inline-edit flag." }) unless settings.inline_edit_enabled
|
|
203
120
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
begin
|
|
208
|
-
body = JSON.parse(request.body.read)
|
|
209
|
-
yaml_content = body["yaml"]
|
|
210
|
-
expected_hash = body["content_hash"]
|
|
211
|
-
rescue JSON::ParserError
|
|
212
|
-
halt 400, JSON.generate({ success: false, error: "Invalid JSON" })
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
instance = db.instance_by_kind(kind, name)
|
|
121
|
+
body = parse_json_body
|
|
122
|
+
instance = db.instance_by_kind(params["kind"], params["name"])
|
|
216
123
|
halt 404, JSON.generate({ success: false, error: "Instance not found" }) unless instance
|
|
217
124
|
|
|
218
|
-
|
|
219
|
-
if (conflict = validate_content_hash(instance, expected_hash))
|
|
125
|
+
if (conflict = validate_content_hash(instance, body["content_hash"]))
|
|
220
126
|
status 409
|
|
221
127
|
return JSON.generate({ success: false }.merge(conflict))
|
|
222
128
|
end
|
|
223
129
|
|
|
224
130
|
begin
|
|
225
131
|
Archsight::Editor::FileWriter.replace_document(
|
|
226
|
-
path: instance.path_ref.path,
|
|
227
|
-
|
|
228
|
-
new_yaml: yaml_content
|
|
132
|
+
path: instance.path_ref.path, start_line: instance.path_ref.line_no,
|
|
133
|
+
new_yaml: body["yaml"]
|
|
229
134
|
)
|
|
230
135
|
db.reload!
|
|
231
136
|
JSON.generate({ success: true, message: "Saved to #{instance.path_ref}" })
|
|
@@ -235,56 +140,24 @@ module Archsight
|
|
|
235
140
|
end
|
|
236
141
|
end
|
|
237
142
|
|
|
238
|
-
# HTMX API - Get instance names for a kind (for relation dropdown)
|
|
239
143
|
get "/api/v1/editor/kinds/:kind/instances" do
|
|
240
144
|
kind = params["kind"]
|
|
241
|
-
|
|
242
|
-
halt 404, "Kind not found" unless klass
|
|
243
|
-
|
|
244
|
-
instances = db.instances_by_kind(kind).keys.sort
|
|
245
|
-
|
|
145
|
+
halt 404, "Kind not found" unless Archsight::Resources[kind]
|
|
246
146
|
content_type :json
|
|
247
|
-
JSON.generate(
|
|
147
|
+
JSON.generate(db.instances_by_kind(kind).keys.sort)
|
|
248
148
|
end
|
|
249
149
|
|
|
250
|
-
# HTMX API - Get valid target kinds for a verb
|
|
251
150
|
get "/api/v1/editor/relation-kinds" do
|
|
252
|
-
|
|
253
|
-
verb = params["verb"]
|
|
254
|
-
halt 400, "Kind and verb required" unless kind && verb
|
|
255
|
-
|
|
256
|
-
target_kinds = Archsight::Editor.target_kinds_for_verb(kind, verb)
|
|
257
|
-
|
|
151
|
+
halt 400, "Kind and verb required" unless params["kind"] && params["verb"]
|
|
258
152
|
content_type :json
|
|
259
|
-
JSON.generate(
|
|
153
|
+
JSON.generate(Archsight::Editor.target_kinds_for_verb(params["kind"], params["verb"]))
|
|
260
154
|
end
|
|
261
155
|
|
|
262
156
|
helpers do
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
relations = []
|
|
268
|
-
|
|
269
|
-
instance.spec.each do |verb, relation_groups|
|
|
270
|
-
next unless relation_groups.is_a?(Hash)
|
|
271
|
-
|
|
272
|
-
relation_groups.each do |relation_name, targets|
|
|
273
|
-
next unless targets.is_a?(Array)
|
|
274
|
-
|
|
275
|
-
# Look up the target class name from the relation definition
|
|
276
|
-
target_class = Archsight::Editor.target_class_for_relation(instance.kind, verb, relation_name)
|
|
277
|
-
next unless target_class
|
|
278
|
-
|
|
279
|
-
targets.each do |target|
|
|
280
|
-
# Target could be an instance object or a string
|
|
281
|
-
target_name = target.respond_to?(:name) ? target.name : target.to_s
|
|
282
|
-
relations << { verb: verb, kind: target_class, name: target_name }
|
|
283
|
-
end
|
|
284
|
-
end
|
|
285
|
-
end
|
|
286
|
-
|
|
287
|
-
relations
|
|
157
|
+
def parse_json_body
|
|
158
|
+
JSON.parse(request.body.read)
|
|
159
|
+
rescue JSON::ParserError
|
|
160
|
+
halt 400, JSON.generate({ error: "Invalid JSON" })
|
|
288
161
|
end
|
|
289
162
|
end
|
|
290
163
|
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{_ as u,l as _,c as s,a as c,v as m,t as f,b as v,r as i,z as k,o as d,B as w}from"./index-DsEsN0_K.js";import"./mermaid-DpPHPFQh.js";const h={class:"api-docs-page"},y={key:0,class:"pico-color-red-500"},g={__name:"ApiDocsPage",setup(B){const l=k(),r=i(null),t=i(null);function p(o){return new Promise((e,n)=>{if(window.Redoc)return e();const a=document.createElement("script");a.src=o,a.onload=e,a.onerror=()=>n(new Error("Failed to load ReDoc")),document.head.appendChild(a)})}return _(async()=>{try{await p("https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"),window.Redoc.init("/api/v1/openapi.yaml",{},r.value)}catch(o){t.value=o.message}}),(o,e)=>(d(),s("div",h,[c("a",{href:"#",class:"back-link",onClick:e[0]||(e[0]=m(n=>w(l).back(),["prevent"]))},"← Back"),t.value?(d(),s("div",y,f(t.value),1)):v("",!0),c("div",{ref_key:"container",ref:r},null,512)]))}},R=u(g,[["__scopeId","data-v-0e03906d"]]);export{R as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.back-link[data-v-0e03906d]{position:fixed;top:12px;right:12px;z-index:100;padding:6px 14px;background:#fff;border:1px solid #ddd;border-radius:4px;text-decoration:none;font-size:.875rem;box-shadow:0 1px 4px #0000001a}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{w as m,c as i,a as f,r as a,o as s,j as p,k as d}from"./index-DsEsN0_K.js";import{r as v}from"./useMermaid-DqxTrLRB.js";import{h as _}from"./useHighlight-C6Kb5G3l.js";import"./mermaid-DpPHPFQh.js";import"./usePanZoom-BybZ_rfh.js";const k=["innerHTML"],g={key:1},D={__name:"DocPage",props:{filename:String},setup(c){const n=c,o=a(""),t=a(!0),e=a(null);async function u(){t.value=!0;const r=await p(n.filename);o.value=r||"<p>Documentation not found.</p>",t.value=!1,await d(),e.value&&(_(e.value),v(e.value))}return m(()=>n.filename,u,{immediate:!0}),(r,l)=>t.value?(s(),i("article",g,[...l[0]||(l[0]=[f("p",null,"Loading...",-1)])])):(s(),i("div",{key:0,ref_key:"articleEl",ref:e,innerHTML:o.value},null,8,k))}};export{D as default};
|