Almirah 0.4.5 → 0.4.6
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/lib/almirah/doc_items/controlled_table.rb +23 -4
- data/lib/almirah/doc_types/base_document.rb +13 -11
- data/lib/almirah/doc_types/protocol.rb +4 -1
- data/lib/almirah/doc_types/risks_overview.rb +6 -6
- data/lib/almirah/doc_types/source_file.rb +2 -1
- data/lib/almirah/project.rb +22 -0
- data/lib/almirah/project_configuration.rb +7 -0
- data/lib/almirah/templates/css/main.css +13 -10
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8f66f0846c24a185b1abb415b4772edd12d7e7dfe93a0802ce8017ade9d0a249
|
|
4
|
+
data.tar.gz: 5f542c8b0aa5aa363310f049041a8e4f4341e49fd54ce8eaf1f26c442746d337
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 57099abaaeb800be450638dcd8cfc8915eda501389ab4833082b8006229e7d42eb9f861c82f07bbf828c79054e2c463b3a7cf52a897f6858354d50eb5a3d4395
|
|
7
|
+
data.tar.gz: a75661f96e5198cc71ffdec7da16577f58f23e18ff02c2c8fcd846d01dd332ded1995c8193ccfbf1789766ce657a3fd5fb328af6a1ae6312936733f6eeec4998
|
|
@@ -103,15 +103,17 @@ class TestStepReferenceColumn < ControlledTableColumn
|
|
|
103
103
|
s = ''
|
|
104
104
|
specifications_path = @parent_row.parent_doc.specifications_path
|
|
105
105
|
if @up_link_ids
|
|
106
|
+
cell_style = 'text-align: center;'
|
|
107
|
+
cell_style += ' background-color: #fcc;' if @up_link_ids.any? { |lnk| dangling?(lnk) }
|
|
106
108
|
if @up_link_ids.length == 1
|
|
107
109
|
if tmp = /^([a-zA-Z]+)-\d+/.match(@up_link_ids[0])
|
|
108
110
|
up_link_doc_name = tmp[1].downcase
|
|
109
111
|
end
|
|
110
|
-
s += "\t\t<td class=\"item_id\" style=\"
|
|
112
|
+
s += "\t\t<td class=\"item_id\" style=\"#{cell_style}\">\
|
|
111
113
|
<a href=\"#{specifications_path}#{up_link_doc_name}/#{up_link_doc_name}.html##{@up_link_ids[0]}\" \
|
|
112
|
-
class=\"
|
|
114
|
+
class=\"#{link_class(@up_link_ids[0])}\" title=\"#{link_title(@up_link_ids[0], 'Linked to')}\">#{@up_link_ids[0]}</a></td>\n"
|
|
113
115
|
else
|
|
114
|
-
s += "\t\t<td class=\"item_id\" style=\"
|
|
116
|
+
s += "\t\t<td class=\"item_id\" style=\"#{cell_style}\">"
|
|
115
117
|
s += "<div id=\"COV_#{@parent_row.id}\" style=\"display: block;\">"
|
|
116
118
|
s += "<a href=\"#\" onclick=\"coverageLink_OnClick(this.parentElement); return false;\" \
|
|
117
119
|
class=\"external\" title=\"Number of verified items\">#{@up_link_ids.length}</a>"
|
|
@@ -122,7 +124,7 @@ class TestStepReferenceColumn < ControlledTableColumn
|
|
|
122
124
|
up_link_doc_name = tmp[1].downcase
|
|
123
125
|
end
|
|
124
126
|
s += "\t\t\t<a href=\"#{specifications_path}#{up_link_doc_name}/#{up_link_doc_name}.html##{lnk}\" \
|
|
125
|
-
class=\"
|
|
127
|
+
class=\"#{link_class(lnk)}\" title=\"#{link_title(lnk, 'Verifies')}\">#{lnk}</a>\n<br>"
|
|
126
128
|
end
|
|
127
129
|
s += '</div>'
|
|
128
130
|
s += "</td>\n"
|
|
@@ -131,6 +133,23 @@ class TestStepReferenceColumn < ControlledTableColumn
|
|
|
131
133
|
"\t\t<td style=\"text-align: center;\"></td>\n\r"
|
|
132
134
|
end
|
|
133
135
|
end
|
|
136
|
+
|
|
137
|
+
# An uplink to a paragraph missing from an existing specification, per the
|
|
138
|
+
# owning document's wrong-links collection (ENH-225). The cell renders it
|
|
139
|
+
# with the wrong-links red background and the broken-link style, keeping
|
|
140
|
+
# the link to the target document clickable.
|
|
141
|
+
def dangling?(link_id)
|
|
142
|
+
doc = @parent_row.parent_doc
|
|
143
|
+
doc.respond_to?(:wrong_links_hash) && doc.wrong_links_hash.key?(link_id)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def link_class(link_id)
|
|
147
|
+
dangling?(link_id) ? 'external broken_link' : 'external'
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def link_title(link_id, resolved_title)
|
|
151
|
+
dangling?(link_id) ? 'Linked item does not exist' : resolved_title
|
|
152
|
+
end
|
|
134
153
|
end
|
|
135
154
|
|
|
136
155
|
class ControlledTable < DocItem
|
|
@@ -6,7 +6,7 @@ class BaseDocument
|
|
|
6
6
|
attr_accessor :title, :id, :dom, :headings, :output_rel_path
|
|
7
7
|
|
|
8
8
|
class << self
|
|
9
|
-
attr_accessor :show_decisions_link, :show_risks_link
|
|
9
|
+
attr_accessor :show_decisions_link, :show_risks_link, :font_size
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def initialize
|
|
@@ -55,6 +55,7 @@ class BaseDocument
|
|
|
55
55
|
file.puts s.gsub! '{{DOCUMENT_TITLE}}', @title
|
|
56
56
|
elsif s.include?('{{STYLES_AND_SCRIPTS}}')
|
|
57
57
|
file.puts "<link rel=\"stylesheet\" href=\"#{rel_to('css/main.css')}\">"
|
|
58
|
+
file.puts font_size_style if BaseDocument.font_size
|
|
58
59
|
file.puts "<script src=\"#{rel_to('scripts/main.js')}\"></script>"
|
|
59
60
|
if @id == 'index'
|
|
60
61
|
file.puts "<script type=\"module\" src=\"#{rel_to('scripts/orama_search.js')}\"></script>"
|
|
@@ -63,11 +64,7 @@ class BaseDocument
|
|
|
63
64
|
file.puts '<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>'
|
|
64
65
|
end
|
|
65
66
|
elsif s.include?('{{HOME_BUTTON}}')
|
|
66
|
-
|
|
67
|
-
file.puts home_link(rel_to('index.html'))
|
|
68
|
-
else
|
|
69
|
-
file.puts index_link(rel_to('index.html'))
|
|
70
|
-
end
|
|
67
|
+
file.puts index_link(rel_to('index.html'))
|
|
71
68
|
file.puts decisions_link(rel_to('decisions/overview.html')) if BaseDocument.show_decisions_link
|
|
72
69
|
file.puts risks_link(rel_to('risks/overview.html')) if BaseDocument.show_risks_link
|
|
73
70
|
elsif s.include?('{{GEM_VERSION}}')
|
|
@@ -89,14 +86,19 @@ class BaseDocument
|
|
|
89
86
|
%(<a id="risks_menu_item" href="#{href}">#{icon} Risks</a>)
|
|
90
87
|
end
|
|
91
88
|
|
|
89
|
+
# The Documents item (ADR-223): the same link on every page, the Index page
|
|
90
|
+
# included, where it self-links — no Home variant. The element id stays
|
|
91
|
+
# index_menu_item; the label is presentation, the id is an interface.
|
|
92
92
|
def index_link(href)
|
|
93
|
-
icon = '<span><i class="fa fa-
|
|
94
|
-
%(<a id="index_menu_item" href="#{href}">#{icon}
|
|
93
|
+
icon = '<span><i class="fa fa-home" aria-hidden="true"></i></span>'
|
|
94
|
+
%(<a id="index_menu_item" href="#{href}">#{icon} Documents</a>)
|
|
95
95
|
end
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
# The inline override carrying the project.yml font_size (ADR-224). Emitted
|
|
98
|
+
# after the main.css link only when the setting exists, so unconfigured
|
|
99
|
+
# projects render exactly as before.
|
|
100
|
+
def font_size_style
|
|
101
|
+
"<style>:root { --almirah-font-size: #{BaseDocument.font_size}px; }</style>"
|
|
100
102
|
end
|
|
101
103
|
|
|
102
104
|
# Relative URL from this page to a target path under the build root.
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
require_relative 'persistent_document'
|
|
2
2
|
|
|
3
3
|
class Protocol < PersistentDocument
|
|
4
|
-
attr_accessor :specifications_path
|
|
4
|
+
attr_accessor :specifications_path, :wrong_links_hash
|
|
5
5
|
|
|
6
6
|
def initialize(fele_path)
|
|
7
7
|
super
|
|
8
8
|
@id = File.basename(fele_path, File.extname(fele_path)).downcase
|
|
9
9
|
@specifications_path = './../../../specifications/'
|
|
10
|
+
# The linker records dangling Req-IDs here as for every other linked
|
|
11
|
+
# document type (ISSUE-226); without it a dangling reference crashed the build.
|
|
12
|
+
@wrong_links_hash = {}
|
|
10
13
|
end
|
|
11
14
|
|
|
12
15
|
def to_html(nav_pane, output_file_path)
|
|
@@ -61,8 +61,8 @@ class RisksOverview < BaseDocument
|
|
|
61
61
|
s += "\t\t<td class=\"item_text\" style='padding: 5px;'>\
|
|
62
62
|
<a name=\"#{name}\" id=\"#{name}\" href=\"./#{name}/overview.html\" class=\"external\" \
|
|
63
63
|
title=\"Risk Registry\">#{registry_title(name)}</a></td>\n"
|
|
64
|
-
s += "\t\t<td class=\"item_rpn\">#{records.length}</td>\n"
|
|
65
|
-
s += "\t\t<td class=\"item_rpn\">#{open_count(records)}</td>\n"
|
|
64
|
+
s += "\t\t<td class=\"item_rpn\" style='width: 7%;'>#{records.length}</td>\n"
|
|
65
|
+
s += "\t\t<td class=\"item_rpn\" style='width: 7%;'>#{open_count(records)}</td>\n"
|
|
66
66
|
s += render_highest_cell(values, group)
|
|
67
67
|
s += render_average_cell(values)
|
|
68
68
|
s + "\t</tr>\n"
|
|
@@ -86,17 +86,17 @@ title=\"Risk Registry\">#{registry_title(name)}</a></td>\n"
|
|
|
86
86
|
# The worst risk's verdict carries up: the cell keeps the leading group's
|
|
87
87
|
# threshold colouring. Blank without a group or computable values.
|
|
88
88
|
def render_highest_cell(values, group)
|
|
89
|
-
return "\t\t<td class=\"item_rpn\"></td>\n" if values.empty?
|
|
89
|
+
return "\t\t<td class=\"item_rpn\" style='width: 7%;'></td>\n" if values.empty?
|
|
90
90
|
|
|
91
91
|
highest = values.max
|
|
92
92
|
classes = ['item_rpn', rpn_threshold_class(highest, group)].compact.join(' ')
|
|
93
|
-
"\t\t<td class=\"#{classes}\">#{format_rpn(highest)}</td>\n"
|
|
93
|
+
"\t\t<td class=\"#{classes}\" style='width: 7%;'>#{format_rpn(highest)}</td>\n"
|
|
94
94
|
end
|
|
95
95
|
|
|
96
96
|
def render_average_cell(values)
|
|
97
|
-
return "\t\t<td class=\"item_rpn\"></td>\n" if values.empty?
|
|
97
|
+
return "\t\t<td class=\"item_rpn\" style='width: 7%;'></td>\n" if values.empty?
|
|
98
98
|
|
|
99
99
|
average = (values.sum.to_f / values.length).round(1)
|
|
100
|
-
"\t\t<td class=\"item_rpn\">#{format_rpn(average)}</td>\n"
|
|
100
|
+
"\t\t<td class=\"item_rpn\" style='width: 7%;'>#{format_rpn(average)}</td>\n"
|
|
101
101
|
end
|
|
102
102
|
end
|
|
@@ -94,9 +94,10 @@ class SourceFile < PersistentDocument
|
|
|
94
94
|
file.puts s.gsub! '{{DOCUMENT_TITLE}}', @title
|
|
95
95
|
elsif s.include?('{{STYLES_AND_SCRIPTS}}')
|
|
96
96
|
file.puts "<link rel=\"stylesheet\" href=\"#{css_path}\">"
|
|
97
|
+
file.puts font_size_style if BaseDocument.font_size
|
|
97
98
|
file.puts "<script src=\"#{js_path}\"></script>"
|
|
98
99
|
elsif s.include?('{{HOME_BUTTON}}')
|
|
99
|
-
file.puts "<a id=\"index_menu_item\" href=\"#{index_path}\"><span><i class=\"fa fa-
|
|
100
|
+
file.puts "<a id=\"index_menu_item\" href=\"#{index_path}\"><span><i class=\"fa fa-home\" aria-hidden=\"true\"></i></span> Documents</a>"
|
|
100
101
|
elsif s.include?('{{GEM_VERSION}}')
|
|
101
102
|
file.puts "(#{Gem.loaded_specs['Almirah'].version.version})"
|
|
102
103
|
else
|
data/lib/almirah/project.rb
CHANGED
|
@@ -18,6 +18,7 @@ class Project
|
|
|
18
18
|
def initialize(configuration)
|
|
19
19
|
@configuration = configuration
|
|
20
20
|
@project_data = ProjectData.new
|
|
21
|
+
BaseDocument.font_size = @configuration.get_font_size
|
|
21
22
|
|
|
22
23
|
@index = nil
|
|
23
24
|
@project = self
|
|
@@ -59,6 +60,7 @@ class Project
|
|
|
59
60
|
render_all_protocols
|
|
60
61
|
render_all_source_files
|
|
61
62
|
render_all_specifications(@project_data.implementation_matrices) # intentionally after source file rendering
|
|
63
|
+
copy_decision_and_risk_images
|
|
62
64
|
render_decisions_overview
|
|
63
65
|
render_all_decisions
|
|
64
66
|
render_all_risk_records
|
|
@@ -90,6 +92,7 @@ class Project
|
|
|
90
92
|
render_all_protocols
|
|
91
93
|
render_all_source_files
|
|
92
94
|
render_all_specifications(@project_data.implementation_matrices) # intentionally after source file rendering
|
|
95
|
+
copy_decision_and_risk_images
|
|
93
96
|
render_decisions_overview
|
|
94
97
|
render_all_decisions
|
|
95
98
|
render_all_risk_records
|
|
@@ -473,6 +476,25 @@ class Project
|
|
|
473
476
|
end
|
|
474
477
|
end
|
|
475
478
|
|
|
479
|
+
# Every folder named img under decisions/ and risks/ is copied to the same
|
|
480
|
+
# relative location under build/ (ADR-227, SRS-176), so relative image
|
|
481
|
+
# references in decision records, risk records, and registry prefaces
|
|
482
|
+
# resolve in the rendered HTML. Folder-based rather than doc-id-based like
|
|
483
|
+
# the specification and protocol copies, because these records share their
|
|
484
|
+
# release and registry folders.
|
|
485
|
+
def copy_decision_and_risk_images
|
|
486
|
+
root = @configuration.project_root_directory
|
|
487
|
+
%w[decisions risks].each do |subroot|
|
|
488
|
+
Dir.glob("#{root}/#{subroot}/**/img").each do |src|
|
|
489
|
+
next unless File.directory?(src)
|
|
490
|
+
|
|
491
|
+
dst = "#{root}/build/#{src.sub("#{root}/", '')}"
|
|
492
|
+
FileUtils.mkdir_p(File.dirname(dst))
|
|
493
|
+
FileUtils.copy_entry(src, dst)
|
|
494
|
+
end
|
|
495
|
+
end
|
|
496
|
+
end
|
|
497
|
+
|
|
476
498
|
def render_all_source_files
|
|
477
499
|
path = @configuration.project_root_directory
|
|
478
500
|
FileUtils.mkdir_p("#{path}/build/source_files")
|
|
@@ -29,6 +29,13 @@ class ProjectConfiguration
|
|
|
29
29
|
[]
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
# The optional base text size in pixels (ADR-224), from the top-level
|
|
33
|
+
# font_size: number. nil when absent or not a positive number.
|
|
34
|
+
def get_font_size
|
|
35
|
+
value = @parameters.is_a?(Hash) ? @parameters['font_size'] : nil
|
|
36
|
+
value.is_a?(Numeric) && value.positive? ? value : nil
|
|
37
|
+
end
|
|
38
|
+
|
|
32
39
|
# The ordered register-column list for a risk registry folder (ADR-216),
|
|
33
40
|
# read from the risks: root — a list of { folder:, columns: } entries.
|
|
34
41
|
# nil when the registry carries no configuration; such a registry renders
|
|
@@ -5,7 +5,10 @@ html {
|
|
|
5
5
|
}
|
|
6
6
|
body {
|
|
7
7
|
font-family: Verdana, sans-serif;
|
|
8
|
-
|
|
8
|
+
/* Base text size, overridable per project via font_size in project.yml
|
|
9
|
+
(ADR-224). Headings, top menu and footer are pinned in px below so the
|
|
10
|
+
setting scales only the reading text and the navigation pane. */
|
|
11
|
+
font-size: var(--almirah-font-size, 12px);
|
|
9
12
|
color: #333;
|
|
10
13
|
margin: 0;
|
|
11
14
|
padding: 0;
|
|
@@ -30,24 +33,24 @@ body {
|
|
|
30
33
|
margin: 0 0 10px 0;
|
|
31
34
|
}
|
|
32
35
|
h1 {
|
|
33
|
-
font-size:
|
|
36
|
+
font-size: 24px;
|
|
34
37
|
}
|
|
35
38
|
h2 {
|
|
36
|
-
font-size:
|
|
39
|
+
font-size: 21.6px;
|
|
37
40
|
}
|
|
38
41
|
h3 {
|
|
39
|
-
font-size:
|
|
42
|
+
font-size: 18px;
|
|
40
43
|
}
|
|
41
44
|
h4 {
|
|
42
|
-
font-size:
|
|
45
|
+
font-size: 14.4px;
|
|
43
46
|
border: none;
|
|
44
47
|
font-weight: bold;
|
|
45
48
|
}
|
|
46
49
|
h5 {
|
|
47
|
-
font-size:
|
|
50
|
+
font-size: 12px;
|
|
48
51
|
}
|
|
49
52
|
h6 {
|
|
50
|
-
font-size:
|
|
53
|
+
font-size: 12px; color: #8e8e8e;
|
|
51
54
|
}
|
|
52
55
|
a.heading_anchor {
|
|
53
56
|
display: none;
|
|
@@ -260,7 +263,7 @@ img{
|
|
|
260
263
|
text-align: center;
|
|
261
264
|
padding: 4px 6px;
|
|
262
265
|
text-decoration: none;
|
|
263
|
-
font-size:
|
|
266
|
+
font-size: 18px;
|
|
264
267
|
font-family: "Trebuchet MS", Verdana, sans-serif;
|
|
265
268
|
}
|
|
266
269
|
#top_nav a.split {
|
|
@@ -269,7 +272,7 @@ img{
|
|
|
269
272
|
text-align: center;
|
|
270
273
|
padding: 4px 6px;
|
|
271
274
|
text-decoration: none;
|
|
272
|
-
font-size:
|
|
275
|
+
font-size: 18px;
|
|
273
276
|
font-family: "Trebuchet MS", Verdana, sans-serif;
|
|
274
277
|
}
|
|
275
278
|
#top_nav a:hover {
|
|
@@ -343,7 +346,7 @@ img{
|
|
|
343
346
|
#footer {
|
|
344
347
|
clear: both;
|
|
345
348
|
border-top: 1px solid #bbb;
|
|
346
|
-
font-size:
|
|
349
|
+
font-size: 10.8px;
|
|
347
350
|
color: #aaa;
|
|
348
351
|
padding: 5px;
|
|
349
352
|
text-align:center;
|