Merge pull request #8117 from tchak/graphql-complete-demarche
feat(graphql): expose more information on demarche descriptor
This commit is contained in:
commit
357290acf7
48 changed files with 1759 additions and 92 deletions
|
@ -22,11 +22,15 @@ class API::V2::Context < GraphQL::Query::Context
|
||||||
Administrateur.find(self[:administrateur_id])
|
Administrateur.find(self[:administrateur_id])
|
||||||
end
|
end
|
||||||
|
|
||||||
def authorized_demarche?(demarche)
|
def authorized_demarche?(demarche, opendata: false)
|
||||||
if internal_use?
|
if internal_use?
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if opendata && demarche.opendata?
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
# We are caching authorization logic because it is called for each node
|
# We are caching authorization logic because it is called for each node
|
||||||
# of the requested graph and can be expensive. Context is reset per request so it is safe.
|
# of the requested graph and can be expensive. Context is reset per request so it is safe.
|
||||||
self[:authorized] ||= Hash.new do |hash, demarche_id|
|
self[:authorized] ||= Hash.new do |hash, demarche_id|
|
||||||
|
|
|
@ -75,7 +75,42 @@ class API::V2::Schema < GraphQL::Schema
|
||||||
Types::GeoAreas::ParcelleCadastraleType,
|
Types::GeoAreas::ParcelleCadastraleType,
|
||||||
Types::GeoAreas::SelectionUtilisateurType,
|
Types::GeoAreas::SelectionUtilisateurType,
|
||||||
Types::PersonneMoraleType,
|
Types::PersonneMoraleType,
|
||||||
Types::PersonnePhysiqueType
|
Types::PersonnePhysiqueType,
|
||||||
|
Types::Champs::Descriptor::AddressChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::AnnuaireEducationChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::CarteChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::CheckboxChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::CiviliteChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::CnafChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::CommuneChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::DateChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::DatetimeChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::DecimalNumberChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::DepartementChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::DgfipChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::DossierLinkChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::DropDownListChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::EmailChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::ExplicationChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::HeaderSectionChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::IbanChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::IntegerNumberChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::LinkedDropDownListChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::MesriChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::MultipleDropDownListChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::NumberChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::PaysChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::PhoneChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::PieceJustificativeChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::PoleEmploiChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::RegionChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::RepetitionChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::RNAChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::SiretChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::TextChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::TextareaChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::TitreIdentiteChampDescriptorType,
|
||||||
|
Types::Champs::Descriptor::YesNoChampDescriptorType
|
||||||
|
|
||||||
def self.unauthorized_object(error)
|
def self.unauthorized_object(error)
|
||||||
# Add a top-level error to the response instead of returning nil:
|
# Add a top-level error to the response instead of returning nil:
|
||||||
|
|
|
@ -50,7 +50,7 @@ class API::V2::StoredQuery
|
||||||
declarative
|
declarative
|
||||||
dateCreation
|
dateCreation
|
||||||
dateFermeture
|
dateFermeture
|
||||||
publishedRevision @include(if: $includeRevision) {
|
activeRevision @include(if: $includeRevision) {
|
||||||
...RevisionFragment
|
...RevisionFragment
|
||||||
}
|
}
|
||||||
groupeInstructeurs @include(if: $includeGroupeInstructeurs) {
|
groupeInstructeurs @include(if: $includeGroupeInstructeurs) {
|
||||||
|
@ -305,25 +305,65 @@ class API::V2::StoredQuery
|
||||||
datePublication
|
datePublication
|
||||||
champDescriptors {
|
champDescriptors {
|
||||||
...ChampDescriptorFragment
|
...ChampDescriptorFragment
|
||||||
|
... on RepetitionChampDescriptor {
|
||||||
champDescriptors {
|
champDescriptors {
|
||||||
...ChampDescriptorFragment
|
...ChampDescriptorFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
annotationDescriptors {
|
annotationDescriptors {
|
||||||
...ChampDescriptorFragment
|
...ChampDescriptorFragment
|
||||||
|
... on RepetitionChampDescriptor {
|
||||||
champDescriptors {
|
champDescriptors {
|
||||||
...ChampDescriptorFragment
|
...ChampDescriptorFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fragment ChampDescriptorFragment on ChampDescriptor {
|
fragment ChampDescriptorFragment on ChampDescriptor {
|
||||||
|
__typename
|
||||||
id
|
id
|
||||||
type
|
|
||||||
label
|
label
|
||||||
description
|
description
|
||||||
required
|
required
|
||||||
|
... on DropDownListChampDescriptor {
|
||||||
options
|
options
|
||||||
|
otherOption
|
||||||
|
}
|
||||||
|
... on MultipleDropDownListChampDescriptor {
|
||||||
|
options
|
||||||
|
}
|
||||||
|
... on LinkedDropDownListChampDescriptor {
|
||||||
|
options
|
||||||
|
}
|
||||||
|
... on PieceJustificativeChampDescriptor {
|
||||||
|
fileTemplate {
|
||||||
|
...FileFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on ExplicationChampDescriptor {
|
||||||
|
collapsibleExplanationEnabled
|
||||||
|
collapsibleExplanationText
|
||||||
|
}
|
||||||
|
... on PaysChampDescriptor {
|
||||||
|
options {
|
||||||
|
name
|
||||||
|
code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on RegionChampDescriptor {
|
||||||
|
options {
|
||||||
|
name
|
||||||
|
code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on DepartementChampDescriptor {
|
||||||
|
options {
|
||||||
|
name
|
||||||
|
code
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fragment AvisFragment on Avis {
|
fragment AvisFragment on Avis {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
module Extensions
|
module Extensions
|
||||||
class Attachment < GraphQL::Schema::FieldExtension
|
class Attachment < GraphQL::Schema::FieldExtension
|
||||||
attr_reader :attachment_assoc
|
attr_reader :attachment_assoc, :root
|
||||||
|
|
||||||
def apply
|
def apply
|
||||||
# Here we try to define the ActiveRecord association name:
|
# Here we try to define the ActiveRecord association name:
|
||||||
|
@ -18,13 +18,14 @@ module Extensions
|
||||||
attachment = field.original_name.to_s.sub(/_url$/, "")
|
attachment = field.original_name.to_s.sub(/_url$/, "")
|
||||||
"#{attachment}_attachment"
|
"#{attachment}_attachment"
|
||||||
end
|
end
|
||||||
|
@root = options&.dig(:root) || :object
|
||||||
end
|
end
|
||||||
|
|
||||||
# This method resolves (as it states) the field itself
|
# This method resolves (as it states) the field itself
|
||||||
# (it's the same as defining a method within a type)
|
# (it's the same as defining a method within a type)
|
||||||
def resolve(object:, **_rest)
|
def resolve(object:, **_rest)
|
||||||
Loaders::Association.for(
|
Loaders::Association.for(
|
||||||
object.object.class,
|
object.public_send(root).class,
|
||||||
attachment_assoc => :blob
|
attachment_assoc => :blob
|
||||||
).load(object.object)
|
).load(object.object)
|
||||||
end
|
end
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,7 @@
|
||||||
module Types
|
module Types
|
||||||
class ChampDescriptorType < Types::BaseObject
|
module ChampDescriptorType
|
||||||
|
include Types::BaseInterface
|
||||||
|
|
||||||
class TypeDeChampType < Types::BaseEnum
|
class TypeDeChampType < Types::BaseEnum
|
||||||
TypeDeChamp.type_champs.each do |symbol_name, string_name|
|
TypeDeChamp.type_champs.each do |symbol_name, string_name|
|
||||||
value(string_name,
|
value(string_name,
|
||||||
|
@ -9,24 +11,107 @@ module Types
|
||||||
end
|
end
|
||||||
|
|
||||||
global_id_field :id
|
global_id_field :id
|
||||||
field :type, TypeDeChampType, "Type de la valeur du champ.", null: false, method: :type_champ
|
|
||||||
field :label, String, "Libellé du champ.", null: false, method: :libelle
|
field :label, String, "Libellé du champ.", null: false, method: :libelle
|
||||||
field :description, String, "Description du champ.", null: true
|
field :description, String, "Description du champ.", null: true
|
||||||
field :required, Boolean, "Est-ce que le champ est obligatoire ?", null: false, method: :mandatory?
|
field :required, Boolean, "Est-ce que le champ est obligatoire ?", null: false, method: :mandatory?
|
||||||
|
|
||||||
field :champ_descriptors, [Types::ChampDescriptorType], "Description des champs d’un bloc répétable.", null: true
|
field :options, [String], "List des options d’un champ avec selection.", null: true, deprecation_reason: 'Utilisez le champ `DropDownListChampDescriptor.options` à la place.'
|
||||||
field :options, [String], "List des options d’un champ avec selection.", null: true
|
field :champ_descriptors, [Types::ChampDescriptorType], "Description des champs d’un bloc répétable.", null: true, deprecation_reason: 'Utilisez le champ `RepetitionChampDescriptor.champ_descriptors` à la place.'
|
||||||
|
field :type, TypeDeChampType, "Type de la valeur du champ.", null: false, method: :type_champ, deprecation_reason: 'Utilisez le champ `__typename` à la place.'
|
||||||
|
|
||||||
|
definition_methods do
|
||||||
|
def resolve_type(object, context)
|
||||||
|
case object.type_champ
|
||||||
|
when TypeDeChamp.type_champs.fetch(:text)
|
||||||
|
Types::Champs::Descriptor::TextChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:textarea)
|
||||||
|
Types::Champs::Descriptor::TextareaChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:date)
|
||||||
|
Types::Champs::Descriptor::DateChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:datetime)
|
||||||
|
Types::Champs::Descriptor::DatetimeChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:number)
|
||||||
|
Types::Champs::Descriptor::NumberChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:decimal_number)
|
||||||
|
Types::Champs::Descriptor::DecimalNumberChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:integer_number)
|
||||||
|
Types::Champs::Descriptor::IntegerNumberChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:checkbox)
|
||||||
|
Types::Champs::Descriptor::CheckboxChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:civilite)
|
||||||
|
Types::Champs::Descriptor::CiviliteChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:email)
|
||||||
|
Types::Champs::Descriptor::EmailChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:phone)
|
||||||
|
Types::Champs::Descriptor::PhoneChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:address)
|
||||||
|
Types::Champs::Descriptor::AddressChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:yes_no)
|
||||||
|
Types::Champs::Descriptor::YesNoChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:drop_down_list)
|
||||||
|
Types::Champs::Descriptor::DropDownListChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:multiple_drop_down_list)
|
||||||
|
Types::Champs::Descriptor::MultipleDropDownListChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:linked_drop_down_list)
|
||||||
|
Types::Champs::Descriptor::LinkedDropDownListChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:communes)
|
||||||
|
Types::Champs::Descriptor::CommuneChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:departements)
|
||||||
|
Types::Champs::Descriptor::DepartementChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:regions)
|
||||||
|
Types::Champs::Descriptor::RegionChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:pays)
|
||||||
|
Types::Champs::Descriptor::PaysChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:header_section)
|
||||||
|
Types::Champs::Descriptor::HeaderSectionChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:explication)
|
||||||
|
Types::Champs::Descriptor::ExplicationChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:dossier_link)
|
||||||
|
Types::Champs::Descriptor::DossierLinkChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:piece_justificative)
|
||||||
|
Types::Champs::Descriptor::PieceJustificativeChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:rna)
|
||||||
|
Types::Champs::Descriptor::RNAChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:carte)
|
||||||
|
Types::Champs::Descriptor::CarteChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:repetition)
|
||||||
|
Types::Champs::Descriptor::RepetitionChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:titre_identite)
|
||||||
|
Types::Champs::Descriptor::TitreIdentiteChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:iban)
|
||||||
|
Types::Champs::Descriptor::IbanChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:siret)
|
||||||
|
Types::Champs::Descriptor::SiretChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:annuaire_education)
|
||||||
|
Types::Champs::Descriptor::AnnuaireEducationChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:cnaf)
|
||||||
|
Types::Champs::Descriptor::CnafChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:dgfip)
|
||||||
|
Types::Champs::Descriptor::DgfipChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:pole_emploi)
|
||||||
|
Types::Champs::Descriptor::PoleEmploiChampDescriptorType
|
||||||
|
when TypeDeChamp.type_champs.fetch(:mesri)
|
||||||
|
Types::Champs::Descriptor::MesriChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def champ_descriptors
|
def champ_descriptors
|
||||||
if object.type_de_champ.block?
|
if type_de_champ.block?
|
||||||
Loaders::Association.for(object.class, revision_types_de_champ: :type_de_champ).load(object)
|
Loaders::Association.for(object.class, revision_types_de_champ: :type_de_champ).load(object)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def options
|
def options
|
||||||
if object.type_de_champ.drop_down_list?
|
if type_de_champ.drop_down_list?
|
||||||
object.type_de_champ.drop_down_list_options.reject(&:empty?)
|
type_de_champ.drop_down_list_options.reject(&:empty?)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def type_de_champ
|
||||||
|
object.type_de_champ
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class AddressChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class AnnuaireEducationChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class CarteChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class CheckboxChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class CiviliteChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class CnafChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class CommuneChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class DateChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class DatetimeChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class DecimalNumberChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,11 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class DepartementChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
|
||||||
|
field :options, [Types::Champs::DepartementChampType::DepartementType], "List des departements.", null: true
|
||||||
|
|
||||||
|
def options
|
||||||
|
APIGeoService.departements
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class DgfipChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class DossierLinkChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,16 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class DropDownListChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
|
||||||
|
field :options, [String], "List des options d’un champ avec selection.", null: true
|
||||||
|
field :other_option, Boolean, "La selection contien l’option \"Autre\".", null: true
|
||||||
|
|
||||||
|
def other_option
|
||||||
|
object.type_de_champ.drop_down_other?
|
||||||
|
end
|
||||||
|
|
||||||
|
def options
|
||||||
|
object.type_de_champ.drop_down_list_options.reject(&:empty?)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class EmailChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,16 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class ExplicationChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
|
||||||
|
field :collapsible_explanation_enabled, Boolean, null: true
|
||||||
|
field :collapsible_explanation_text, String, null: true
|
||||||
|
|
||||||
|
def collapsible_explanation_enabled
|
||||||
|
object.type_de_champ.collapsible_explanation_enabled?
|
||||||
|
end
|
||||||
|
|
||||||
|
def collapsible_explanation_text
|
||||||
|
object.type_de_champ.collapsible_explanation_text
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class HeaderSectionChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class IbanChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class IntegerNumberChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,11 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class LinkedDropDownListChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
|
||||||
|
field :options, [String], "List des options d’un champ avec selection.", null: true
|
||||||
|
|
||||||
|
def options
|
||||||
|
object.type_de_champ.drop_down_list_options.reject(&:empty?)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class MesriChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,11 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class MultipleDropDownListChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
|
||||||
|
field :options, [String], "List des options d’un champ avec selection.", null: true
|
||||||
|
|
||||||
|
def options
|
||||||
|
object.type_de_champ.drop_down_list_options.reject(&:empty?)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class NumberChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,11 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class PaysChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
|
||||||
|
field :options, [Types::Champs::PaysChampType::PaysType], "List des pays.", null: true
|
||||||
|
|
||||||
|
def options
|
||||||
|
APIGeoService.countries
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class PhoneChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,9 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class PieceJustificativeChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
|
||||||
|
field :file_template, Types::File, "Modèle de la pièce justificative.", null: true, extensions: [
|
||||||
|
{ Extensions::Attachment => { attachment: :piece_justificative_template, root: :type_de_champ } }
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class PoleEmploiChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,11 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class RegionChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
|
||||||
|
field :options, [Types::Champs::RegionChampType::RegionType], "List des regions.", null: true
|
||||||
|
|
||||||
|
def options
|
||||||
|
APIGeoService.regions
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,11 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class RepetitionChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
|
||||||
|
field :champ_descriptors, [Types::ChampDescriptorType], "Description des champs d’un bloc répétable.", null: true
|
||||||
|
|
||||||
|
def champ_descriptors
|
||||||
|
Loaders::Association.for(object.class, revision_types_de_champ: :type_de_champ).load(object)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class RNAChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class SiretChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class TextChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class TextareaChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class TitreIdentiteChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Types::Champs::Descriptor
|
||||||
|
class YesNoChampDescriptorType < Types::BaseObject
|
||||||
|
implements Types::ChampDescriptorType
|
||||||
|
end
|
||||||
|
end
|
|
@ -25,11 +25,24 @@ Cela évite l’accès récursif aux dossiers."
|
||||||
field :date_depublication, GraphQL::Types::ISO8601DateTime, "Date de la dépublication.", null: true
|
field :date_depublication, GraphQL::Types::ISO8601DateTime, "Date de la dépublication.", null: true
|
||||||
field :date_fermeture, GraphQL::Types::ISO8601DateTime, "Date de la fermeture.", null: true
|
field :date_fermeture, GraphQL::Types::ISO8601DateTime, "Date de la fermeture.", null: true
|
||||||
|
|
||||||
|
field :duree_conservation_dossiers, Int, "Durée de conservation des dossiers en mois.", null: false
|
||||||
|
|
||||||
|
field :demarche_url, String, null: true
|
||||||
|
field :site_web_url, String, null: true
|
||||||
|
field :dpo_url, String, null: true
|
||||||
|
field :notice_url, String, null: true
|
||||||
|
field :cadre_juridique_url, String, null: true
|
||||||
|
|
||||||
|
field :opendata, Boolean, null: false
|
||||||
|
field :tags, [String], null: false
|
||||||
|
field :zones, [String], null: false
|
||||||
|
|
||||||
field :revision, Types::RevisionType, null: false
|
field :revision, Types::RevisionType, null: false
|
||||||
field :service, Types::ServiceType, null: true
|
field :service, Types::ServiceType, null: true
|
||||||
|
|
||||||
field :cadre_juridique, String, null: true
|
field :logo, Types::File, null: true, extensions: [{ Extensions::Attachment => { root: :procedure } }]
|
||||||
field :deliberation, String, null: true
|
field :notice, Types::File, null: true, extensions: [{ Extensions::Attachment => { root: :procedure } }]
|
||||||
|
field :deliberation, Types::File, null: true, extensions: [{ Extensions::Attachment => { root: :procedure } }]
|
||||||
|
|
||||||
field :dossiers_count, Int, null: false, internal: true
|
field :dossiers_count, Int, null: false, internal: true
|
||||||
|
|
||||||
|
@ -38,25 +51,51 @@ Cela évite l’accès récursif aux dossiers."
|
||||||
end
|
end
|
||||||
|
|
||||||
def revision
|
def revision
|
||||||
object.is_a?(ProcedureRevision) ? object : object.active_revision
|
if object.is_a?(ProcedureRevision)
|
||||||
|
object
|
||||||
|
else
|
||||||
|
object.active_revision
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def procedure
|
||||||
|
if object.is_a?(ProcedureRevision)
|
||||||
|
object.procedure
|
||||||
|
else
|
||||||
|
object
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def dossiers_count
|
def dossiers_count
|
||||||
object.dossiers.count
|
procedure.dossiers.visible_by_administration.count
|
||||||
end
|
|
||||||
|
|
||||||
def deliberation
|
|
||||||
Rails.application.routes.url_helpers.url_for(procedure.deliberation) if procedure.deliberation.attached?
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def state
|
def state
|
||||||
procedure.aasm.current_state
|
procedure.aasm.current_state
|
||||||
end
|
end
|
||||||
|
|
||||||
def cadre_juridique
|
delegate :description, :opendata, :tags, to: :procedure
|
||||||
|
|
||||||
|
def demarche_url
|
||||||
|
procedure.lien_demarche
|
||||||
|
end
|
||||||
|
|
||||||
|
def dpo_url
|
||||||
|
procedure.lien_dpo
|
||||||
|
end
|
||||||
|
|
||||||
|
def notice_url
|
||||||
|
procedure.lien_notice
|
||||||
|
end
|
||||||
|
|
||||||
|
def cadre_juridique_url
|
||||||
procedure.cadre_juridique
|
procedure.cadre_juridique
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def site_web_url
|
||||||
|
procedure.lien_site_web
|
||||||
|
end
|
||||||
|
|
||||||
def number
|
def number
|
||||||
procedure.id
|
procedure.id
|
||||||
end
|
end
|
||||||
|
@ -65,10 +104,6 @@ Cela évite l’accès récursif aux dossiers."
|
||||||
procedure.libelle
|
procedure.libelle
|
||||||
end
|
end
|
||||||
|
|
||||||
def description
|
|
||||||
procedure.description
|
|
||||||
end
|
|
||||||
|
|
||||||
def declarative
|
def declarative
|
||||||
procedure.declarative_with_state
|
procedure.declarative_with_state
|
||||||
end
|
end
|
||||||
|
@ -93,15 +128,17 @@ Cela évite l’accès récursif aux dossiers."
|
||||||
procedure.closed_at
|
procedure.closed_at
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.authorized?(object, context)
|
def duree_conservation_dossiers
|
||||||
procedure = object.is_a?(ProcedureRevision) ? object.procedure : object
|
procedure.duree_conservation_dossiers_dans_ds
|
||||||
procedure.opendata? || context.authorized_demarche?(procedure)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
def zones
|
||||||
|
procedure.zones.map(&:current_label)
|
||||||
|
end
|
||||||
|
|
||||||
def procedure
|
def self.authorized?(object, context)
|
||||||
revision.procedure
|
procedure = object.is_a?(ProcedureRevision) ? object.procedure : object
|
||||||
|
context.authorized_demarche?(procedure, opendata: true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,7 +12,11 @@ module Types
|
||||||
end
|
end
|
||||||
|
|
||||||
def annotation_descriptors
|
def annotation_descriptors
|
||||||
|
if context.authorized_demarche?(object.procedure, opendata: true)
|
||||||
Loaders::Association.for(object.class, revision_types_de_champ_private: :type_de_champ).load(object)
|
Loaders::Association.for(object.class, revision_types_de_champ_private: :type_de_champ).load(object)
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -303,16 +303,18 @@ class SerializerService
|
||||||
}
|
}
|
||||||
|
|
||||||
fragment ChampDescriptorFragment on ChampDescriptor {
|
fragment ChampDescriptorFragment on ChampDescriptor {
|
||||||
type
|
__typename
|
||||||
label
|
label
|
||||||
description
|
description
|
||||||
required
|
required
|
||||||
|
... on DropDownListChampDescriptor {
|
||||||
options
|
options
|
||||||
champDescriptors {
|
otherOption
|
||||||
type
|
}
|
||||||
label
|
... on MultipleDropDownListChampDescriptor {
|
||||||
description
|
options
|
||||||
required
|
}
|
||||||
|
... on LinkedDropDownListChampDescriptor {
|
||||||
options
|
options
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -321,13 +323,28 @@ class SerializerService
|
||||||
number
|
number
|
||||||
title
|
title
|
||||||
description
|
description
|
||||||
|
tags
|
||||||
|
zones
|
||||||
datePublication
|
datePublication
|
||||||
service { nom organisme typeOrganisme }
|
service { nom organisme typeOrganisme }
|
||||||
cadreJuridique
|
demarcheUrl
|
||||||
deliberation
|
dpoUrl
|
||||||
|
noticeUrl
|
||||||
|
siteWebUrl
|
||||||
|
cadreJuridiqueUrl
|
||||||
|
logo { ...FileFragment }
|
||||||
|
notice { ...FileFragment }
|
||||||
|
deliberation { ...FileFragment }
|
||||||
dossiersCount
|
dossiersCount
|
||||||
revision {
|
revision {
|
||||||
champDescriptors { ...ChampDescriptorFragment }
|
champDescriptors {
|
||||||
|
...ChampDescriptorFragment
|
||||||
|
... on RepetitionChampDescriptor {
|
||||||
|
champDescriptors {
|
||||||
|
...ChampDescriptorFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GRAPHQL
|
GRAPHQL
|
||||||
|
|
|
@ -67,7 +67,7 @@ describe API::V2::GraphqlController do
|
||||||
publishedRevision {
|
publishedRevision {
|
||||||
id
|
id
|
||||||
champDescriptors {
|
champDescriptors {
|
||||||
type
|
__typename
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
service {
|
service {
|
||||||
|
@ -76,17 +76,27 @@ describe API::V2::GraphqlController do
|
||||||
organisme
|
organisme
|
||||||
}
|
}
|
||||||
champDescriptors {
|
champDescriptors {
|
||||||
|
__typename
|
||||||
id
|
id
|
||||||
type
|
|
||||||
label
|
label
|
||||||
description
|
description
|
||||||
required
|
required
|
||||||
|
... on RepetitionChampDescriptor {
|
||||||
champDescriptors {
|
champDescriptors {
|
||||||
|
__typename
|
||||||
id
|
id
|
||||||
type
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
... on DropDownListChampDescriptor {
|
||||||
options
|
options
|
||||||
}
|
}
|
||||||
|
... on MultipleDropDownListChampDescriptor {
|
||||||
|
options
|
||||||
|
}
|
||||||
|
... on LinkedDropDownListChampDescriptor {
|
||||||
|
options
|
||||||
|
}
|
||||||
|
}
|
||||||
dossiers {
|
dossiers {
|
||||||
nodes {
|
nodes {
|
||||||
id
|
id
|
||||||
|
@ -157,9 +167,13 @@ describe API::V2::GraphqlController do
|
||||||
describe "query a demarche" do
|
describe "query a demarche" do
|
||||||
let(:procedure) { create(:procedure, :published, :for_individual, :with_service, :with_all_champs, :with_all_annotations, administrateurs: [admin]) }
|
let(:procedure) { create(:procedure, :published, :for_individual, :with_service, :with_all_champs, :with_all_annotations, administrateurs: [admin]) }
|
||||||
|
|
||||||
|
def format_type_champ(type_champ)
|
||||||
|
"#{type_champ.gsub('regions', 'region').gsub('departements', 'departement').gsub('communes', 'commune').camelcase}ChampDescriptor"
|
||||||
|
end
|
||||||
|
|
||||||
it "returns the demarche" do
|
it "returns the demarche" do
|
||||||
expect(gql_errors).to eq(nil)
|
expect(gql_errors).to eq(nil)
|
||||||
expect(gql_data).to eq(demarche: {
|
expect(gql_data).to include(demarche: {
|
||||||
id: procedure.to_typed_id,
|
id: procedure.to_typed_id,
|
||||||
number: procedure.id,
|
number: procedure.id,
|
||||||
title: procedure.libelle,
|
title: procedure.libelle,
|
||||||
|
@ -174,15 +188,11 @@ describe API::V2::GraphqlController do
|
||||||
label: "défaut"
|
label: "défaut"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
revisions: procedure.revisions.map { |revision| { id: revision.to_typed_id } },
|
revisions: procedure.revisions.map { { id: _1.to_typed_id } },
|
||||||
draftRevision: { id: procedure.draft_revision.to_typed_id },
|
draftRevision: { id: procedure.draft_revision.to_typed_id },
|
||||||
publishedRevision: {
|
publishedRevision: {
|
||||||
id: procedure.published_revision.to_typed_id,
|
id: procedure.published_revision.to_typed_id,
|
||||||
champDescriptors: procedure.published_revision.types_de_champ_public.map do |tdc|
|
champDescriptors: procedure.published_revision.types_de_champ_public.map { { __typename: format_type_champ(_1.type_champ) } }
|
||||||
{
|
|
||||||
type: tdc.type_champ
|
|
||||||
}
|
|
||||||
end
|
|
||||||
},
|
},
|
||||||
service: {
|
service: {
|
||||||
nom: procedure.service.nom,
|
nom: procedure.service.nom,
|
||||||
|
@ -193,15 +203,15 @@ describe API::V2::GraphqlController do
|
||||||
{
|
{
|
||||||
id: tdc.to_typed_id,
|
id: tdc.to_typed_id,
|
||||||
label: tdc.libelle,
|
label: tdc.libelle,
|
||||||
type: tdc.type_champ,
|
__typename: format_type_champ(tdc.type_champ),
|
||||||
description: tdc.description,
|
description: tdc.description,
|
||||||
required: tdc.mandatory?,
|
required: tdc.mandatory?,
|
||||||
champDescriptors: tdc.repetition? ? procedure.active_revision.children_of(tdc.reload).map { |tdc| { id: tdc.to_typed_id, type: tdc.type_champ } } : nil,
|
champDescriptors: tdc.repetition? ? procedure.active_revision.children_of(tdc.reload).map { { id: _1.to_typed_id, __typename: format_type_champ(_1.type_champ) } } : nil,
|
||||||
options: tdc.drop_down_list? ? tdc.drop_down_list_options.reject(&:empty?) : nil
|
options: tdc.drop_down_list? ? tdc.drop_down_list_options.reject(&:empty?) : nil
|
||||||
}
|
}.compact
|
||||||
end,
|
end,
|
||||||
dossiers: {
|
dossiers: {
|
||||||
nodes: dossiers.map { |dossier| { id: dossier.to_typed_id } }
|
nodes: dossiers.map { { id: _1.to_typed_id } }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
|
@ -79,6 +79,16 @@ describe API::V2::GraphqlController do
|
||||||
expect(gql_data[:demarche][:dossiers][:nodes].size).to eq(1)
|
expect(gql_data[:demarche][:dossiers][:nodes].size).to eq(1)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'include Revision' do
|
||||||
|
let(:variables) { { demarcheNumber: procedure.id, includeRevision: true } }
|
||||||
|
|
||||||
|
it {
|
||||||
|
expect(gql_errors).to be_nil
|
||||||
|
expect(gql_data[:demarche][:id]).to eq(procedure.to_typed_id)
|
||||||
|
expect(gql_data[:demarche][:activeRevision]).not_to be_nil
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'getGroupeInstructeur' do
|
context 'getGroupeInstructeur' do
|
||||||
|
|
|
@ -5,9 +5,9 @@ FactoryBot.define do
|
||||||
labels { [{ designated_on: '1981-05-08', name: "Ministère de l'Education Populaire" }] }
|
labels { [{ designated_on: '1981-05-08', name: "Ministère de l'Education Populaire" }] }
|
||||||
end
|
end
|
||||||
|
|
||||||
after(:create) do |zone, evaluator|
|
after(:build) do |zone, evaluator|
|
||||||
evaluator.labels.each do |label|
|
evaluator.labels.each do |label|
|
||||||
zone.labels.create(designated_on: label[:designated_on], name: label[:name])
|
zone.labels.build(designated_on: label[:designated_on], name: label[:name])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
describe DemarchesPubliquesExportService do
|
describe DemarchesPubliquesExportService do
|
||||||
let(:procedure) { create(:procedure, :published, :with_service, :with_type_de_champ) }
|
let(:procedure) { create(:procedure, :published, :with_service, :with_type_de_champ) }
|
||||||
let!(:dossier) { create(:dossier, procedure: procedure) }
|
let!(:dossier) { create(:dossier, :en_construction, procedure: procedure) }
|
||||||
let(:gzip_filename) { "demarches.json.gz" }
|
let(:gzip_filename) { "demarches.json.gz" }
|
||||||
|
|
||||||
after { FileUtils.rm(gzip_filename) }
|
after { FileUtils.rm(gzip_filename) }
|
||||||
|
@ -16,19 +16,25 @@ describe DemarchesPubliquesExportService do
|
||||||
organisme: "organisme",
|
organisme: "organisme",
|
||||||
typeOrganisme: "association"
|
typeOrganisme: "association"
|
||||||
},
|
},
|
||||||
cadreJuridique: "un cadre juridique important",
|
cadreJuridiqueUrl: "un cadre juridique important",
|
||||||
|
demarcheUrl: nil,
|
||||||
|
dpoUrl: nil,
|
||||||
|
noticeUrl: nil,
|
||||||
|
siteWebUrl: "https://mon-site.gouv",
|
||||||
|
logo: nil,
|
||||||
|
notice: nil,
|
||||||
deliberation: nil,
|
deliberation: nil,
|
||||||
datePublication: procedure.published_at.iso8601,
|
datePublication: procedure.published_at.iso8601,
|
||||||
|
zones: ["Ministère de l'Education Populaire"],
|
||||||
|
tags: [],
|
||||||
dossiersCount: 1,
|
dossiersCount: 1,
|
||||||
revision: {
|
revision: {
|
||||||
champDescriptors: [
|
champDescriptors: [
|
||||||
{
|
{
|
||||||
description: procedure.active_revision.types_de_champ_public.first.description,
|
description: procedure.active_revision.types_de_champ_public.first.description,
|
||||||
label: procedure.active_revision.types_de_champ_public.first.libelle,
|
label: procedure.active_revision.types_de_champ_public.first.libelle,
|
||||||
options: nil,
|
|
||||||
required: false,
|
required: false,
|
||||||
type: "text",
|
__typename: "TextChampDescriptor"
|
||||||
champDescriptors: nil
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue