Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(#243): Adds the rank question type #288

Merged
merged 51 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
4ec889c
Adding Rank in xform-engine
latin-panda Jan 21, 2025
fe70d69
Adding Rank demo form
latin-panda Jan 21, 2025
88539c8
installing vue-draggable-plus dependency
latin-panda Jan 21, 2025
defd00a
Adding Vue component for Rank
latin-panda Jan 21, 2025
6132e38
Integrating Rank from xform-engine to Rank from Web Forms
latin-panda Jan 21, 2025
9599af1
Simplified typing and added setValueState to update the currentState
latin-panda Jan 22, 2025
8b166e3
Fixes type warning
latin-panda Jan 22, 2025
62915f0
Format error message
latin-panda Jan 22, 2025
a9a724c
Adding constant for hold and drag
latin-panda Jan 22, 2025
b6824df
Fixing binding between engine and web forms
latin-panda Jan 22, 2025
5f9201d
Fixing codestyle and removing unneeded code
latin-panda Jan 22, 2025
8568fe0
Reusing common code between select and rank
latin-panda Jan 23, 2025
d127f11
Polishing code
latin-panda Jan 23, 2025
5f39d71
Fixes import and data type
latin-panda Jan 23, 2025
9133cff
Adds web forms test coverage
latin-panda Jan 23, 2025
6536500
Reverts changes around items and itemset and adds support for items i…
latin-panda Jan 23, 2025
0b8cb90
Includes demo form for rank with choice filter
latin-panda Jan 23, 2025
04f4fdc
Includes support for choice filter in Web Form's Rank Control
latin-panda Jan 25, 2025
aa12c6c
Saving value in keyboard events
latin-panda Jan 27, 2025
225e83e
update the value after the user has ranked and later added new option…
latin-panda Jan 27, 2025
9c7a8f7
Removed RankElement, Rank Type and added appearances
latin-panda Jan 27, 2025
df42f98
Makes Item and Itemset accept Rank Definition type
latin-panda Jan 27, 2025
48d6e4b
Renames test file and type in createItemCollection module
latin-panda Jan 27, 2025
ffcf446
Fixes correct values types and fixes naming of type assertion
latin-panda Jan 27, 2025
5479c5f
Renames single and multiple item codecs
latin-panda Jan 27, 2025
adb1ac0
Simplifying typing in createItemCollection
latin-panda Jan 27, 2025
acba007
Uses CSS variables instead of SASS variables
latin-panda Jan 27, 2025
261370c
Adding missing type in Rank Definition
latin-panda Jan 27, 2025
b1fc872
Fixes lint
latin-panda Jan 27, 2025
e7f6b61
Fixes lint
latin-panda Jan 27, 2025
d697d8f
Fixes error handling
latin-panda Jan 27, 2025
7ed379e
Adds relevant to rank choice-filter's demo form
latin-panda Jan 27, 2025
fda6382
Adds hold and drag just for touch events
latin-panda Jan 27, 2025
ecd9c1e
Makes buttons invisible but keeping its place
latin-panda Jan 27, 2025
b0f8b24
Fixes lint
latin-panda Jan 27, 2025
04b2f93
Fixes lint
latin-panda Jan 28, 2025
303c7bb
Fixes lint in web forms
latin-panda Jan 28, 2025
b38600f
Fixes type errors
latin-panda Jan 28, 2025
61e8070
Fixes GH Union type constituents must be sorted
latin-panda Jan 28, 2025
262b28f
Fixes UI to look like select and also disables buttons when it's firs…
latin-panda Jan 28, 2025
c51f1ac
Fixes UI to hide buttons when only 1 option is displayed
latin-panda Jan 28, 2025
372d8b8
Adds tests for rank in scenario suite
latin-panda Jan 29, 2025
105c6e4
Fixes style for disabled buttons and formats code style
latin-panda Jan 29, 2025
f5aef0b
Adds test in Web Form package for rank with choice filter
latin-panda Jan 30, 2025
78ed4bd
Add changeset for <rank>
latin-panda Jan 30, 2025
7203693
Adds support for readonly
latin-panda Jan 30, 2025
dbf54ef
Clarify changeset
latin-panda Jan 31, 2025
e91ad1e
Making DSL forms inline and improving test cases' description
latin-panda Jan 31, 2025
aba6361
Adds new test in scenario to ensure all values are included in rank
latin-panda Jan 31, 2025
4742935
Refactors based on feedback to simplify code and make clear ToDos for…
latin-panda Jan 31, 2025
1232cd8
Adding asserts for exception, adding JS Docs and decreasing highlight…
latin-panda Jan 31, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/proud-beans-march.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@getodk/xforms-engine': minor
'@getodk/web-forms': minor
'@getodk/scenario': minor
'@getodk/common': patch
---

Support for rank question types (`<odk:rank>`)
146 changes: 146 additions & 0 deletions packages/common/src/fixtures/rank/1-rank.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<?xml version="1.0"?>
<h:html xmlns="http://www.w3.org/2002/xforms" xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jr="http://openrosa.org/javarosa" xmlns:orx="http://openrosa.org/xforms"
xmlns:odk="http://www.opendatakit.org/xforms">
<h:head>
<h:title>Rank</h:title>
<model odk:xforms-version="1.0.0">
<itext>
<translation lang="English (en)">
<text id="decision_making-0">
<value>Health</value>
</text>
<text id="decision_making-1">
<value>Family and Friends</value>
</text>
<text id="decision_making-2">
<value>Career Growth and Learning Opportunities</value>
</text>
<text id="decision_making-3">
<value>Financial Stability</value>
</text>
<text id="decision_making-4">
<value>Pursuit of Hobbies and Passions</value>
</text>
<text id="decision_making-5">
<value>Environmental Sustainability</value>
</text>
<text id="decision_making-6">
<value>Time Management and Work-Life Balance</value>
</text>
<text id="decision_making-7">
<value>Building a Supportive Community</value>
</text>
<text id="decision_making-8">
<value>Personal Development and Mindfulness</value>
</text>
<text id="decision_making-9">
<value>Creativity and Innovation</value>
</text>
<text id="/data/priorities:label">
<value>What values guide your decision-making?</value>
</text>
</translation>
<translation lang="French (fr)">
<text id="decision_making-0">
<value>Santé</value>
</text>
<text id="decision_making-1">
<value>Famille et amis</value>
</text>
<text id="decision_making-2">
<value>Croissance professionnelle et opportunités d'apprentissage</value>
</text>
<text id="decision_making-3">
<value>Stabilité financière</value>
</text>
<text id="decision_making-4">
<value>Poursuite de loisirs et passions</value>
</text>
<text id="decision_making-5">
<value>Durabilité environnementale</value>
</text>
<text id="decision_making-6">
<value>Gestion du temps et équilibre vie professionnelle/vie personnelle</value>
</text>
<text id="decision_making-7">
<value>Construire une communauté solidaire</value>
</text>
<text id="decision_making-8">
<value>Développement personnel et pleine conscience</value>
</text>
<text id="decision_making-9">
<value>Créativité et innovation</value>
</text>
<text id="/data/priorities:label">
<value>Quelles valeurs guident votre prise de décision?</value>
</text>
</translation>
</itext>
<instance>
<data id="1_rank" version="2025011401">
<priorities/>
<meta>
<instanceID/>
</meta>
</data>
</instance>
<instance id="decision_making">
<root>
<item>
<itextId>decision_making-0</itextId>
<name>health</name>
</item>
<item>
<itextId>decision_making-1</itextId>
<name>family_and_friends</name>
</item>
<item>
<itextId>decision_making-2</itextId>
<name>career_growth_and_learning_opportunities</name>
</item>
<item>
<itextId>decision_making-3</itextId>
<name>financial_stability</name>
</item>
<item>
<itextId>decision_making-4</itextId>
<name>pursuit_of_hobbies_and_passions</name>
</item>
<item>
<itextId>decision_making-5</itextId>
<name>environmental_sustainability</name>
</item>
<item>
<itextId>decision_making-6</itextId>
<name>time_management_and_work_life_balance</name>
</item>
<item>
<itextId>decision_making-7</itextId>
<name>building_a_supportive_community</name>
</item>
<item>
<itextId>decision_making-8</itextId>
<name>personal_development_and_mindfulness</name>
</item>
<item>
<itextId>decision_making-9</itextId>
<name>creativity_and_innovation</name>
</item>
</root>
</instance>
<bind nodeset="/data/priorities" type="odk:rank"/>
<bind nodeset="/data/meta/instanceID" type="string" readonly="true()" jr:preload="uid"/>
</model>
</h:head>
<h:body>
<odk:rank ref="/data/priorities">
<label ref="jr:itext('/data/priorities:label')"/>
<itemset nodeset="randomize(instance('decision_making')/root/item)">
<value ref="name"/>
<label ref="jr:itext(itextId)"/>
</itemset>
</odk:rank>
</h:body>
</h:html>
162 changes: 162 additions & 0 deletions packages/common/src/fixtures/rank/2-rank-with-choice-filter.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
<?xml version="1.0"?>
<h:html xmlns="http://www.w3.org/2002/xforms" xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jr="http://openrosa.org/javarosa" xmlns:orx="http://openrosa.org/xforms"
xmlns:odk="http://www.opendatakit.org/xforms">
<h:head>
<h:title>Rank with choice filter</h:title>
<model odk:xforms-version="1.0.0">
<itext>
<translation lang="English (en)">
<text id="decision_making-0">
<value>Health</value>
</text>
<text id="decision_making-1">
<value>Family and Friends</value>
</text>
<text id="decision_making-2">
<value>Career Growth and Learning Opportunities</value>
</text>
<text id="decision_making-3">
<value>Financial Stability</value>
</text>
<text id="decision_making-4">
<value>Pursuit of Hobbies and Passions</value>
</text>
<text id="decision_making-5">
<value>Environmental Sustainability</value>
</text>
<text id="decision_making-6">
<value>Time Management and Work-Life Balance</value>
</text>
<text id="decision_making-7">
<value>Building a Supportive Community</value>
</text>
<text id="decision_making-8">
<value>Personal Development and Mindfulness</value>
</text>
<text id="decision_making-9">
<value>Creativity and Innovation</value>
</text>
<text id="/data/decision_making:label">
<value>Choose the values that guide your decision-making</value>
</text>
<text id="/data/priorities:label">
<value>Please prioritize the values that guide your decision-making</value>
</text>
</translation>
<translation lang="French (fr)">
<text id="decision_making-0">
<value>Santé</value>
</text>
<text id="decision_making-1">
<value>Famille et amis</value>
</text>
<text id="decision_making-2">
<value>Croissance professionnelle et opportunités d'apprentissage</value>
</text>
<text id="decision_making-3">
<value>Stabilité financière</value>
</text>
<text id="decision_making-4">
<value>Poursuite de loisirs et passions</value>
</text>
<text id="decision_making-5">
<value>Durabilité environnementale</value>
</text>
<text id="decision_making-6">
<value>Gestion du temps et équilibre vie professionnelle/vie personnelle</value>
</text>
<text id="decision_making-7">
<value>Construire une communauté solidaire</value>
</text>
<text id="decision_making-8">
<value>Développement personnel et pleine conscience</value>
</text>
<text id="decision_making-9">
<value>Créativité et innovation</value>
</text>
<text id="/data/decision_making:label">
<value>Choisissez les valeurs qui guident votre prise de décision</value>
</text>
<text id="/data/priorities:label">
<value>Veuillez prioriser les valeurs qui guident votre prise de décision</value>
</text>
</translation>
</itext>
<instance>
<data id="1_rank_with_choice_filter" version="2025011401">
<decision_making/>
<priorities/>
<meta>
<instanceID/>
</meta>
</data>
</instance>
<instance id="decision_making">
<root>
<item>
<itextId>decision_making-0</itextId>
<name>health</name>
</item>
<item>
<itextId>decision_making-1</itextId>
<name>family_and_friends</name>
</item>
<item>
<itextId>decision_making-2</itextId>
<name>career_growth_and_learning_opportunities</name>
</item>
<item>
<itextId>decision_making-3</itextId>
<name>financial_stability</name>
</item>
<item>
<itextId>decision_making-4</itextId>
<name>pursuit_of_hobbies_and_passions</name>
</item>
<item>
<itextId>decision_making-5</itextId>
<name>environmental_sustainability</name>
</item>
<item>
<itextId>decision_making-6</itextId>
<name>time_management_and_work_life_balance</name>
</item>
<item>
<itextId>decision_making-7</itextId>
<name>building_a_supportive_community</name>
</item>
<item>
<itextId>decision_making-8</itextId>
<name>personal_development_and_mindfulness</name>
</item>
<item>
<itextId>decision_making-9</itextId>
<name>creativity_and_innovation</name>
</item>
</root>
</instance>
<bind nodeset="/data/decision_making" type="string" required="true()"/>
<bind nodeset="/data/priorities" type="odk:rank" required="true()"
relevant="count-selected( /data/decision_making )&gt;0"/>
<bind nodeset="/data/meta/instanceID" type="string" readonly="true()" jr:preload="uid"/>
</model>
</h:head>
<h:body>
<select ref="/data/decision_making">
<label ref="jr:itext('/data/decision_making:label')"/>
<itemset nodeset="instance('decision_making')/root/item">
<value ref="name"/>
<label ref="jr:itext(itextId)"/>
</itemset>
</select>
<odk:rank ref="/data/priorities">
<label ref="jr:itext('/data/priorities:label')"/>
<itemset nodeset="instance('decision_making')/root/item[selected( /data/decision_making , name)]">
<value ref="name"/>
<label ref="jr:itext(itextId)"/>
</itemset>
</odk:rank>
</h:body>
</h:html>
16 changes: 16 additions & 0 deletions packages/common/src/test/fixtures/xform-dsl/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,22 @@ export const proposed_selectDynamic: Proposed_selectDynamic = (

export { proposed_selectDynamic as selectDynamic };

export const proposed_rankDynamic = (ref: string, nodesetRef: string): XFormsElement => {
const value = t('value ref="value"');
const label = t('label ref="label"');

const itemsetAttributes = new Map<string, string>();
itemsetAttributes.set('nodeset', nodesetRef);

const itemset = new TagXFormsElement('itemset', itemsetAttributes, [value, label]);
const rankAttributes = new Map<string, string>();
rankAttributes.set('ref', ref);

return new TagXFormsElement('odk:rank', rankAttributes, [itemset]) as XFormsElement;
};

export { proposed_rankDynamic as rankDynamic };

export const group = (ref: string, ...children: XFormsElement[]): XFormsElement => {
return t(`group ref="${ref}"`, ...children);
};
Expand Down
1 change: 0 additions & 1 deletion packages/common/types/JSONValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export type JSONValue =
export type JSONArray = readonly JSONValue[];

// This must be an interface to avoid a circular type reference error
// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style
export interface JSONObject {
readonly [key: string]: JSONValue;
}
19 changes: 19 additions & 0 deletions packages/scenario/src/answer/RankNodeAnswer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { JSONValue } from '@getodk/common/types/JSONValue.ts';
import type { RankNode } from '@getodk/xforms-engine';
import { ValueNodeAnswer } from './ValueNodeAnswer.ts';

export class RankNodeAnswer extends ValueNodeAnswer<RankNode> {
readonly stringValue: string;
readonly value: readonly string[];

constructor(node: RankNode) {
super(node);

this.stringValue = node.currentState.instanceValue;
this.value = node.currentState.value;
}

override inspectValue(): JSONValue {
return this.stringValue;
}
}
21 changes: 21 additions & 0 deletions packages/scenario/src/answer/RankValuesAnswer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { JSONValue } from '@getodk/common/types/JSONValue.ts';
import type { RankNode } from '@getodk/xforms-engine';
import { ComparableAnswer } from './ComparableAnswer.ts';

/**
* Produces a value which may be **assigned** to a {@link RankNode}, e.g.
* as part of a test's "act" phase.
*/
export class RankValuesAnswer extends ComparableAnswer {
readonly stringValue: string;

constructor(readonly values: readonly string[]) {
super();

this.stringValue = values.join(' ');
}

override inspectValue(): JSONValue {
return this.values;
}
}
Loading
Loading