feat(attestation): better presentation of repetition champs

This commit is contained in:
Colin Darie 2024-07-25 11:42:50 +02:00
parent 09581ad028
commit c9956c4881
No known key found for this signature in database
GPG key ID: 4FB865FDBCA4BCC4
8 changed files with 244 additions and 10 deletions

View file

@ -178,4 +178,14 @@
bottom: 0; bottom: 0;
} }
} }
.tdc-repetition li {
margin-bottom: 5mm;
dl {
display: grid;
grid-template-columns: auto 1fr;
gap: 1mm 5mm;
}
}
} }

View file

@ -0,0 +1,58 @@
# frozen_string_literal: true
class ChampPresentations::RepetitionPresentation
attr_reader :libelle
attr_reader :rows
def initialize(libelle, rows)
@libelle = libelle
@rows = rows
end
def to_s
([libelle] + rows.map do |champs|
champs.map do |champ|
"#{champ.libelle} : #{champ}"
end.join("\n")
end).join("\n\n")
end
def to_tiptap_node
{
type: 'orderedList',
attrs: { class: 'tdc-repetition' },
content: rows.map do |champs|
{
type: 'listItem',
content: [
{
type: 'descriptionList',
content: champs.map do |champ|
[
{
type: 'descriptionTerm',
content: [
{
type: 'text',
text: champ.libelle
}
]
},
{
type: 'descriptionDetails',
content: [
{
type: 'text',
text: champ.to_s
}
]
}
]
end.flatten
}
]
}
end
}
end
end

View file

@ -44,14 +44,6 @@ class Champs::RepetitionChamp < Champ
# The user cannot enter any information here so it doesnt make much sense to search # The user cannot enter any information here so it doesnt make much sense to search
end end
def for_tag(path = :value)
([libelle] + rows.map do |champs|
champs.map do |champ|
"#{champ.libelle} : #{champ}"
end.join("\n")
end).join("\n\n")
end
def rows_for_export def rows_for_export
row_ids.map.with_index(1) do |row_id, index| row_ids.map.with_index(1) do |row_id, index|
Champs::RepetitionChamp::Row.new(index:, row_id:, dossier:) Champs::RepetitionChamp::Row.new(index:, row_id:, dossier:)

View file

@ -1,6 +1,13 @@
# frozen_string_literal: true # frozen_string_literal: true
class TypesDeChamp::RepetitionTypeDeChamp < TypesDeChamp::TypeDeChampBase class TypesDeChamp::RepetitionTypeDeChamp < TypesDeChamp::TypeDeChampBase
def self.champ_value_for_tag(champ, path = :value)
return nil if path != :value
return champ_default_value if champ.rows.blank?
ChampPresentations::RepetitionPresentation.new(champ.libelle, champ.rows)
end
def estimated_fill_duration(revision) def estimated_fill_duration(revision)
estimated_rows_in_repetition = 2.5 estimated_rows_in_repetition = 2.5

View file

@ -79,10 +79,16 @@ class TiptapService
"<h#{hlevel}#{body_start_mark}#{text_align(attrs)}>#{children(content, substitutions, level + 1)}</h#{hlevel}>" "<h#{hlevel}#{body_start_mark}#{text_align(attrs)}>#{children(content, substitutions, level + 1)}</h#{hlevel}>"
in type: 'bulletList', content: in type: 'bulletList', content:
"<ul>#{children(content, substitutions, level + 1)}</ul>" "<ul>#{children(content, substitutions, level + 1)}</ul>"
in type: 'orderedList', content: in type: 'orderedList', content:, **rest
"<ol>#{children(content, substitutions, level + 1)}</ol>" "<ol#{class_list(rest[:attrs])}>#{children(content, substitutions, level + 1)}</ol>"
in type: 'listItem', content: in type: 'listItem', content:
"<li>#{children(content, substitutions, level + 1)}</li>" "<li>#{children(content, substitutions, level + 1)}</li>"
in type: 'descriptionList', content:
"<dl>#{children(content, substitutions, level + 1)}</dl>"
in type: 'descriptionTerm', content:
"<dt>#{children(content, substitutions, level + 1)}</dt>"
in type: 'descriptionDetails', content:
"<dd>#{children(content, substitutions, level + 1)}</dd>"
in type: 'text', text:, **rest in type: 'text', text:, **rest
if rest[:marks].present? if rest[:marks].present?
apply_marks(text, rest[:marks]) apply_marks(text, rest[:marks])
@ -115,6 +121,12 @@ class TiptapService
end end
end end
def class_list(attrs)
if attrs.present? && attrs[:class].present?
" class=\"#{attrs[:class]}\""
end
end
def apply_marks(text, marks) def apply_marks(text, marks)
marks.reduce(text) do |text, mark| marks.reduce(text) do |text, mark|
case mark case mark

