Skip to content

Commit 52e941a

Browse files
nass600MihajloHomarobot-ci-heartex
authored
fix: LEAP-1892: [FE] Deeply nested Choices are visible when their parents are hidden (#7180)
Co-authored-by: nass600 <[email protected]> Co-authored-by: MihajloHoma <[email protected]> Co-authored-by: robot-ci-heartex <[email protected]>
1 parent 59499cd commit 52e941a

File tree

5 files changed

+457
-3
lines changed

5 files changed

+457
-3
lines changed

web/libs/editor/src/mixins/Visibility.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ const VisibilityMixin = types
4949
const tag = self.annotation.names.get(tagName);
5050

5151
if (!tag?.hasChoiceSelection && !choiceValue?.length) return false;
52+
if (tag.isVisible === false) return false;
5253

5354
return tag.hasChoiceSelection(choiceValue?.split(","), tag.selectedValues());
5455
},

web/libs/editor/src/regions/Result.js

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,24 @@ const Result = types
158158
get canBeSubmitted() {
159159
const control = self.from_name;
160160

161+
// Find the first node moving up in the tree with the given visibleWhen value
162+
function findParentWithVisibleWhen(control, visibleWhen) {
163+
let currentControl = control;
164+
165+
while (currentControl) {
166+
if (currentControl.visiblewhen === visibleWhen) return currentControl;
167+
168+
try {
169+
currentControl = getParent(currentControl);
170+
if (!currentControl) break;
171+
} catch {
172+
break;
173+
}
174+
}
175+
176+
return null;
177+
}
178+
161179
if (control.perregion) {
162180
const label = control.whenlabelvalue;
163181

@@ -201,13 +219,21 @@ const Result = types
201219
return true;
202220
};
203221

204-
if (control.visiblewhen === "choice-selected") {
222+
// When perregion is used, we must ignore the visibility of the components and focus only on the selection
223+
if (control.perregion && control.visiblewhen === "choice-selected") {
205224
return isChoiceSelected();
206225
}
226+
207227
if (control.visiblewhen === "choice-unselected") {
208228
return !isChoiceSelected();
209229
}
210230

231+
// We need to check if there is any node up in the tree with visibility restrictions so we can determine
232+
// if the element is selected considering its own visibility
233+
if (!control.perregion && findParentWithVisibleWhen(control, "choice-selected")) {
234+
return control.isVisible === false ? false : isChoiceSelected();
235+
}
236+
211237
return true;
212238
},
213239

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
export const simpleVisibleWhenVisibilityConfig = `<View>
2+
<Text name="text" value="$text"/>
3+
4+
<View name="Level 1">
5+
<Header value="Level 1"/>
6+
<Choices name="level1" toName="text" choice="single" showInLine="true">
7+
<Choice value="1A"/>
8+
<Choice value="1B"/>
9+
</Choices>
10+
</View>
11+
12+
<Choices
13+
name="level2" toName="text" choice="single" showInLine="true"
14+
visibleWhen="choice-selected"
15+
whenTagName="level1"
16+
whenChoiceValue="1A"
17+
>
18+
<Choice value="2A"/>
19+
<Choice value="2B"/>
20+
</Choices>
21+
22+
<Choices
23+
name="level3" toName="text" choice="single" showInLine="true"
24+
visibleWhen="choice-selected"
25+
whenTagName="level2"
26+
whenChoiceValue="2A"
27+
>
28+
<Choice value="3A"/>
29+
<Choice value="3B"/>
30+
</Choices>
31+
</View>`;
32+
33+
export const multipleChainedViewsVisibilityConfig = `<View>
34+
<Text name="text" value="$text"/>
35+
36+
<View name="Level 1">
37+
<Header value="Level 1"/>
38+
<Choices name="level1" toName="text" choice="single" showInLine="true">
39+
<Choice value="1A"/>
40+
<Choice value="1B"/>
41+
</Choices>
42+
</View>
43+
44+
<!-- Level 2 -->
45+
<View
46+
name="Level 2"
47+
visibleWhen="choice-selected"
48+
whenTagName="level1"
49+
whenChoiceValue="1A"
50+
>
51+
<Header value="Level 2"/>
52+
<Choices name="level2" toName="text" choice="single" showInLine="true">
53+
<Choice value="2A"/>
54+
<Choice value="2B"/>
55+
</Choices>
56+
</View>
57+
58+
<!-- Level 3A -->
59+
<View
60+
name="Level 3A"
61+
visibleWhen="choice-selected"
62+
whenTagName="level2"
63+
whenChoiceValue="2A"
64+
>
65+
<Header value="Level 3A"/>
66+
<Choices name="level3A" toName="text" choice="single" showInLine="true">
67+
<Choice value="3X"/>
68+
<Choice value="3Y"/>
69+
</Choices>
70+
</View>
71+
72+
<!-- Level 3B -->
73+
<View
74+
name="Level 3B"
75+
visibleWhen="choice-selected"
76+
whenTagName="level2"
77+
whenChoiceValue="2B"
78+
>
79+
<Header value="Level 3B"/>
80+
<Choices name="level3B" toName="text" choice="single" showInLine="true">
81+
<Choice value="3Q"/>
82+
<Choice value="3W"/>
83+
</Choices>
84+
</View>
85+
</View>`;
86+
87+
export const simpleUnselectedVisibilityConfig = `
88+
<View>
89+
<Text name="text" value="$text"/>
90+
91+
<Choices name="level1" toName="text" choice="single-radio" showInline="true" required="true">
92+
<Choice value="A" />
93+
<Choice value="B" />
94+
<Choice value="Other" />
95+
</Choices>
96+
<View name="level2" visibleWhen="choice-selected" whenTagName="level1" whenChoiceValue="A,B">
97+
<Header value="Selected level"/>
98+
<Choices name="selected-level" toName="text">
99+
<Choice value="1X"/>
100+
</Choices>
101+
</View>
102+
<View name="level3" visibleWhen="choice-unselected" whenChoiceValue="Other" whenTagName="level1">
103+
<Header value="Unselected level"/>
104+
<Choices name="unselected-level" toName="text">
105+
<Choice value="2X"/>
106+
</Choices>
107+
</View>
108+
</View>
109+
`;
110+
111+
export const textareaVisibilityConfig = `
112+
<View>
113+
<Header value="Author"/>
114+
<Text name="text" value="$text"/>
115+
<Choices name="author" toName="text" required="false" maxUsages="1">
116+
<Choice value="choice1"/>
117+
</Choices>
118+
119+
<View visibleWhen="choice-selected" whenTagName="author" whenChoiceValue="choice1">
120+
<Header value="New Author"/>
121+
<TextArea name="new_author" toName="text" maxSubmissions="1"/>
122+
</View>
123+
</View>
124+
`;
125+
126+
export const perRegionVisibilityConfig = `
127+
<View>
128+
<Image name="image" value="$image"/>
129+
130+
<RectangleLabels name="label" toName="image">
131+
<Label value="Tumor" background="green"/>
132+
</RectangleLabels>
133+
134+
<Choices name="classification" toName="image" perRegion="true">
135+
<Choice value="Benign"/>
136+
<Choice value="Malignant"/>
137+
<Choice value="Normal"/>
138+
</Choices>
139+
</View>
140+
`;
141+
142+
export const perRegionVisibilityResult = [
143+
{
144+
id: "Dx_aB91ISN",
145+
source: "$image",
146+
from_name: "label",
147+
to_name: "image",
148+
type: "rectanglelabels",
149+
origin: "manual",
150+
value: {
151+
height: 20,
152+
rotation: 0,
153+
width: 20,
154+
x: 40,
155+
y: 40,
156+
rectanglelabels: ["Tumor"],
157+
},
158+
},
159+
];
160+
161+
export const perRegionConditionalVisibilityConfig = `
162+
<View>
163+
<Image name="image" value="$image"/>
164+
<Rectangle name="rect" toName="image" />
165+
<View visibleWhen="region-selected">
166+
167+
<!-- Level 1 -->
168+
<View name="Level 1">
169+
<Header value="Level 1"/>
170+
<Choices perRegion="true" name="level1" toName="image" choice="single" showInLine="true">
171+
<Choice value="Start nesting choices"/>
172+
<Choice value="Show nothing"/>
173+
</Choices>
174+
</View>
175+
176+
<!-- Level 2 under Safety and Compliance -->
177+
<View name="Level 2 Safety and Compliance"
178+
visibleWhen="choice-selected"
179+
whenTagName="level1"
180+
whenChoiceValue="Start nesting choices">
181+
<Header value="Level 2"/>
182+
<Choices perRegion="true" name="level2_safety" toName="image" choice="single" showInLine="true"
183+
visibleWhen="choice-selected"
184+
whenTagName="level1"
185+
whenChoiceValue="Start nesting choices">
186+
<Choice value="A"/>
187+
<Choice value="B"/>
188+
</Choices>
189+
</View>
190+
<!-- Level 3 under Documentation and Record Keeping -->
191+
<View name="Level 3 Doc and Record"
192+
visibleWhen="choice-selected"
193+
whenTagName="level2_safety"
194+
whenChoiceValue="A">
195+
<Header value="Level 3"/>
196+
<Choices perRegion="true" name="level3_doc" toName="image" choice="single" showInLine="true"
197+
visibleWhen="choice-selected"
198+
whenTagName="level2_safety"
199+
whenChoiceValue="A">
200+
<Choice value="X"/>
201+
<Choice value="Y"/>
202+
</Choices>
203+
</View>
204+
<!-- Level 3 under Training and Familiarization (under Safety and Compliance) -->
205+
<View name="Level 3 Training"
206+
visibleWhen="choice-selected"
207+
whenTagName="level2_safety"
208+
whenChoiceValue="B">
209+
<Header value="Level 3"/>
210+
<Choices perRegion="true" name="level3_training" toName="image" choice="single" showInLine="true">
211+
<Choice value="Q"/>
212+
<Choice value="W"/>
213+
</Choices>
214+
</View>
215+
</View>
216+
</View>
217+
`;
218+
219+
export const perRegionConditionalVisibilityResult = [
220+
{
221+
original_width: 600,
222+
original_height: 403,
223+
image_rotation: 0,
224+
value: {
225+
x: 22.72106824925816,
226+
y: 47.18100890207715,
227+
width: 21.126607319485665,
228+
height: 31.157270029673583,
229+
rotation: 0,
230+
},
231+
id: "fgWSL6Nor_",
232+
from_name: "rect",
233+
to_name: "image",
234+
type: "rectangle",
235+
origin: "manual",
236+
},
237+
];
238+
239+
export const visibilityTextData = {
240+
text: "This text exists for no reason",
241+
};
242+
243+
export const visibilityImageData = {
244+
image: "https://data.heartex.net/open-images/train_0/mini/00155094b7acc33b.jpg",
245+
};

0 commit comments

Comments
 (0)