Skip to content

Commit b9c5676

Browse files
authored
NeTEx: Documentation en ligne des règles France (#5461)
1 parent b47a7c8 commit b9c5676

12 files changed

Lines changed: 279 additions & 87 deletions

File tree

apps/transport/client/stylesheets/components/_validation.scss

Lines changed: 58 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -124,60 +124,76 @@ details > code {
124124
}
125125
}
126126

127-
table.netex_generic_issue, table.netex_xsd_schema {
128-
tr.message td {
129-
vertical-align: top;
127+
.download-button {
128+
text-decoration: none;
129+
&:hover {
130+
background-color: unset;
130131
}
131132
}
132133

133-
table.netex_generic_issue {
134-
th, td {
135-
&:nth-child(1) {
136-
width: 60%;
137-
}
138-
&:nth-child(3) {
139-
width: 10%;
134+
.netex {
135+
dialog.inline-help {
136+
max-width: 90%;
137+
width: 80ch;
138+
max-height: 90%;
139+
overflow: scrollable;
140+
overscroll-behavior: contain;
141+
142+
h5 { margin-block: 0 1em; }
143+
h6 { margin-block: 2em 1em; }
144+
.header_with_action_bar + h6 { margin-top: 0; }
145+
.fa-close { padding: unset }
146+
code { font-size: 0.75em; }
147+
}
148+
149+
table.netex_generic_issue, table.netex_xsd_schema {
150+
tr.message td {
151+
vertical-align: top;
140152
}
141153
}
142-
}
143154

144-
table.netex_xsd_schema {
145-
tr, td {
146-
&:nth-child(1) {
147-
text-align: right;
155+
table.netex_xsd_schema {
156+
tr, td {
157+
&:nth-child(1) {
158+
text-align: right;
159+
}
148160
}
149161
}
150-
}
151162

152-
table.netex_generic_issue tr.debug:hover {
153-
background: revert;
154-
}
163+
table.netex_generic_issue {
164+
th, td {
165+
&:nth-child(1) {
166+
width: 60%;
167+
}
168+
&:nth-child(3) {
169+
width: 10%;
170+
}
171+
}
155172

156-
table.netex_generic_issue tr.debug td {
157-
border-top: none;
158-
padding-top: 0;
159-
}
173+
tr.debug {
174+
&:hover {
175+
background: revert;
176+
}
160177

161-
table.netex_generic_issue tr.debug td summary {
162-
cursor: pointer;
163-
}
178+
td {
179+
border-top: none;
180+
padding-top: 0;
164181

165-
table.netex_generic_issue tr.debug td pre {
166-
margin-block: 0;
167-
}
182+
summary {
183+
cursor: pointer;
184+
}
168185

169-
table.netex_generic_issue tr.debug td code {
170-
width: 100%;
171-
}
186+
pre {
187+
margin-block: 0;
188+
}
172189

173-
.download-button {
174-
text-decoration: none;
175-
&:hover {
176-
background-color: unset;
190+
code {
191+
width: 100%;
192+
}
193+
}
194+
}
177195
}
178-
}
179196

180-
.netex {
181197
#download-popup {
182198
max-width: 60ch;
183199

@@ -278,6 +294,10 @@ table.netex_generic_issue tr.debug td code {
278294
--taint: var(--orange);
279295
}
280296
}
297+
298+
button[popovertarget="french-profile-rules"] {
299+
margin-left: 0.5em;
300+
}
281301
}
282302

283303
blockquote {

apps/transport/lib/netex/chouette_valid_ruleset_generator.ex

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ defmodule Transport.NeTEx.ChouetteValidRulesetGenerator do
99
- it can keep track of source documentation for each rule to help maintain a user friendly interface
1010
"""
1111

12+
use Gettext, backend: TransportWeb.Gettext
13+
1214
def mandatory_attributes(parent, names, documentation_title, documentation_url) do
1315
%{
1416
type: :mandatory_attributes,
@@ -31,27 +33,42 @@ defmodule Transport.NeTEx.ChouetteValidRulesetGenerator do
3133
Enum.map(ruleset, &process_rule_context(sub_profile, &1))
3234
end
3335

34-
def document_ruleset(ruleset, device \\ :stdio) do
35-
Enum.each(ruleset, &document_sub_profile(&1, device))
36+
def document_ruleset(ruleset, device \\ :stdio, markdown_options \\ []) do
37+
Enum.each(ruleset, &document_sub_profile(&1, device, markdown_options))
3638
end
3739

38-
def document_sub_profile(%{title: title, ruleset: ruleset}, device) do
39-
IO.puts(device, "## #{title}")
40-
IO.puts(device, "")
40+
def document_sub_profile(%{title: title, ruleset: ruleset}, device, options) do
41+
header_level = Keyword.get(options, :header_level, 1)
4142

42-
ruleset
43-
|> Enum.each(fn rule_context ->
44-
IO.puts(device, "In [#{rule_context.documentation_link.title}](#{rule_context.documentation_link.url}):")
43+
if not Enum.empty?(ruleset) do
44+
IO.puts(device, header(header_level, dgettext("netex-documentation", "Sub-profile “%{title}”", title: title)))
4545
IO.puts(device, "")
4646

47-
for name <- rule_context.names do
48-
IO.puts(device, "- `//#{rule_context.parent}/#{name}` : `0:1` -> `1:1`")
49-
end
47+
ruleset
48+
|> Enum.each(fn rule_context ->
49+
IO.puts(device, dgettext("netex-documentation", "Section [%{title}](%{url}):", rule_context.documentation_link))
50+
IO.puts(device, "")
51+
52+
for name <- rule_context.names do
53+
IO.puts(
54+
device,
55+
"- #{dgettext("netex-documentation", "The element `%{name}` is required.", name: "#{rule_context.parent}/#{name}")}"
56+
)
57+
end
58+
59+
IO.puts(device, "")
60+
end)
61+
end
62+
end
5063

51-
IO.puts(device, "")
52-
end)
64+
defp header(level, text) when level in 1..6 do
65+
symbol = "######" |> String.slice(0, level)
66+
67+
"#{symbol} #{text}"
5368
end
5469

70+
defp header(_level, text), do: text
71+
5572
def process_rule_context(sub_profile, %{type: :mandatory_attributes, parent: parent, names: names}) do
5673
%{
5774
rule_context: "resource/kind_of",

apps/transport/lib/netex/french_profile.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ defmodule Transport.NeTEx.FrenchProfile do
1313

1414
defdelegate slug, to: Latest
1515
defdelegate ruleset(device), to: Latest
16-
defdelegate markdown(device), to: Latest
16+
defdelegate markdown(device, markdown_options), to: Latest
1717
end

apps/transport/lib/netex/french_profile/v1.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ defmodule Transport.NeTEx.FrenchProfile.V1 do
1717
definition() |> encode_ruleset(device)
1818
end
1919

20-
def markdown(device \\ :stdio) do
21-
definition() |> document_ruleset(device)
20+
def markdown(device \\ :stdio, markdown_options \\ []) do
21+
definition() |> document_ruleset(device, markdown_options)
2222
end
2323

2424
defp definition do

apps/transport/lib/netex/french_profile/v2.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ defmodule Transport.NeTEx.FrenchProfile.V2 do
1919
definition() |> encode_ruleset(device)
2020
end
2121

22-
def markdown(device \\ :stdio) do
23-
definition() |> document_ruleset(device)
22+
def markdown(device \\ :stdio, markdown_options \\ []) do
23+
definition() |> document_ruleset(device, markdown_options)
2424
end
2525

2626
defp definition do

apps/transport/lib/transport_web/views/netex_report_components.ex

Lines changed: 90 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ defmodule TransportWeb.NeTExReportComponents do
105105
errors={errors}
106106
validation_report_url={@validation_report_url}
107107
pagination={@pagination}
108+
results_adapter={@results_adapter}
108109
/>
109110
"""
110111
end
@@ -138,41 +139,55 @@ defmodule TransportWeb.NeTExReportComponents do
138139
end
139140

140141
defp netex_validation_selected_category(
141-
%{conn: _, compliance_check: _, current_category: _, errors: _, validation_report_url: _, pagination: _} =
142+
%{
143+
conn: _,
144+
compliance_check: _,
145+
current_category: _,
146+
errors: _,
147+
validation_report_url: _,
148+
pagination: _,
149+
results_adapter: _
150+
} =
142151
assigns
143152
) do
144153
~H"""
145154
<% locale = get_session(@conn, :locale) %>
146155
<div class="selected-category">
147-
<.netex_category_description category={@current_category} compliance_check={@compliance_check} conn={@conn} />
156+
<.netex_category_description
157+
category={@current_category}
158+
compliance_check={@compliance_check}
159+
conn={@conn}
160+
results_adapter={@results_adapter}
161+
/>
148162
<.netex_category_comment count={Enum.count(@errors)} category={@current_category} />
149163
150-
<div :if={@current_category == "xsd-schema" and Enum.count(@errors) > 0} id="issues-list">
151-
<p>
152-
{dgettext(
153-
"validations-explanations",
154-
"Here is a summary of XSD validation errors. Full detail of those errors is available in the <a href=\"%{validation_report_url}\" target=\"_blank\">CSV report</a>. Those errors are produced by <a href=\"https://gnome.pages.gitlab.gnome.org/libxml2/xmllint.html\" target=\"_blank\">xmllint</a>.",
155-
validation_report_url: @validation_report_url
156-
)
157-
|> raw()}
158-
</p>
159-
<.non_translated_messages locale={locale} />
160-
<table class="table netex_xsd_schema">
161-
<tr>
162-
<th>{dgettext("validations-explanations", "Occurrences")}</th>
163-
<th>{dgettext("validations-explanations", "Message")}</th>
164-
</tr>
165-
166-
<tr :for={xsd_error <- @errors} class="message">
167-
<td>{Helpers.format_number(xsd_error["counts"], locale: locale)}</td>
168-
<td lang="en">{xsd_error["message"]}</td>
169-
</tr>
170-
</table>
171-
</div>
172-
<div :if={@current_category != "xsd-schema" and Enum.count(@errors) > 0} id="issues-list">
173-
<.non_translated_messages locale={locale} />
174-
<.netex_generic_issues issues={@errors} />
175-
{@pagination}
164+
<div :if={Enum.count(@errors) > 0} id="issues-list">
165+
<%= if @current_category == "xsd-schema" do %>
166+
<p>
167+
{dgettext(
168+
"validations-explanations",
169+
"Here is a summary of XSD validation errors. Full detail of those errors is available in the <a href=\"%{validation_report_url}\" target=\"_blank\">CSV report</a>. Those errors are produced by <a href=\"https://gnome.pages.gitlab.gnome.org/libxml2/xmllint.html\" target=\"_blank\">xmllint</a>.",
170+
validation_report_url: @validation_report_url
171+
)
172+
|> raw()}
173+
</p>
174+
<.non_translated_messages locale={locale} />
175+
<table class="table netex_xsd_schema">
176+
<tr>
177+
<th>{dgettext("validations-explanations", "Occurrences")}</th>
178+
<th>{dgettext("validations-explanations", "Message")}</th>
179+
</tr>
180+
181+
<tr :for={xsd_error <- @errors} class="message">
182+
<td>{Helpers.format_number(xsd_error["counts"], locale: locale)}</td>
183+
<td lang="en">{xsd_error["message"]}</td>
184+
</tr>
185+
</table>
186+
<% else %>
187+
<.non_translated_messages locale={locale} />
188+
<.netex_generic_issues issues={@errors} />
189+
{@pagination}
190+
<% end %>
176191
</div>
177192
</div>
178193
"""
@@ -259,11 +274,33 @@ defmodule TransportWeb.NeTExReportComponents do
259274
"""
260275
end
261276

262-
defp netex_category_tooltip(%{category: _, compliance_check: _} = assigns) do
277+
defp with_string(proc) do
278+
{:ok, device} = StringIO.open("")
279+
280+
proc.(device)
281+
282+
StringIO.flush(device)
283+
end
284+
285+
defp netex_category_tooltip(%{category: _, compliance_check: _, results_adapter: _, conn: _} = assigns) do
263286
~H"""
287+
<% french_profile = @results_adapter.french_profile() %>
264288
<p :if={@category == "french-profile"}>
265289
<.info_icon /> {french_profile_comment(@compliance_check)}
290+
<button :if={french_profile} class="button-outline small secondary" popovertarget="french-profile-rules">
291+
<i class="fa fa-circle-question" aria-hidden="true"></i> {dgettext("validations", "Learn more")}
292+
</button>
266293
</p>
294+
<dialog :if={french_profile} id="french-profile-rules" popover class="panel inline-help">
295+
<div class="header_with_action_bar">
296+
<h5>{dgettext("validations", "List of French Profile rules currently checked")}</h5>
297+
<button popovertarget="french-profile-rules" popovertargetaction="hide" class="small secondary">
298+
<i class="fa fa-close"></i>
299+
</button>
300+
</div>
301+
<% markdown = with_string(&french_profile.markdown(&1, header_level: 6)) %>
302+
{markdown_to_safe_html!(markdown)}
303+
</dialog>
267304
"""
268305
end
269306

@@ -272,6 +309,23 @@ defmodule TransportWeb.NeTExReportComponents do
272309
"""
273310
end
274311

312+
defp markdown_to_safe_html!(markdown) do
313+
case TransportWeb.MarkdownHandler.markdown_to_safe_html!(markdown) do
314+
{:safe, safe} -> {:safe, update_links_target(safe)}
315+
otherwise -> otherwise
316+
end
317+
end
318+
319+
defp update_links_target(html) do
320+
html
321+
|> Floki.parse_fragment!()
322+
|> Floki.traverse_and_update(fn
323+
{"a", attrs, children} -> {"a", [{"target", "_blank"} | attrs], children}
324+
other -> other
325+
end)
326+
|> Floki.raw_html()
327+
end
328+
275329
defp french_profile_comment(:none), do: dgettext("validations", "netex-french-profile-no-compliance") |> raw()
276330
defp french_profile_comment(:partial), do: dgettext("validations", "netex-french-profile-partial-compliance") |> raw()
277331
defp french_profile_comment(:good_enough), do: ""
@@ -309,14 +363,19 @@ defmodule TransportWeb.NeTExReportComponents do
309363
Map.reject(query_params, fn {_, v} -> is_nil(v) end)
310364
end
311365

312-
defp netex_category_description(%{category: _, compliance_check: _, conn: _} = assigns) do
366+
defp netex_category_description(%{category: _, compliance_check: _, conn: _, results_adapter: _} = assigns) do
313367
~H"""
314368
<% url = netex_link_to_category(@conn, "french-profile") %>
315369
<% description = netex_category_description_html(@category, url) %>
316370
<p :if={description}>
317371
{raw(description)}
318372
</p>
319-
<.netex_category_tooltip category={@category} compliance_check={@compliance_check} />
373+
<.netex_category_tooltip
374+
category={@category}
375+
compliance_check={@compliance_check}
376+
results_adapter={@results_adapter}
377+
conn={@conn}
378+
/>
320379
"""
321380
end
322381

0 commit comments

Comments
 (0)