View file

@ -0,0 +1,86 @@
# frozen_string_literal: true
describe ChampPresentations::RepetitionPresentation do
let(:libelle) { "Langages de programmation" }
let(:procedure) {
create(:procedure, types_de_champ_public: [
{
type: :repetition,
children: [
{ type: :text, libelle: "nom" },
{ type: :integer_number, libelle: "stars" }
]
}
])
}
let(:dossier) { create(:dossier, procedure:) }
before do
nom, stars = dossier.champs[0].rows.first
nom.update(value: "ruby")
stars.update(value: 5)
nom, stars = dossier.champs[0].add_row(dossier.procedure.active_revision)
nom.update(value: "rust")
stars.update(value: 4)
end
let(:representation) { described_class.new(libelle, dossier.champs[0].reload.rows) }
describe '#to_s' do
it 'returns a key-value representation' do
expect(representation.to_s).to eq(
<<~TXT.strip
Langages de programmation
nom : ruby
stars : 5
nom : rust
stars : 4
TXT
)
end
end
describe '#to_tiptap_node' do
it 'returns the correct HTML structure, without libelle' do
expected_node = {
type: "orderedList",
attrs: { class: "tdc-repetition" },
content: [
{
type: "listItem",
content: [
{
type: "descriptionList",
content: [
{ content: [{ text: "nom", type: "text" }], type: "descriptionTerm" },
{ content: [{ text: "ruby", type: "text" }], type: "descriptionDetails" },
{ content: [{ text: "stars", type: "text" }], type: "descriptionTerm" },
{ content: [{ text: "5", type: "text" }], type: "descriptionDetails" }
]
}
]
}, {
type: "listItem",
content: [
{
type: "descriptionList",
content: [
{ content: [{ text: "nom", type: "text" }], type: "descriptionTerm" },
{ content: [{ text: "rust", type: "text" }], type: "descriptionDetails" },
{ content: [{ text: "stars", type: "text" }], type: "descriptionTerm" },
{ content: [{ text: "4", type: "text" }], type: "descriptionDetails" }
]
}
]
}
]
}
expect(representation.to_tiptap_node).to eq(expected_node)
end
end
end

View file

@ -0,0 +1,35 @@
# frozen_string_literal: true
describe Champs::RepetitionChamp do
let(:procedure) {
create(:procedure,
types_de_champ_public: [
{
type: :repetition,
children: [{ type: :text, libelle: "Ext" }], libelle: "Languages"
}
])
}
let(:dossier) { create(:dossier, procedure:) }
let(:champ) { dossier.champs.first }
describe "#for_tag" do
before do
champ.rows[0][0].update(value: "rb")
end
it "can render as string" do
expect(champ.for_tag.to_s).to eq(
<<~TXT.strip
Languages
Ext : rb
TXT
)
end
it "as tiptap node" do
expect(champ.for_tag.to_tiptap_node).to include(type: 'orderedList')
end
end
end

View file

@ -201,6 +201,40 @@ RSpec.describe TiptapService do
expect(described_class.new.to_html(json, substitutions)).to eq("<h1>The Title</h1><p class=\"body-start\">First paragraph</p>") expect(described_class.new.to_html(json, substitutions)).to eq("<h1>The Title</h1><p class=\"body-start\">First paragraph</p>")
end end
end end
context 'ordered list with custom classes' do
let(:json) do
{
type: 'doc',
content: [
{
type: 'orderedList',
attrs: { class: "my-class" },
content: [
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [
{
type: 'text',
text: 'Item 1'
}
]
}
]
}
]
}
]
}
end
it "set class attribute" do
expect(described_class.new.to_html(json, substitutions)).to eq('<ol class="my-class"><li><p>Item 1</p></li></ol>')
end
end
end end
describe '#used_tags' do describe '#used_tags' do