Pogues
Pogues copied to clipboard
Roundabout component - DDI model
WIP
- [x] First model of the object
- [x] Check name
- [ ] Update controlled vocabulary
- [x] How to parametrize?
- [ ] Final model
Describe what this component is about
This could be modelled as a DDI Sequence with a TypeOfSequence with value "roundabout".
<d:Sequence>
<r:Agency>fr.insee</r:Agency>
<r:ID>abcd1234</r:ID>
<r:Version>1</r:Version>
<d:ConstructName>
<r:String xml:lang="fr-FR">ROUNDABOUT</r:String>
</d:ConstructName>
<r:Label>
<r:Content xml:lang="fr-FR">Le rond-point</r:Content>
</r:Label>
<!-- Typing the sequence -->
<d:TypeOfSequence controlledVocabularyID="INSEE-TOS-CL-1">roundabout</d:TypeOfSequence>
<d:ControlConstructReference>
[...]
</d:ControlConstructReference>
</d:Sequence>
Pour le rond-point, je ne sais pas s'il faut en faire une séquence ou un attribut de la boucle qu'il introduit. Je ne sais pas ce que l'on souhaite mettre exactement sur la page de rond-point à part :
- des liens vers la page précédente
- pour chacune des occurrences de la boucle qui suit : - l'état d'avancement de la saisie pour cette occurrence - un lien vers la première page - un lien vers la dernière page atteinte
Si l'on ne souhaite pas afficher davantage, le label de la boucle (qui n'est a priori pas utilisé) peut suffire comme label pour la page (ou du tableau des occurrences de boucle) et le reste peut s'en déduire...
Pour identifier la meilleure modélisation, il faudrait un exemple de ce que l'on souhaite obtenir avec l'orchestrateur. Le but est moins d'identifier ce à quoi cette page devra ressembler (l'UX design pourra la faire évoluer) que d'identifier quelles informations devront être fournies par Pogues, donc quelles informations devront figurer dans les modèles Pogues, DDI et Lunatic.
Pour avancer :
- le composant est en démo sur le storybook V2
- le modèle sous-jacent pour cet exemple est ici.
En terme d'usage du rond-point, deux éléments de configuration au moins :
- les expressions permettant de préciser comment déterminer l'état des sous-questionnaires ;
"expressions": {
"unnecessary": {
"value": "AGE < 13",
"type": "VTL"
},
"complete": {
"value": "not(isnull(KNOWREC)) and not(isnull(SEXE)) and not(isnull(SOMETHING))",
"type": "VTL"
},
"partial": {
"value": "not(isnull(KNOWREC)) or not(isnull(SEXE)) or not(isnull(SOMETHING))",
"type": "VTL"
},
"label": {
"value": "\"Série de question pour \" || PRENOMS",
"type": "VTL"
}
}
- la liste des composants pour chaque sous-questionnaire.
"components": [
{
"id": "radio",
"componentType": "Radio",
"mandatory": false,
"page": "4.1",
"label": {
"value": "\"Connaissez-vous le recensement de la population ?\"",
"type": "VTL|MD"
},
"conditionFilter": { "value": "true", "type": "VTL" },
"options": [
{ "value": "1", "label": { "value": "\"oui\"", "type": "VTL|MD" } },
{ "value": "2", "label": { "value": "\"non\"", "type": "VTL|MD" } }
],
"response": { "name": "KNOWREC" }
},
{
"id": "jsygk7m7",
"componentType": "Subsequence",
"page": "4.2",
"label": {
"value": "\"Deuxième page de questions pour \"|| PRENOMS",
"type": "VTL|MD"
},
"conditionFilter": { "value": "true", "type": "VTL" }
},
...
]
A priori, on inclut uniquement des sous-séquences et des questions comme enfants du rond-point.
Asking @renaud23 if subsequence is the higher component level or not.
UPDATE : same constraint as for paged loop ("boucles paginées"), so any component seems good.
De ce que je vois au niveau du modèle Lunatic présent en lien, on est assez près de la boucle liée :
- même contenu au niveau des components
- le filtre présent au niveau de unnecessary ressemble à celui d'une boucle liée
Il manque :
- le label
- complete ou partial (c'est 2 conditions sont opposées, donc avoir l'une revient à avoir l'autre)
- locked (je ne sais pas ce que c'est)
Dans le cas d'une boucle liée avec filtre sur les occurrences, on était parti sur une Loop référençant un filtre, référençant lui-même une séquence -> ce sont les 3 éléments que l'on peut enrichir pour avoir les informations manquantes (mais il faudrait pour Eno indiquer dans la Loop qu'il s'agit d'un rond-point)
Would the following be a good design ?
<d:Loop>
<r:Agency>fr.insee</r:Agency>
<r:ID>lmomdlun</r:ID>
<r:Version>1</r:Version>
<d:ConstructName>
<r:String xml:lang="fr-FR">B2</r:String>
</d:ConstructName>
<d:ControlConstructReference>
<r:Agency>fr.insee</r:Agency>
<r:ID>lmommfe7</r:ID>
<r:Version>1</r:Version>
<r:TypeOfObject>Sequence</r:TypeOfObject>
</d:ControlConstructReference>
<r:UserAttributePair>
<r:AttributeKey>Navigation</r:AttributeKey>
<r:AttributeValue>Roundabout</r:AttributeValue>
</r:UserAttributePair>
<r:UserAttributePair>
<r:AttributeKey>RoundaboutConfiguration</r:AttributeKey>
<r:AttributeValue><![CDATA[
"expressions": {
"unnecessary": {
"value": "AGE < 13",
"type": "VTL"
},
"complete": {
"value": "not(isnull(KNOWREC)) and not(isnull(SEXE)) and not(isnull(SOMETHING))",
"type": "VTL"
},
"partial": {
"value": "not(isnull(KNOWREC)) or not(isnull(SEXE)) or not(isnull(SOMETHING))",
"type": "VTL"
},
"label": {
"value": "\"Série de question pour \" || PRENOMS",
"type": "VTL"
}
}
]]></r:AttributeValue>
</r:UserAttributePair>
</d:Loop>
As suggested by @BulotF we are reusing here the DDI design for linked loops, adding two <r:UserAttributePair>
:
- the first one indicating that this linked loop will be displayed as as Roundabout
- the second one giving all necessary parameters.
Asking for validation @BulotF and @laurentC35 🤗
There are sevreal problem with the second element :
- "unnecessary" is redundant : the loop references a IfThenElse with this condition : no information present twice if not necessary
- "complete" / "partial" contain duplicated code : started "not(isnull(KNOWREC))" and complete "not(isnull(SEXE)) and not(isnull(SOMETHING))" would be better (partial = started and not complete)
- everywhere else, code references to other element. Not here
- it is not possible pour internationalize "label"
VTL code is written "as is" as it is an example provided by a Lunatic roundabout developer.
So if i understand correctly, the configuration part of the Roundabout would be produced by scanning part of the DDI? Or all?
Alternative design : A round-about is a mono-paged loop or a QuestionGrid with a roster. Still with something indicating that that component is a roundabout.
That component may be inside a Sequence with label "Libellé du rondpoint".
If it is a Loop, its content should be a unique ControlConstruct, but I don't know which kind of element inside : a StatementItem ?
If it is a QuestionGrid, probably a noDataByDefinition in each cell with a label containing the complete and partial formulas. Maybe with several columns if there are several linked loops.
It seems to me that if really makes sense to use a Loop as the base construct for the Roundabout 😃
The main idea is to design the roundabout as a Loop that contains a Sequence which itself contains a StatementItem and three ComputationItems, one for each Roundabout parameter:
Loop
Sequence
StatementItem
ComputationItem[unnecessary]
ComputationItem[partial]
ComputationItem[complete]
The Loop
<d:Loop>
<r:Agency>fr.insee</r:Agency>
<r:ID>lnbp643q</r:ID>
<r:Version>1</r:Version>
<r:UserAttributePair>
<r:AttributeKey>ROUNDABOUT_OBJECT</r:AttributeKey>
<r:AttributeValue>ROUNDABOUT_LOOP</r:AttributeValue>
</r:UserAttributePair>
<d:ConstructName>
<r:String xml:lang="fr-FR">B_RONDPOINT</r:String>
</d:ConstructName>
<d:ControlConstructReference>
<r:Agency>fr.insee</r:Agency>
<r:ID>lnbpayrw</r:ID>
<r:Version>1</r:Version>
<r:TypeOfObject>Sequence</r:TypeOfObject>
</d:ControlConstructReference>
</d:Loop>
The Sequence
<d:Sequence>
<r:Agency>fr.insee</r:Agency>
<r:ID>lnbpayrw</r:ID>
<r:Version>1</r:Version>
<d:ConstructName>
<r:String xml:lang="fr-FR">RONDPOINT</r:String>
</d:ConstructName>
<d:ControlConstructReference>[StatementItem]</d:ControlConstructReference>
<d:ControlConstructReference>[ComputationItem]</d:ControlConstructReference>
<d:ControlConstructReference>[ComputationItem]</d:ControlConstructReference>
<d:ControlConstructReference>[ComputationItem]</d:ControlConstructReference>
</d:Sequence>
The StatementItem
<d:StatementItem>
<r:Agency>fr.insee</r:Agency>
<r:ID>LABEL_ET_BOUTON</r:ID>
<r:Version>1</r:Version>
<r:UserAttributePair>
<r:AttributeKey>ROUNDABOUT_OBJECT</r:AttributeKey>
<r:AttributeValue>LABEL_AND_BUTTON</r:AttributeValue>
</r:UserAttributePair>
<r:Label>
<r:Content>Le libellé au-dessus du bouton</r:Content>
</r:Label>
</d:StatementItem>
The ComputationItems
In order to describe completion parameters we use <d:ComputationItem>
. For example here, for the unnecessary
Lunatic Parameter:
<d:ComputationItem>
<r:Agency>fr.insee</r:Agency>
<r:ID>lahvkp0z-CI-0</r:ID>
<r:Version>1</r:Version>
<d:ConstructName>
<r:String xml:lang="fr-FR">ROUNDABOUT_UNNECESSARY</r:String>
</d:ConstructName>
<r:Description>
<r:Content xml:lang="fr-FR">Rond-point - Les itérations à masquer.</r:Content>
</r:Description>
<d:InterviewerInstructionReference>
<r:Agency>fr.insee</r:Agency>
<r:ID>lahvkp0z-CI-0-II-0</r:ID>
<r:Version>1</r:Version>
<r:TypeOfObject>Instruction</r:TypeOfObject>
</d:InterviewerInstructionReference>
<d:TypeOfComputationItem controlledVocabularyID="INSEE-LUNATIC">roundabout-unnecessary</d:TypeOfComputationItem>
<r:CommandCode>
<r:Command>
<r:ProgramLanguage>vtl</r:ProgramLanguage>
<r:CommandContent>AGE ;< 13</r:CommandContent>
</r:Command>
</r:CommandCode>
</d:ComputationItem>
- To specify the type of loop, I would prefer :
<r:UserAttributePair>
<r:AttributeKey>loopType</r:AttributeKey>
<r:AttributeValue>roundabout</r:AttributeValue>
</r:UserAttributePair>
- For the StatementItem :
<r:UserAttributePair>
<r:AttributeKey>button</r:AttributeKey>
<r:AttributeValue>roundabout-link</r:AttributeValue>
</r:UserAttributePair>
-
The controlledVocabulary for TypeOfComputationItem would be : roundabout-unnecessary roundabout-complete roundabout-partial
-
ComputationItem have no InterviewerInstructionReference
-
For at least dynamic arrays (QuestionGrid with 2 dimensions for which the first dimension is a roster and the second one is a codeList), I'd use a Variable to indicate where the buttons should be displayed. It would be mandatory when there is at least 2 buttons, to assign correctly the computation items to each. Alternative in the component that displays the link, I'd like to have a reference (basedOn ?) to the 3 parameters ComputationItem...
ComputationItem have no InterviewerInstructionReference
Yes, i just forgot to delete this part 😉
Maybe it could be important to fill a controlled vocabulary for attributevaluekeys too I don't see how the choice is made between the partial label and complet label , when all the fields are completed I change my previous comment. two possibilities. the basedOnObject cardinality is 0 1. it can contain several basedOnReferences we could type with RserAttributPair. Why not using inparameter instead to get computation item value ?
I thought that controlled vocabulary's AttributeKeys was specified in the DDI profile (and only in it)
InParameter is a better alternative. Nice.
I agree in the DDI profile it's fine ! not the same status as a value
So it seems that we have an agreement on the design, i propose to add that to a proper and versionned document.
The implementation can start.
I wrapped up our comments in this document 👇
I don't think we need an alternative QuestionGrid based design with this. But:
- we still have the 5. of François remarks to discuss
- we probably need a french version of this document.
a suggestion of identifying the used suggester also by a version number , if it evolves over time
A last review by @BulotF is in progress.
Reprise des réflexions sur le rond-point... J'écris en français pour permettre aux participations à la discussion de ne pas alourdir la compréhension de mes explications avec la traduction.
Résumé de ma vision du rond-point du point de vue métier : Lorsqu'on est sur un questionnaire sans rond-point, l'avancement dans le questionnaire ne peut être que linéaire : Au niveau des boucles, on répond aux occurrences dans l'ordre et on attend d'en finir une avant d'entamer la suivante.
Avec le rond-point, on se donne la possibilité de basculer d'une occurrence à une autre, dans un ordre déterminé par le(s) répondant(s) et sans forcément avoir terminé une occurrence avant de basculer à une autre.
Pour faire un parallèle : le questionnaire global est le processus principal. On le met en pause pour lancer plusieurs petits processus parallèles. On le reprend lorsque tous ces petits processus sont terminés.
Pour avoir une expérience utilisateur la plus claire possible, on a besoin des éléments suivants :
- le rond-point est sur une page spécifique
- il peut avoir un titre et éventuellement des instructions
- pour chaque occurrence :
- il affiche un libellé qui permet d'identifier l'occurrence
- il permet d'accéder à la dernière page renseignée de l'occurrence (si cela a du sens)
- il renseigne sur l'état de l'occurrence : "non concerné" ; "non commencé" ; "en cours" ; "terminé" (libellés donnés à titre indicatif)
- si le rond-point permet d'accéder à plusieurs boucles qui se suivent et que l'on souhaite clarifier au répondant les étapes (ex : informations individu ; questions individus majeurs ; informations grosses dépenses ; carnet de dépenses), l'information pour chaque occurrence peut être préciser pour chaque étape + chaque étape possède un libellé.
- en cours de navigation au sein d'une occurrence, le rond-point est immédiatement accessible
Le rond-point peut être vu comme un conteneur de boucle(s), plutôt que comme un type de boucle particulier. Le définir comme une séquence de typeOfSequence = "roundabout" offre plusieurs possibilités intéressantes :
- fournir une présentation structurée au niveau de la page, en dehors des liens vers les boucles : en plus du titre de page, utiliser des déclarations
- pouvoir référencer plusieurs boucles au lieu d'être restreint à une seule
Par ailleurs, je pense que le filtre d'occurrence que l'on indiquait sous la forme d'un ComputationItem "unnecessary" mérite de redevenir un filtre (ce qu'il est déjà avec les boucles hors rond-point). Je conserverais les ComputationItem "complete" et "partial" tels quels.
Au niveau StatementItem, outre le libellé pour désigner l'occurrence, j'utiliserais des StatementItem pour les boutons "Ajouter une occurrence" (actuellement, on utiliser le label de la Loop et c'est assez moyen) et "supprimer une occurrence". Si on choisit de les indiquer au sein de la Sequence qui dépend directement de la Loop, on peut même choisir d'en faire des d:Instruction et donc de leur donner des InstructionName correspondant à leur statut : Loop.InstanceLabel ; Loop.Add ; Loop.Remove
Si on souhaite modéliser l'exemple suivant :
N.B. Modélisation en mode déréférencé (je remplace la référence par l'objet) qui n'indiquerait que les éléments utiles...
<d:Sequence>
<r:Label>Liens vers les différentes personnes du ménage :</r:Label>
<d:Instruction>
<d:InstructionName>help</d:InstructionName>
<d:InstructionText>Cette page permet d’accéder aux questionnaires des différentes personnes du ménage.
Vous pouvez revenir à cette page en appuyant sur le bouton « revenir au rond-point »</d:InstructionText>
</d:Instruction>
<d:TypeOfSequence controlledVocabularyID="INSEE-TOS-CL-1">roundabout</d:TypeOfSequence>
<d:Loop>
<r:Label>Questions individuelles</r:Label>
<d:Sequence>
<d:Instruction>
<d:InstructionName>Loop.InstanceLabel</d:InstructionName>
<d:InstructionText>¤PRENOM¤</d:InstructionText>
</d:Instruction>
<d:Instruction>
<d:InstructionName>Loop.Add</d:InstructionName>
<d:InstructionText>Ajouter un individu</d:InstructionText>
</d:Instruction>
<d:Instruction>
<d:InstructionName>Loop.Remove</d:InstructionName>
<d:InstructionText>Supprimer un individu</d:InstructionText>
</d:Instruction>
<d:TypeOfSequence controlledVocabularyID="INSEE-TOS-CL-1">loopContent</d:TypeOfSequence>
<d:ComputationItem>
<d:TypeOfComputationItem controlledVocabularyID="INSEE-TOCI-CL-1">loop.complete</d:TypeOfComputationItem>
<r:CommandCode>Tout est renseigné</r:CommandCode>
</d:ComputationItem>
<d:ComputationItem>
<d:TypeOfComputationItem controlledVocabularyID="INSEE-TOCI-CL-1">loop.partial</d:TypeOfComputationItem>
<r:CommandCode>Au moins une variable est renseignés</r:CommandCode>
</d:ComputationItem>
... Contenu de la boucle questions individuelles ...
</d:Sequence>
</d:Loop>
<d:Loop>
<r:Label>Questions sur les majeurs</r:Label>
<d:IfThenElse>
<d:IfCondition>AGE >= 18</d:IfCondition>
<d:Sequence>
<d:TypeOfSequence controlledVocabularyID="INSEE-TOS-CL-1">filteredLoopContent</d:TypeOfSequence>
<d:ComputationItem>
<d:TypeOfComputationItem controlledVocabularyID="INSEE-TOCI-CL-1">loop.complete</d:TypeOfComputationItem>
<r:CommandCode>Tout est renseigné</r:CommandCode>
</d:ComputationItem>
<d:ComputationItem>
<d:TypeOfComputationItem controlledVocabularyID="INSEE-TOCI-CL-1">loop.partial</d:TypeOfComputationItem>
<r:CommandCode>Au moins une variable est renseignés</r:CommandCode>
</d:ComputationItem>
... Contenu de la boucle questions sur les majeurs ...
</d:Sequence>
</d:IfThenElse>
</d:Loop>
<d:Loop>
<r:Label>Cœur de l’enquête</r:Label>
<d:IfThenElse>
<d:IfCondition>Indiv = Kish</d:IfCondition>
<d:Sequence>
<d:TypeOfSequence controlledVocabularyID="INSEE-TOS-CL-1">filteredLoopContent</d:TypeOfSequence>
<d:ComputationItem>
<d:TypeOfComputationItem controlledVocabularyID="INSEE-TOCI-CL-1">loop.complete</d:TypeOfComputationItem>
<r:CommandCode>Tout est renseigné</r:CommandCode>
</d:ComputationItem>
<d:ComputationItem>
<d:TypeOfComputationItem controlledVocabularyID="INSEE-TOCI-CL-1">loop.partial</d:TypeOfComputationItem>
<r:CommandCode>Au moins une variable est renseignés</r:CommandCode>
</d:ComputationItem>
... Contenu de la boucle cœur de l’enquête ...
</d:Sequence>
</d:IfThenElse>
</d:Loop>
</d:Sequence>
Eléments de vocabulaire qui n'existent pas encore, mais auraient de l'intérêt pour les séquences : ajouter des valeurs à typeOfSequence : filterContent ; loopContent et filteredLoopContent (contenu d'une boucle dont les occurrences sont filtrées)
Cette description a l'avantage de ne pas utiliser r:UserAttributePair. L'enrichissement de la sémantique est porté par les modalités de TypeOfSequence ; InstructionName ; TypeOfComputationItem
à documenter ailleurs qu'ici Faire une issue Pogues-Model + Eno
Modification des besoins Lunatic :
- suppression du besoin des ComputationItem loop.complete et loop.partial (directement calculés)
- le besoin des Instruction Loop.Add et Loop.Remove n'est plus lié au rond-point (mais reste pertinent dans le cas des boucles principales)
- ajout d'une variable collectée indiquant la page d'avancement du répondant sur chaque occurrence : pour moi, il s'agit d'une paradonnée (comme l'information de la page courante du répondant hors rond-point) ; elle mérite de ne pas formuler dans le DDI ; je propose de faire générer cette variable à Eno à partir du nom du rond-point
- Remplacement du libellé destiné à décrire la raison de non-collecte des occurrences exclues par les filtres (que j'avais mis en r:Label du IfThenElse, par une description de l'état de l'occurrence vis-à-vis du rond-point. Plutôt que partir sur l'utilisation du r:Description de l'Instruction Loop.InstanceLabel, je propose une Instruction Loop.InstanceDescription : pour Dylan, il s'agit de la description de l'occurrence ; pour moi, il s'agit de 2 concepts distincts : un identifiant de l'occurrence à destination du répondant pour le InstanceLabel ; une description de l'état de l'occurrence vis-à-vis des réponses qu'elle devra donner.
- ajout d'un paramètre "Locked" : pour le moment, un booléen, qui indique si on est bloqué pour revenir sur une occurrence terminée. Pour le moment, au niveau du modèle Lunatic, il s'agit d'un booléen simple. Je pense néanmoins que les concepteurs pourraient souhaiter mettre une condition au fait de bloquer ou non les occurrences. Je propose donc un ComputationItem de type loop.lock qui, dans un premier temps, vaudrait true en condition et n'aurait pas de libellé
quelques remarques -je suis d'accord sur le fait que dans le DDI il n'est pas nécessaire de mettre tous les objets techniques pour gérer l'affichage, l'essentiel c'est d'avoir l'information logique/métier de la passation -je suis ok sur la présentation du ddi de l'exemple du 13 mars, il faudra voir avec les imports dans Colectica que les instructions des séquences sont bien importées (actuellement non décrits dans Designer), on est plutot sur interviewerinstruction il me semble -sur les exemples ce serait pratique de mentionner la version de DDI utilisé, ddi3_2 ou ddi3_3 et par la suite ddi3_4