Skip to content
This repository was archived by the owner on Apr 18, 2024. It is now read-only.

Commit c38c288

Browse files
authored
feat: LSDV-4712: Add effect of skipDuplicates parameter on results editing (#1309)
* feat: LSDV-4712: Add effect of skipDuplicates parameter on results editing * test: LSDV-4712: Add test for skipDuplicates parameter on results editing * doc: LSDV-4712: Update skipDuplicates example in docs
1 parent f58da51 commit c38c288

File tree

6 files changed

+382
-15
lines changed

6 files changed

+382
-15
lines changed

e2e/fragments/AtOutliner.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ module.exports = {
2222
locateRegionItemIndex(idx) {
2323
return locate(this._regionListItemIndex).withText(`${idx}`).inside(this.locateRegionItemList());
2424
},
25+
locateSelectedItem(locator) {
26+
const selectedLocator = locate(this._regionListItemSelectedSelector).inside(this.locateRegionList());
27+
28+
return locator ? selectedLocator.find(locator) : selectedLocator;
29+
},
2530
seeRegions(count) {
2631
count && I.seeElement(this.locateRegionItemList().at(count));
2732
I.dontSeeElement(this.locateRegionItemList().at(count + 1));
@@ -30,10 +35,10 @@ module.exports = {
3035
I.click(this.locateRegionItemIndex(idx));
3136
},
3237
seeSelectedRegion() {
33-
I.seeElement(locate(this._regionListItemSelectedSelector).inside(this.locateRegionList()));
38+
I.seeElement(this.locateSelectedItem());
3439
},
3540
dontSeeSelectedRegion() {
36-
I.dontSeeElement(locate(this._regionListItemSelectedSelector).inside(this.locateRegionList()));
41+
I.dontSeeElement(this.locateSelectedItem());
3742
},
3843
/**
3944
* Drag and drop region through the outliner's regions tree

e2e/setup/feature-flags.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
module.exports = {
66
fflag_feat_front_lsdv_4659_skipduplicates_060323_short: true,
7+
fflag_feat_front_lsdv_4712_skipduplicates_editing_110423_short: true,
78
fflag_fix_font_lsdv_1148_hotkeys_namespaces_01022023_short: true,
89
fflag_fix_front_lsdv_4881_timeseries_points_missing_140423_short: true,
910
};

e2e/tests/textarea.skip-duplicates.test.js

Lines changed: 320 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const assert = require('assert');
2+
13
Feature('Skip duplicates (textarea)');
24

35
const SKIP_DUPLICATES_ERROR = 'There is already an entry with that text. Please enter unique text.';
@@ -206,4 +208,321 @@ Scenario('Independent skip duplicate values', async ({ I, LabelStudio, AtSidebar
206208
I.pressKey('Enter');
207209

208210
Modals.dontSeeWarning(SKIP_DUPLICATES_ERROR);
209-
});
211+
});
212+
213+
Scenario('Skip duplicate values on editing', async ({ I, LabelStudio, AtOutliner, Modals }) => {
214+
I.amOnPage('/');
215+
LabelStudio.setFeatureFlags({
216+
ff_front_1170_outliner_030222_short: true,
217+
});
218+
LabelStudio.init({
219+
data: { letter: 'Aa' },
220+
config: `<View>
221+
<Text name="letter" value="$letter"/>
222+
<Labels name="label" toName="letter">
223+
<Label value="Letter A" background="yellow"/>
224+
</Labels>
225+
<TextArea name="perText" toName="letter" skipDuplicates="true" editable="true"/>
226+
<TextArea name="perRegion" toName="letter" skipDuplicates="true" perRegion="true" maxsubmissions="5" editable="true"/>
227+
<TextArea name="perRegionAndAside" toName="letter" skipDuplicates="true" perRegion="true" maxsubmissions="5" displayMode="region-list" editable="true"/>
228+
</View>`,
229+
annotations: [{
230+
id: 'test',
231+
result: [
232+
{
233+
id: 'letter_A',
234+
from_name: 'label',
235+
to_name: 'letter',
236+
type: 'labels',
237+
value: { start: 0, end: 1, labels: ['Letter A'], text: 'A' },
238+
},
239+
{
240+
id: 'letter_a',
241+
from_name: 'label',
242+
to_name: 'letter',
243+
type: 'labels',
244+
value: { start: 1, end: 2, labels: ['Letter A'], text: 'a' },
245+
},
246+
],
247+
}],
248+
});
249+
LabelStudio.waitForObjectsReady();
250+
AtOutliner.seeRegions(2);
251+
252+
I.say('Check perText Textarea regions editing');
253+
{
254+
I.say('Create some random values in perText Textarea');
255+
I.fillField('[name="perText"]', 'A');
256+
I.pressKey('Enter');
257+
I.fillField('[name="perText"]', '1');
258+
I.pressKey('Enter');
259+
I.fillField('[name="perText"]', 'letter');
260+
I.pressKey('Enter');
261+
I.fillField('[name="perText"]', 'last');
262+
I.pressKey('Enter');
263+
264+
I.say('Try to create duplicate value by editing');
265+
266+
I.click(locate('[aria-label="Edit Region"]').inside('[data-testid="textarea-region"]').at(2), locate('.lsf-text-area').at(1));
267+
I.pressKey('Backspace');
268+
I.pressKey('A');
269+
I.pressKey('Enter');
270+
271+
Modals.seeWarning(SKIP_DUPLICATES_ERROR);
272+
Modals.closeWarning();
273+
274+
I.say('Check that these changes were not committed');
275+
276+
I.see('1', locate('.lsf-text-area').at(1).find(locate('.//*[./@data-testid = \'textarea-region\'][position()=2]')));
277+
I.dontSee('A', locate('.lsf-text-area').at(1).find(locate('.//*[./@data-testid = \'textarea-region\'][position()=2]')));
278+
279+
I.say('Delete second region and check results after that');
280+
I.click(locate('[aria-label="Delete Region"]'), locate('.lsf-text-area').at(1).find(locate('.//*[./@data-testid = \'textarea-region\'][position()=2]')));
281+
282+
I.see('A', locate('.lsf-text-area').at(1).find(locate('.//*[./@data-testid = \'textarea-region\'][position()=1]')));
283+
I.see('letter', locate('.lsf-text-area').at(1).find(locate('.//*[./@data-testid = \'textarea-region\'][position()=2]')));
284+
I.see('last', locate('.lsf-text-area').at(1).find(locate('.//*[./@data-testid = \'textarea-region\'][position()=3]')));
285+
286+
{
287+
const result = await LabelStudio.serialize();
288+
289+
assert.deepStrictEqual(
290+
result[2].value.text,
291+
['A', 'letter', 'last'],
292+
`There should be 3 specific text lines in the textarea result: ${JSON.stringify(['A', 'letter', 'last'])} but ${result[2].value.text} was given.`,
293+
);
294+
}
295+
296+
I.say('Check that skip duplication allow us to keep the same value after editing without errors');
297+
298+
I.click(locate('[aria-label="Edit Region"]').inside('[data-testid="textarea-region"]').at(2), locate('.lsf-text-area').at(1));
299+
I.pressKey(['CommandOrControl', 'a']);
300+
I.pressKey('Backspace');
301+
Array.from('letter').forEach(v => {
302+
I.pressKey(v);
303+
});
304+
I.pressKey('Enter');
305+
306+
I.see('letter', locate('.lsf-text-area').at(1).find(locate('.//*[./@data-testid = \'textarea-region\'][position()=2]')));
307+
Modals.dontSeeWarning(SKIP_DUPLICATES_ERROR);
308+
309+
{
310+
const result = await LabelStudio.serialize();
311+
312+
assert.deepStrictEqual(
313+
result[2].value.text,
314+
['A', 'letter', 'last'],
315+
`There should be 3 specific text lines in the textarea result: ${JSON.stringify(['A', 'letter', 'last'])} but ${result[2].value.text} was given.`,
316+
);
317+
}
318+
319+
I.say('Check that skip duplication allow us to set different value by editing and do not get errors');
320+
321+
I.click(locate('[aria-label="Edit Region"]').inside('[data-testid="textarea-region"]').at(2), locate('.lsf-text-area').at(1));
322+
I.pressKey(['CommandOrControl', 'a']);
323+
I.pressKey('Backspace');
324+
Array.from('other').forEach(v => {
325+
I.pressKey(v);
326+
});
327+
I.pressKey('Enter');
328+
329+
I.see('other', locate('.lsf-text-area').at(1).find(locate('.//*[./@data-testid = \'textarea-region\'][position()=2]')));
330+
Modals.dontSeeWarning(SKIP_DUPLICATES_ERROR);
331+
332+
{
333+
const result = await LabelStudio.serialize();
334+
335+
assert.deepStrictEqual(
336+
result[2].value.text,
337+
['A', 'other', 'last'],
338+
`There should be 3 specific text lines in the textarea result: ${JSON.stringify(['A', 'other', 'last'])} but ${result[2].value.text} was given.`,
339+
);
340+
}
341+
}
342+
343+
I.say('Check perRegion Textarea regions editing');
344+
{
345+
AtOutliner.clickRegion(1);
346+
I.say('Create some random values in perRegion Textarea');
347+
I.fillField('[name="perRegion"]', 'a');
348+
I.pressKey('Enter');
349+
I.fillField('[name="perRegion"]', '1');
350+
I.pressKey('Enter');
351+
I.fillField('[name="perRegion"]', 'letter');
352+
I.pressKey('Enter');
353+
I.fillField('[name="perRegion"]', 'last');
354+
I.pressKey('Enter');
355+
356+
I.say('Try to create duplicate value by editing');
357+
358+
I.click(locate('[aria-label="Edit Region"]').inside('[data-testid="textarea-region"]').at(2), locate('.lsf-text-area').at(2));
359+
I.pressKey('Backspace');
360+
I.pressKey('a');
361+
I.pressKey('Enter');
362+
363+
Modals.seeWarning(SKIP_DUPLICATES_ERROR);
364+
Modals.closeWarning();
365+
366+
I.say('Check that these changes were not committed');
367+
I.see('1', locate('.lsf-text-area').at(2).find(locate('.//*[./@data-testid = \'textarea-region\'][position()=2]')));
368+
I.dontSee('a', locate('.lsf-text-area').at(2).find(locate('.//*[./@data-testid = \'textarea-region\'][position()=2]')));
369+
370+
I.say('Delete second region and check results after that');
371+
I.click(locate('[aria-label="Delete Region"]'), locate('.lsf-text-area').at(2).find(locate('.//*[./@data-testid = \'textarea-region\'][position()=2]')));
372+
373+
I.see('a', locate('.lsf-text-area').at(2).find(locate('.//*[./@data-testid = \'textarea-region\'][position()=1]')));
374+
I.see('letter', locate('.lsf-text-area').at(2).find(locate('.//*[./@data-testid = \'textarea-region\'][position()=2]')));
375+
I.see('last', locate('.lsf-text-area').at(2).find(locate('.//*[./@data-testid = \'textarea-region\'][position()=3]')));
376+
377+
{
378+
const result = await LabelStudio.serialize();
379+
380+
assert.deepStrictEqual(
381+
result[1].value.text,
382+
['a', 'letter', 'last'],
383+
`There should be 3 specific text lines in the textarea result: ${JSON.stringify(['a', 'letter', 'last'])} but ${result[1].value.text} was given.`,
384+
);
385+
}
386+
387+
I.say('Check that skip duplication allow us to keep the same value after editing without errors');
388+
389+
I.click(locate('[aria-label="Edit Region"]').inside('[data-testid="textarea-region"]').at(2), locate('.lsf-text-area').at(2));
390+
I.pressKey(['CommandOrControl', 'a']);
391+
I.pressKey('Backspace');
392+
Array.from('letter').forEach(v => {
393+
I.pressKey(v);
394+
});
395+
I.pressKey('Enter');
396+
397+
I.see('letter', locate('.lsf-text-area').at(2).find(locate('.//*[./@data-testid = \'textarea-region\'][position()=2]')));
398+
Modals.dontSeeWarning(SKIP_DUPLICATES_ERROR);
399+
400+
{
401+
const result = await LabelStudio.serialize();
402+
403+
assert.deepStrictEqual(
404+
result[1].value.text,
405+
['a', 'letter', 'last'],
406+
`There should be 3 specific text lines in the textarea result: ${JSON.stringify(['a', 'letter', 'last'])} but ${result[1].value.text} was given.`,
407+
);
408+
}
409+
410+
I.say('Check that skip duplication allow us to set different value by editing and do not get errors');
411+
412+
I.click(locate('[aria-label="Edit Region"]').inside('[data-testid="textarea-region"]').at(2), locate('.lsf-text-area').at(2));
413+
I.pressKey(['CommandOrControl', 'a']);
414+
I.pressKey('Backspace');
415+
Array.from('other').forEach(v => {
416+
I.pressKey(v);
417+
});
418+
I.pressKey('Enter');
419+
420+
I.see('other', locate('.lsf-text-area').at(2).find(locate('.//*[./@data-testid = \'textarea-region\'][position()=2]')));
421+
Modals.dontSeeWarning(SKIP_DUPLICATES_ERROR);
422+
423+
{
424+
const result = await LabelStudio.serialize();
425+
426+
assert.deepStrictEqual(
427+
result[1].value.text,
428+
['a', 'other', 'last'],
429+
`There should be 3 specific text lines in the textarea result: ${JSON.stringify(['a', 'other', 'last'])} but ${result[1].value.text} was given.`,
430+
);
431+
}
432+
}
433+
434+
I.say('Check ocr-like perRegion Textarea regions editing');
435+
{
436+
AtOutliner.clickRegion(2);
437+
438+
I.say('Create some random values in ocr-like perRegion Textarea');
439+
I.fillField(AtOutliner.locateSelectedItem('.lsf-textarea-tag__form input'), 'One');
440+
I.pressKey('Enter');
441+
I.fillField(AtOutliner.locateSelectedItem('.lsf-textarea-tag__form input'), 'Two');
442+
I.pressKey('Enter');
443+
I.fillField(AtOutliner.locateSelectedItem('.lsf-textarea-tag__form input'), 'Three');
444+
I.pressKey('Enter');
445+
I.fillField(AtOutliner.locateSelectedItem('.lsf-textarea-tag__form input'), 'Four');
446+
I.pressKey('Enter');
447+
448+
I.say('Try to create duplicate value by editing');
449+
450+
I.click(AtOutliner.locateSelectedItem(locate('.lsf-textarea-tag__item:nth-child(2) input')));
451+
I.pressKey(['CommandOrControl', 'a']);
452+
I.pressKey('Backspace');
453+
I.pressKey('O');
454+
I.pressKey('n');
455+
I.pressKey('e');
456+
I.pressKey('Enter');
457+
458+
Modals.seeWarning(SKIP_DUPLICATES_ERROR);
459+
Modals.closeWarning();
460+
461+
I.say('Check that these changes were not committed');
462+
I.seeInField(AtOutliner.locateSelectedItem(locate('.lsf-textarea-tag__item:nth-child(2) input')), 'Two');
463+
I.dontSeeInField(AtOutliner.locateSelectedItem(locate('.lsf-textarea-tag__item:nth-child(2) input')), 'One');
464+
465+
I.say('Delete second region and check results after that');
466+
I.click(locate('[aria-label="Delete Region"]'), AtOutliner.locateSelectedItem(locate('.lsf-textarea-tag__item:nth-child(2)')));
467+
468+
I.seeInField(AtOutliner.locateSelectedItem(locate('.lsf-textarea-tag__item:nth-child(1) input')), 'One');
469+
I.seeInField(AtOutliner.locateSelectedItem(locate('.lsf-textarea-tag__item:nth-child(2) input')), 'Three');
470+
I.seeInField(AtOutliner.locateSelectedItem(locate('.lsf-textarea-tag__item:nth-child(3) input')), 'Four');
471+
472+
{
473+
const result = await LabelStudio.serialize();
474+
475+
assert.deepStrictEqual(
476+
result[3].value.text,
477+
['One', 'Three', 'Four'],
478+
`There should be 3 specific text lines in the textarea result: ${JSON.stringify(['One', 'Three', 'Four'])} but ${result[3].value.text} was given.`,
479+
);
480+
}
481+
482+
I.say('Check that skip duplication allow us to keep the same value after editing without errors');
483+
484+
I.click(AtOutliner.locateSelectedItem(locate('.lsf-textarea-tag__item:nth-child(2) input')));
485+
I.pressKey(['CommandOrControl', 'a']);
486+
I.pressKey('Backspace');
487+
Array.from('Three').forEach(v => {
488+
I.pressKey(v);
489+
});
490+
I.pressKey('Enter');
491+
492+
I.seeInField(AtOutliner.locateSelectedItem(locate('.lsf-textarea-tag__item:nth-child(2) input')), 'Three');
493+
Modals.dontSeeWarning(SKIP_DUPLICATES_ERROR);
494+
495+
{
496+
const result = await LabelStudio.serialize();
497+
498+
assert.deepStrictEqual(
499+
result[3].value.text,
500+
['One', 'Three', 'Four'],
501+
`There should be 3 specific text lines in the textarea result: ${JSON.stringify(['One', 'Three', 'Four'])} but ${result[3].value.text} was given.`,
502+
);
503+
}
504+
505+
I.say('Check that skip duplication allow us to set different value by editing and do not get errors');
506+
507+
I.click(AtOutliner.locateSelectedItem(locate('.lsf-textarea-tag__item:nth-child(2) input')));
508+
I.pressKey(['CommandOrControl', 'a']);
509+
I.pressKey('Backspace');
510+
Array.from('other').forEach(v => {
511+
I.pressKey(v);
512+
});
513+
I.pressKey('Enter');
514+
515+
I.seeInField(AtOutliner.locateSelectedItem(locate('.lsf-textarea-tag__item:nth-child(2) input')), 'other');
516+
Modals.dontSeeWarning(SKIP_DUPLICATES_ERROR);
517+
518+
{
519+
const result = await LabelStudio.serialize();
520+
521+
assert.deepStrictEqual(
522+
result[3].value.text,
523+
['One', 'other', 'Four'],
524+
`There should be 3 specific text lines in the textarea result: ${JSON.stringify(['One', 'other', 'Four'])} but ${result[3].value.text} was given.`,
525+
);
526+
}
527+
}
528+
});

src/regions/TextAreaRegion.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { guidGenerator } from '../core/Helpers';
1010

1111
import styles from './TextAreaRegion/TextAreaRegion.module.scss';
1212
import { HtxTextBox } from '../components/HtxTextBox/HtxTextBox';
13-
import { FF_DEV_1566, isFF } from '../utils/feature-flags';
13+
import { FF_DEV_1566, FF_LSDV_4712, isFF } from '../utils/feature-flags';
1414

1515
const Model = types
1616
.model('TextAreaRegionModel', {
@@ -40,6 +40,8 @@ const Model = types
4040
}))
4141
.actions(self => ({
4242
setValue(val) {
43+
if (isFF(FF_LSDV_4712) && (self._value === val || !self.parent.validateValue(val))) return;
44+
4345
self._value = val;
4446
self.parent.onChange();
4547
},

0 commit comments

Comments
 (0)