a1c00l commited on
Commit
8402521
·
verified ·
1 Parent(s): 7960b17

Update templates/result.html

Browse files
Files changed (1) hide show
  1. templates/result.html +357 -190
templates/result.html CHANGED
@@ -2,103 +2,114 @@
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8">
5
- <title>AIBOM Generated - Improved Scoring</title>
6
  <style>
7
- body { font-family: Arial, sans-serif; margin: 20px; color: #333; }
8
- h2, h3 { color: #2c3e50; }
9
-
10
- /* Table styles */
11
- table { border-collapse: collapse; width: 100%; margin: 15px 0 25px 0; }
12
- th, td { border: 1px solid #ddd; padding: 12px; text-align: left; }
13
  th { background-color: #f4f4f4; }
 
 
 
 
 
14
 
15
- /* Progress bar styles */
16
- .progress-container {
17
- width: 100%;
18
- background-color: #f1f1f1;
19
- border-radius: 5px;
20
- margin: 5px 0;
 
21
  }
22
- .progress-bar {
23
- height: 24px;
24
- border-radius: 5px;
25
- display: flex;
26
- align-items: center;
27
- justify-content: center;
28
- color: white;
 
 
 
 
 
 
 
 
 
 
 
29
  font-weight: bold;
30
- transition: width 1s;
 
31
  }
32
- .excellent { background-color: #27ae60; }
33
- .good { background-color: #2980b9; }
34
- .fair { background-color: #f39c12; }
35
- .poor { background-color: #e74c3c; }
36
-
37
- /* Field checklist styles */
38
- .field-list { list-style: none; padding-left: 0; }
39
- .missing { color: #e74c3c; }
40
- .present { color: #27ae60; }
41
-
42
- /* Improvement section styles */
43
- .improvement {
44
- color: #2c3e50;
45
- background-color: #ecf0f1;
46
- padding: 15px;
47
- border-radius: 5px;
48
- margin-bottom: 20px;
49
  }
50
- .improvement-value { color: #27ae60; font-weight: bold; }
51
- .ai-badge {
52
- background-color: #3498db;
53
- color: white;
54
- padding: 3px 8px;
55
- border-radius: 3px;
56
- font-size: 0.8em;
57
- margin-left: 10px;
58
  }
59
-
60
- /* Score explanation styles */
61
- .score-explanation {
62
- background-color: #f8f9fa;
63
- border: 1px solid #e9ecef;
64
- border-radius: 5px;
65
- padding: 15px;
66
- margin: 20px 0;
67
  }
68
- .calculation-step {
69
- font-family: monospace;
70
- margin: 5px 0;
71
  }
72
- .weight-indicator {
73
- font-size: 0.9em;
74
- color: #7f8c8d;
75
- margin-left: 5px;
 
 
 
 
 
 
 
 
 
76
  }
77
-
78
- /* Collapsible section styles */
79
  .collapsible {
80
- background-color: #f1f1f1;
81
- color: #444;
82
  cursor: pointer;
83
- padding: 18px;
84
- width: 100%;
85
- border: none;
86
- text-align: left;
87
- outline: none;
88
- font-size: 15px;
89
- border-radius: 5px;
90
- margin: 10px 0;
91
  }
92
- .active, .collapsible:hover {
93
- background-color: #e0e0e0;
 
 
 
 
 
94
  }
95
- .content {
96
- padding: 0 18px;
97
  max-height: 0;
98
  overflow: hidden;
99
  transition: max-height 0.2s ease-out;
100
- background-color: #f9f9f9;
101
- border-radius: 0 0 5px 5px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  }
103
  </style>
104
  </head>
@@ -110,128 +121,262 @@
110
  <div class="improvement">
111
  <h3>AI Enhancement Results</h3>
112
  <p>This AIBOM was enhanced using <strong>{{ enhancement_report.ai_model }}</strong></p>
113
-
114
- <p>Original Score:
115
- <div class="progress-container">
116
- <div class="progress-bar {% if enhancement_report.original_score.total_score >= 80 %}excellent{% elif enhancement_report.original_score.total_score >= 60 %}good{% elif enhancement_report.original_score.total_score >= 40 %}fair{% else %}poor{% endif %}"
117
- style="width: {{ enhancement_report.original_score.total_score }}%">
118
- {{ enhancement_report.original_score.total_score }}%
119
- </div>
120
- </div>
121
- </p>
122
-
123
- <p>Enhanced Score:
124
- <div class="progress-container">
125
- <div class="progress-bar {% if enhancement_report.final_score.total_score >= 80 %}excellent{% elif enhancement_report.final_score.total_score >= 60 %}good{% elif enhancement_report.final_score.total_score >= 40 %}fair{% else %}poor{% endif %}"
126
- style="width: {{ enhancement_report.final_score.total_score }}%">
127
- {{ enhancement_report.final_score.total_score }}%
128
- </div>
129
- </div>
130
- </p>
131
-
132
  <p>Improvement: <span class="improvement-value">+{{ enhancement_report.improvement }} points</span></p>
133
  </div>
134
  {% endif %}
135
 
136
- <h3>Overall AIBOM Completeness
137
  {% if enhancement_report and enhancement_report.ai_enhanced %}
138
  <span class="ai-badge">AI Enhanced</span>
139
  {% endif %}
140
  </h3>
141
-
142
- <div class="progress-container">
143
- <div class="progress-bar {% if completeness_score.total_score >= 80 %}excellent{% elif completeness_score.total_score >= 60 %}good{% elif completeness_score.total_score >= 40 %}fair{% else %}poor{% endif %}"
144
- style="width: {{ completeness_score.total_score }}%">
145
- {{ completeness_score.total_score }}%
146
- </div>
147
- </div>
148
-
149
- <p>
150
- {% if completeness_score.total_score >= 80 %}
151
- <strong>Excellent:</strong> This AIBOM is very comprehensive and provides thorough documentation.
152
- {% elif completeness_score.total_score >= 60 %}
153
- <strong>Good:</strong> This AIBOM contains most essential information but could be improved.
154
- {% elif completeness_score.total_score >= 40 %}
155
- <strong>Fair:</strong> This AIBOM has basic information but is missing several important details.
156
- {% else %}
157
- <strong>Needs Improvement:</strong> This AIBOM is missing critical information and requires significant enhancement.
158
- {% endif %}
159
- </p>
160
 
161
- <h3>Section Completion</h3>
162
  <table>
163
  <thead>
164
- <tr>
165
- <th>Section</th>
166
- <th>Completion</th>
167
- <th>Weight</th>
168
- <th>Contribution</th>
169
- </tr>
170
  </thead>
171
  <tbody>
172
  {% for section, score in completeness_score.section_scores.items() %}
173
- {% set max_score = completeness_score.max_scores[section] %}
174
- {% set percentage = (score / max_score * 100) | round %}
175
- {% set weight = 0.2 if section == 'required_fields' else 0.2 if section == 'metadata' else 0.2 if section == 'component_basic' else 0.3 if section == 'component_model_card' else 0.1 %}
176
- {% set contribution = (score * weight) | round(1) %}
177
  <tr>
178
- <td>{{ section | replace('_', ' ') | title }}</td>
179
- <td>
180
- <div class="progress-container">
181
- <div class="progress-bar {% if percentage >= 80 %}excellent{% elif percentage >= 60 %}good{% elif percentage >= 40 %}fair{% else %}poor{% endif %}"
182
- style="width: {{ percentage }}%">
183
- {{ score }}/{{ max_score }} ({{ percentage }}%)
184
- </div>
185
- </div>
186
- </td>
187
- <td>{{ (weight * 100) | int }}%</td>
188
- <td>{{ contribution }} points</td>
189
  </tr>
190
  {% endfor %}
191
  </tbody>
192
  </table>
193
 
194
- <button class="collapsible">How is the score calculated?</button>
195
- <div class="content">
196
- <div class="score-explanation">
197
- <h4>Score Calculation Breakdown</h4>
198
- <p>The overall score is a weighted average of section scores:</p>
199
-
200
- <div class="calculation-step">Required Fields: {{ completeness_score.section_scores.required_fields }} × 0.20 = {{ (completeness_score.section_scores.required_fields * 0.2) | round(1) }} points</div>
201
- <div class="calculation-step">Metadata: {{ completeness_score.section_scores.metadata }} × 0.20 = {{ (completeness_score.section_scores.metadata * 0.2) | round(1) }} points</div>
202
- <div class="calculation-step">Component Basic: {{ completeness_score.section_scores.component_basic }} × 0.20 = {{ (completeness_score.section_scores.component_basic * 0.2) | round(1) }} points</div>
203
- <div class="calculation-step">Model Card: {{ completeness_score.section_scores.component_model_card }} × 0.30 = {{ (completeness_score.section_scores.component_model_card * 0.3) | round(1) }} points</div>
204
- <div class="calculation-step">External References: {{ completeness_score.section_scores.external_references }} × 0.10 = {{ (completeness_score.section_scores.external_references * 0.1) | round(1) }} points</div>
205
- <div class="calculation-step"><strong>Total: {{ completeness_score.total_score }} points</strong></div>
206
-
207
- <p>Each section has a different weight in the final calculation to reflect its importance:</p>
208
- <ul>
209
- <li>Required Fields: 20% weight</li>
210
- <li>Metadata: 20% weight</li>
211
- <li>Component Basic: 20% weight</li>
212
- <li>Model Card: 30% weight (higher weight as it contains critical AI information)</li>
213
- <li>External References: 10% weight</li>
214
- </ul>
215
- </div>
216
  </div>
217
 
218
- <h3>Field Checklist</h3>
219
- <ul class="field-list">
220
- {% for field, status in completeness_score.field_checklist.items() %}
221
- {% if status == "✔" %}
222
- <li class="present">{{ status }} {{ field }}</li>
223
- {% else %}
224
- <li class="missing">{{ status }} {{ field }}</li>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
225
  {% endif %}
226
- {% endfor %}
227
- </ul>
228
 
229
- <h3>
230
- Download AI SBOM in CycloneDX format for {{ model_id }}
231
- <button onclick="downloadJSON()">Download JSON</button>
232
- </h3>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
 
234
- <pre id="aibom-json">{{ aibom | tojson(indent=2) }}</pre>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
 
236
  <script>
237
  function downloadJSON() {
@@ -243,20 +388,42 @@
243
  downloadAnchorNode.click();
244
  downloadAnchorNode.remove();
245
  }
246
-
247
- // Collapsible sections
248
- var coll = document.getElementsByClassName("collapsible");
249
- for (var i = 0; i < coll.length; i++) {
250
- coll[i].addEventListener("click", function() {
251
- this.classList.toggle("active");
252
- var content = this.nextElementSibling;
253
- if (content.style.maxHeight) {
254
- content.style.maxHeight = null;
255
- } else {
256
- content.style.maxHeight = content.scrollHeight + "px";
257
- }
258
- });
 
 
 
 
 
 
 
259
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
  </script>
261
  </body>
262
- </html>
 
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8">
5
+ <title>AIBOM Generated</title>
6
  <style>
7
+ body { font-family: Arial, sans-serif; margin: 20px; }
8
+ table { border-collapse: collapse; width: 60%; margin-top: 15px; }
9
+ th, td { border: 1px solid #ddd; padding: 8px; }
 
 
 
10
  th { background-color: #f4f4f4; }
11
+ .missing { color: red; }
12
+ .present { color: green; }
13
+ .improvement { color: #2c3e50; background-color: #ecf0f1; padding: 15px; border-radius: 5px; margin-bottom: 20px; }
14
+ .improvement-value { color: #27ae60; font-weight: bold; }
15
+ .ai-badge { background-color: #3498db; color: white; padding: 3px 8px; border-radius: 3px; font-size: 0.8em; margin-left: 10px; }
16
 
17
+ /* New styles for human-friendly viewer */
18
+ .aibom-viewer {
19
+ margin: 20px 0;
20
+ border: 1px solid #ddd;
21
+ border-radius: 5px;
22
+ padding: 20px;
23
+ background-color: #f9f9f9;
24
  }
25
+ .aibom-section {
26
+ margin-bottom: 20px;
27
+ padding: 15px;
28
+ border-radius: 5px;
29
+ background-color: white;
30
+ box-shadow: 0 1px 3px rgba(0,0,0,0.1);
31
+ }
32
+ .aibom-section h4 {
33
+ margin-top: 0;
34
+ color: #2c3e50;
35
+ border-bottom: 1px solid #eee;
36
+ padding-bottom: 8px;
37
+ }
38
+ .aibom-property {
39
+ display: flex;
40
+ margin: 5px 0;
41
+ }
42
+ .property-name {
43
  font-weight: bold;
44
+ width: 200px;
45
+ color: #34495e;
46
  }
47
+ .property-value {
48
+ flex: 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  }
50
+ .aibom-tabs {
51
+ display: flex;
52
+ border-bottom: 1px solid #ddd;
53
+ margin-bottom: 20px;
 
 
 
 
54
  }
55
+ .aibom-tab {
56
+ padding: 10px 20px;
57
+ cursor: pointer;
58
+ background-color: #f4f4f4;
59
+ margin-right: 5px;
60
+ border-radius: 5px 5px 0 0;
 
 
61
  }
62
+ .aibom-tab.active {
63
+ background-color: #3498db;
64
+ color: white;
65
  }
66
+ .tab-content {
67
+ display: none;
68
+ }
69
+ .tab-content.active {
70
+ display: block;
71
+ }
72
+ .json-view {
73
+ background-color: #f8f8f8;
74
+ border: 1px solid #ddd;
75
+ border-radius: 5px;
76
+ padding: 15px;
77
+ overflow: auto;
78
+ max-height: 500px;
79
  }
 
 
80
  .collapsible {
 
 
81
  cursor: pointer;
82
+ position: relative;
 
 
 
 
 
 
 
83
  }
84
+ .collapsible:after {
85
+ content: '+';
86
+ position: absolute;
87
+ right: 10px;
88
+ }
89
+ .collapsible.active:after {
90
+ content: '-';
91
  }
92
+ .collapsible-content {
 
93
  max-height: 0;
94
  overflow: hidden;
95
  transition: max-height 0.2s ease-out;
96
+ }
97
+ .collapsible-content.active {
98
+ max-height: 500px;
99
+ }
100
+ .tag {
101
+ display: inline-block;
102
+ background-color: #e0e0e0;
103
+ padding: 2px 8px;
104
+ border-radius: 12px;
105
+ margin: 2px;
106
+ font-size: 0.9em;
107
+ }
108
+ .key-info {
109
+ background-color: #e3f2fd;
110
+ border-left: 4px solid #2196F3;
111
+ padding: 10px;
112
+ margin-bottom: 15px;
113
  }
114
  </style>
115
  </head>
 
121
  <div class="improvement">
122
  <h3>AI Enhancement Results</h3>
123
  <p>This AIBOM was enhanced using <strong>{{ enhancement_report.ai_model }}</strong></p>
124
+ <p>Original Score: {{ enhancement_report.original_score.total_score }}/100</p>
125
+ <p>Enhanced Score: {{ enhancement_report.final_score.total_score }}/100</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  <p>Improvement: <span class="improvement-value">+{{ enhancement_report.improvement }} points</span></p>
127
  </div>
128
  {% endif %}
129
 
130
+ <h3>Overall Completeness Score: {{ completeness_score.total_score }}/100
131
  {% if enhancement_report and enhancement_report.ai_enhanced %}
132
  <span class="ai-badge">AI Enhanced</span>
133
  {% endif %}
134
  </h3>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
 
136
+ <h3>Section Breakdown</h3>
137
  <table>
138
  <thead>
139
+ <tr><th>Section</th><th>Score</th></tr>
 
 
 
 
 
140
  </thead>
141
  <tbody>
142
  {% for section, score in completeness_score.section_scores.items() %}
 
 
 
 
143
  <tr>
144
+ <td>{{ section }}</td>
145
+ <td>{{ score }}/{{ completeness_score.max_scores[section] }}</td>
 
 
 
 
 
 
 
 
 
146
  </tr>
147
  {% endfor %}
148
  </tbody>
149
  </table>
150
 
151
+ <!-- Human-friendly AIBOM Viewer -->
152
+ <div style="background-color: #fff3cd; border-left: 4px solid #ffc107; padding: 10px; margin: 15px 0;">
153
+ <p><strong>Note:</strong> This page displays the AIBOM in a human-friendly format for easier readability.
154
+ The downloaded JSON file follows the standard CycloneDX format required for interoperability with other tools.</p>
155
+ </div>
156
+
157
+ <div class="aibom-tabs">
158
+ <div class="aibom-tab active" onclick="switchTab('human-view')">Human-Friendly View</div>
159
+ <div class="aibom-tab" onclick="switchTab('json-view')">JSON View</div>
160
+ <div class="aibom-tab" onclick="switchTab('field-checklist')">Field Checklist</div>
 
 
 
 
 
 
 
 
 
 
 
 
161
  </div>
162
 
163
+ <div id="human-view" class="tab-content active">
164
+ <div class="aibom-viewer">
165
+ <!-- Key Information Section -->
166
+ <div class="aibom-section key-info">
167
+ <h4>Key Information</h4>
168
+ <div class="aibom-property">
169
+ <div class="property-name">Model Name:</div>
170
+ <div class="property-value">{{ aibom.components[0].name if aibom.components and aibom.components[0].name else 'Not specified' }}</div>
171
+ </div>
172
+ <div class="aibom-property">
173
+ <div class="property-name">Type:</div>
174
+ <div class="property-value">{{ aibom.components[0].type if aibom.components and aibom.components[0].type else 'Not specified' }}</div>
175
+ </div>
176
+ <div class="aibom-property">
177
+ <div class="property-name">Version:</div>
178
+ <div class="property-value">{{ aibom.components[0].version if aibom.components and aibom.components[0].version else 'Not specified' }}</div>
179
+ </div>
180
+ <div class="aibom-property">
181
+ <div class="property-name">PURL:</div>
182
+ <div class="property-value">{{ aibom.components[0].purl if aibom.components and aibom.components[0].purl else 'Not specified' }}</div>
183
+ </div>
184
+ {% if aibom.components and aibom.components[0].description %}
185
+ <div class="aibom-property">
186
+ <div class="property-name">Description:</div>
187
+ <div class="property-value">{{ aibom.components[0].description }}</div>
188
+ </div>
189
+ {% endif %}
190
+ </div>
191
+
192
+ <!-- Model Card Section -->
193
+ {% if aibom.components and aibom.components[0].modelCard %}
194
+ <div class="aibom-section">
195
+ <h4 class="collapsible" onclick="toggleCollapsible(this)">Model Card</h4>
196
+ <div class="collapsible-content">
197
+ {% if aibom.components[0].modelCard.modelParameters %}
198
+ <div class="aibom-property">
199
+ <div class="property-name">Model Parameters:</div>
200
+ <div class="property-value">
201
+ {% for key, value in aibom.components[0].modelCard.modelParameters.items() %}
202
+ <div><strong>{{ key }}:</strong>
203
+ {% if value is string %}
204
+ {{ value }}
205
+ {% elif value is iterable %}
206
+ {{ value|join(', ') }}
207
+ {% else %}
208
+ {{ value }}
209
+ {% endif %}
210
+ </div>
211
+ {% endfor %}
212
+ </div>
213
+ </div>
214
+ {% endif %}
215
+
216
+ {% if aibom.components[0].modelCard.quantitativeAnalysis %}
217
+ <div class="aibom-property">
218
+ <div class="property-name">Performance Metrics:</div>
219
+ <div class="property-value">
220
+ {% if aibom.components[0].modelCard.quantitativeAnalysis.performanceMetrics %}
221
+ {% for metric in aibom.components[0].modelCard.quantitativeAnalysis.performanceMetrics %}
222
+ <div><strong>{{ metric.type if metric.type else 'Metric' }}:</strong> {{ metric.value if metric.value else 'Not specified' }}</div>
223
+ {% endfor %}
224
+ {% endif %}
225
+ </div>
226
+ </div>
227
+ {% endif %}
228
+
229
+ {% if aibom.components[0].modelCard.considerations %}
230
+ <div class="aibom-property">
231
+ <div class="property-name">Considerations:</div>
232
+ <div class="property-value">
233
+ {% for key, value in aibom.components[0].modelCard.considerations.items() %}
234
+ <div><strong>{{ key }}:</strong> {{ value }}</div>
235
+ {% endfor %}
236
+ </div>
237
+ </div>
238
+ {% endif %}
239
+ </div>
240
+ </div>
241
  {% endif %}
 
 
242
 
243
+ <!-- Metadata Section -->
244
+ <div class="aibom-section">
245
+ <h4 class="collapsible" onclick="toggleCollapsible(this)">Metadata</h4>
246
+ <div class="collapsible-content">
247
+ <div class="aibom-property">
248
+ <div class="property-name">Generated:</div>
249
+ <div class="property-value">{{ aibom.metadata.timestamp if aibom.metadata.timestamp else 'Not specified' }}</div>
250
+ </div>
251
+
252
+ {% if aibom.metadata.authors %}
253
+ <div class="aibom-property">
254
+ <div class="property-name">Authors:</div>
255
+ <div class="property-value">
256
+ {% for author in aibom.metadata.authors %}
257
+ <div>{{ author.name }} {% if author.url %}({{ author.url }}){% endif %}</div>
258
+ {% endfor %}
259
+ </div>
260
+ </div>
261
+ {% endif %}
262
+
263
+ {% if aibom.metadata.tools %}
264
+ <div class="aibom-property">
265
+ <div class="property-name">Generated by:</div>
266
+ <div class="property-value">
267
+ {% for tool in aibom.metadata.tools %}
268
+ <div>{{ tool.name }} v{{ tool.version }} ({{ tool.vendor }})</div>
269
+ {% endfor %}
270
+ </div>
271
+ </div>
272
+ {% endif %}
273
+
274
+ {% if aibom.metadata.properties %}
275
+ <div class="aibom-property">
276
+ <div class="property-name">Properties:</div>
277
+ <div class="property-value">
278
+ {% for prop in aibom.metadata.properties %}
279
+ {% if prop.name == 'tags' and prop.value %}
280
+ <div><strong>Tags:</strong>
281
+ {% set tags = prop.value|replace('[', '')|replace(']', '')|replace('"', '')|split(', ') %}
282
+ {% for tag in tags %}
283
+ <span class="tag">{{ tag }}</span>
284
+ {% endfor %}
285
+ </div>
286
+ {% elif prop.name not in ['aibom:quality-score', 'aibom:quality-breakdown', 'aibom:max-scores'] %}
287
+ <div><strong>{{ prop.name }}:</strong> {{ prop.value }}</div>
288
+ {% endif %}
289
+ {% endfor %}
290
+ </div>
291
+ </div>
292
+ {% endif %}
293
+ </div>
294
+ </div>
295
 
296
+ <!-- External References Section -->
297
+ {% if aibom.components and aibom.components[0].externalReferences %}
298
+ <div class="aibom-section">
299
+ <h4 class="collapsible" onclick="toggleCollapsible(this)">External References</h4>
300
+ <div class="collapsible-content">
301
+ {% for ref in aibom.components[0].externalReferences %}
302
+ <div class="aibom-property">
303
+ <div class="property-name">{{ ref.type|capitalize if ref.type else 'Reference' }}:</div>
304
+ <div class="property-value"><a href="{{ ref.url }}" target="_blank">{{ ref.url }}</a></div>
305
+ </div>
306
+ {% endfor %}
307
+ </div>
308
+ </div>
309
+ {% endif %}
310
+
311
+ <!-- Dependencies Section -->
312
+ {% if aibom.dependencies %}
313
+ <div class="aibom-section">
314
+ <h4 class="collapsible" onclick="toggleCollapsible(this)">Dependencies</h4>
315
+ <div class="collapsible-content">
316
+ {% for dep in aibom.dependencies %}
317
+ <div class="aibom-property">
318
+ <div class="property-name">{{ dep.ref }}:</div>
319
+ <div class="property-value">
320
+ {% if dep.dependsOn %}
321
+ {% for dependency in dep.dependsOn %}
322
+ <div>{{ dependency }}</div>
323
+ {% endfor %}
324
+ {% else %}
325
+ No dependencies specified
326
+ {% endif %}
327
+ </div>
328
+ </div>
329
+ {% endfor %}
330
+ </div>
331
+ </div>
332
+ {% endif %}
333
+
334
+ <!-- SBOM Information Section -->
335
+ <div class="aibom-section">
336
+ <h4 class="collapsible" onclick="toggleCollapsible(this)">SBOM Information</h4>
337
+ <div class="collapsible-content">
338
+ <div class="aibom-property">
339
+ <div class="property-name">Format:</div>
340
+ <div class="property-value">{{ aibom.bomFormat }}</div>
341
+ </div>
342
+ <div class="aibom-property">
343
+ <div class="property-name">Spec Version:</div>
344
+ <div class="property-value">{{ aibom.specVersion }}</div>
345
+ </div>
346
+ <div class="aibom-property">
347
+ <div class="property-name">Serial Number:</div>
348
+ <div class="property-value">{{ aibom.serialNumber }}</div>
349
+ </div>
350
+ <div class="aibom-property">
351
+ <div class="property-name">Version:</div>
352
+ <div class="property-value">{{ aibom.version }}</div>
353
+ </div>
354
+ </div>
355
+ </div>
356
+ </div>
357
+ </div>
358
+
359
+ <div id="json-view" class="tab-content">
360
+ <div class="json-view">
361
+ <pre id="aibom-json">{{ aibom | tojson(indent=2) }}</pre>
362
+ </div>
363
+ <div style="margin-top: 15px;">
364
+ <button onclick="downloadJSON()">Download JSON</button>
365
+ </div>
366
+ </div>
367
+
368
+ <div id="field-checklist" class="tab-content">
369
+ <h3>Field Checklist</h3>
370
+ <ul>
371
+ {% for field, status in completeness_score.field_checklist.items() %}
372
+ {% if status == "✔" %}
373
+ <li class="present">{{ status }} {{ field }}</li>
374
+ {% else %}
375
+ <li class="missing">{{ status }} {{ field }}</li>
376
+ {% endif %}
377
+ {% endfor %}
378
+ </ul>
379
+ </div>
380
 
381
  <script>
382
  function downloadJSON() {
 
388
  downloadAnchorNode.click();
389
  downloadAnchorNode.remove();
390
  }
391
+
392
+ function switchTab(tabId) {
393
+ // Hide all tab contents
394
+ const tabContents = document.getElementsByClassName('tab-content');
395
+ for (let i = 0; i < tabContents.length; i++) {
396
+ tabContents[i].classList.remove('active');
397
+ }
398
+
399
+ // Deactivate all tabs
400
+ const tabs = document.getElementsByClassName('aibom-tab');
401
+ for (let i = 0; i < tabs.length; i++) {
402
+ tabs[i].classList.remove('active');
403
+ }
404
+
405
+ // Activate the selected tab and content
406
+ document.getElementById(tabId).classList.add('active');
407
+ const selectedTab = document.querySelector(`.aibom-tab[onclick="switchTab('${tabId}')"]`);
408
+ if (selectedTab) {
409
+ selectedTab.classList.add('active');
410
+ }
411
  }
412
+
413
+ function toggleCollapsible(element) {
414
+ element.classList.toggle('active');
415
+ const content = element.nextElementSibling;
416
+ content.classList.toggle('active');
417
+ }
418
+
419
+ // Initialize collapsible sections
420
+ document.addEventListener('DOMContentLoaded', function() {
421
+ const collapsibles = document.getElementsByClassName('collapsible');
422
+ for (let i = 0; i < collapsibles.length; i++) {
423
+ collapsibles[i].nextElementSibling.classList.add('active');
424
+ collapsibles[i].classList.add('active');
425
+ }
426
+ });
427
  </script>
428
  </body>
429
+ </html>