Skip to content

Commit ff66aa5

Browse files
authored
Item 10437: Aliquot Field Inheritance (#872)
1 parent f7293bc commit ff66aa5

25 files changed

+1006
-316
lines changed

packages/components/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@labkey/components",
3-
"version": "2.195.1",
3+
"version": "2.196.0",
44
"description": "Components, models, actions, and utility functions for LabKey applications and pages",
55
"main": "dist/components.js",
66
"module": "dist/components.js",

packages/components/releaseNotes/components.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
# @labkey/components
22
Components, models, actions, and utility functions for LabKey applications and pages.
33

4+
### version 2.196.0
5+
*Released*: 7 July 2022
6+
* Item 10437: Aliquot Field Inheritance
7+
* Update DerivationDataScopeFieldOptions, SampleTypeDesigner, EntityInsertPanel and SamplesBulkUpdateForm to support aliquot & sample options
8+
49
### version 2.195.1
510
*Released*: 7 July 2022
611
* Issue 44599: Field editor PHI Level doesn't show correct value for a field if the admin user does not have that level of PHI access
Lines changed: 222 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,258 @@
11
import { mount } from 'enzyme';
2-
import React, { ReactNode } from 'react';
2+
import React from 'react';
33

4-
import { createFormInputId } from './actions';
5-
import { DOMAIN_FIELD_DERIVATION_DATA_SCOPE, DOMAIN_FIELD_NOT_LOCKED } from './constants';
4+
import { Radio } from 'react-bootstrap';
5+
6+
import { Alert } from '../base/Alert';
7+
8+
import { DERIVATION_DATA_SCOPES, DOMAIN_FIELD_NOT_LOCKED } from './constants';
69
import { DerivationDataScopeFieldOptions } from './DerivationDataScopeFieldOptions';
10+
import { PropDescType, TEXT_TYPE, UNIQUE_ID_TYPE } from './PropDescType';
711

812
describe('DerivationDataScopeFieldOptions', () => {
9-
test('Derivation Data Scope Field Options', () => {
10-
const label = 'Aliquot properties';
13+
test('Default config, new field', () => {
14+
const props = {
15+
index: 1,
16+
domainIndex: 1,
17+
label: null,
18+
onChange: jest.fn(),
19+
lockType: DOMAIN_FIELD_NOT_LOCKED,
20+
isExistingField: false,
21+
};
22+
23+
const wrapper = mount(<DerivationDataScopeFieldOptions {...props} />);
24+
25+
const sectionLabel = wrapper.find({ className: 'domain-field-section-heading domain-field-section-hdr' });
26+
expect(sectionLabel.length).toEqual(1);
27+
expect(sectionLabel.text()).toEqual('Derivation Data Scope');
28+
29+
const radios = wrapper.find(Radio);
30+
expect(radios).toHaveLength(3);
31+
expect(radios.at(0).prop('checked')).toBeTruthy();
32+
expect(radios.at(0).prop('disabled')).toBeFalsy();
33+
expect(radios.at(0).text()).toBe('Editable for parent data only (default)');
34+
expect(radios.at(1).prop('checked')).toBeFalsy();
35+
expect(radios.at(1).prop('disabled')).toBeFalsy();
36+
expect(radios.at(1).text()).toBe('Editable for child data only');
37+
expect(radios.at(2).prop('checked')).toBeFalsy();
38+
expect(radios.at(2).prop('disabled')).toBeFalsy();
39+
expect(radios.at(2).text()).toBe('Editable for parent and child data independently');
40+
expect(wrapper.find(Alert)).toHaveLength(0);
41+
42+
wrapper.unmount();
43+
});
44+
45+
test('Existing field, value = ParentOnly', () => {
46+
const props = {
47+
index: 1,
48+
domainIndex: 1,
49+
label: null,
50+
onChange: jest.fn(),
51+
lockType: DOMAIN_FIELD_NOT_LOCKED,
52+
isExistingField: true,
53+
value: DERIVATION_DATA_SCOPES.PARENT_ONLY,
54+
};
55+
56+
const wrapper = mount(<DerivationDataScopeFieldOptions {...props} />);
1157

58+
const radios = wrapper.find(Radio);
59+
expect(radios).toHaveLength(3);
60+
expect(radios.at(0).prop('checked')).toBeTruthy();
61+
expect(radios.at(0).prop('disabled')).toBeFalsy();
62+
expect(radios.at(1).prop('checked')).toBeFalsy();
63+
expect(radios.at(1).prop('disabled')).toBeTruthy();
64+
expect(radios.at(2).prop('checked')).toBeFalsy();
65+
expect(radios.at(2).prop('disabled')).toBeFalsy();
66+
expect(wrapper.find(Alert)).toHaveLength(0);
67+
68+
wrapper.unmount();
69+
});
70+
71+
test('Existing field, value is empty', () => {
72+
const props = {
73+
index: 1,
74+
domainIndex: 1,
75+
label: null,
76+
onChange: jest.fn(),
77+
lockType: DOMAIN_FIELD_NOT_LOCKED,
78+
isExistingField: true,
79+
value: '',
80+
};
81+
82+
const wrapper = mount(<DerivationDataScopeFieldOptions {...props} />);
83+
84+
const radios = wrapper.find(Radio);
85+
expect(radios).toHaveLength(3);
86+
expect(radios.at(0).prop('checked')).toBeTruthy();
87+
expect(radios.at(0).prop('disabled')).toBeFalsy();
88+
expect(radios.at(1).prop('checked')).toBeFalsy();
89+
expect(radios.at(1).prop('disabled')).toBeTruthy();
90+
expect(radios.at(2).prop('checked')).toBeFalsy();
91+
expect(radios.at(2).prop('disabled')).toBeFalsy();
92+
expect(wrapper.find(Alert)).toHaveLength(0);
93+
94+
wrapper.unmount();
95+
});
96+
97+
test('Existing field, value = ChildOnly', () => {
98+
const props = {
99+
index: 1,
100+
domainIndex: 1,
101+
label: null,
102+
onChange: jest.fn(),
103+
lockType: DOMAIN_FIELD_NOT_LOCKED,
104+
isExistingField: true,
105+
value: DERIVATION_DATA_SCOPES.CHILD_ONLY,
106+
};
107+
108+
const wrapper = mount(<DerivationDataScopeFieldOptions {...props} />);
109+
110+
const radios = wrapper.find(Radio);
111+
expect(radios).toHaveLength(3);
112+
expect(radios.at(0).prop('checked')).toBeFalsy();
113+
expect(radios.at(0).prop('disabled')).toBeTruthy();
114+
expect(radios.at(0).text()).toBe('Editable for parent data only (default)');
115+
expect(radios.at(1).prop('checked')).toBeTruthy();
116+
expect(radios.at(1).prop('disabled')).toBeFalsy();
117+
expect(radios.at(1).text()).toBe('Editable for child data only');
118+
expect(radios.at(2).prop('checked')).toBeFalsy();
119+
expect(radios.at(2).prop('disabled')).toBeFalsy();
120+
expect(radios.at(2).text()).toBe('Editable for parent and child data independently');
121+
expect(wrapper.find(Alert)).toHaveLength(0);
122+
123+
wrapper.unmount();
124+
});
125+
126+
test('Existing field, value = All', () => {
127+
const props = {
128+
index: 1,
129+
domainIndex: 1,
130+
label: null,
131+
onChange: jest.fn(),
132+
lockType: DOMAIN_FIELD_NOT_LOCKED,
133+
isExistingField: true,
134+
value: DERIVATION_DATA_SCOPES.ALL,
135+
};
136+
137+
const wrapper = mount(<DerivationDataScopeFieldOptions {...props} />);
138+
139+
const radios = wrapper.find(Radio);
140+
expect(radios).toHaveLength(3);
141+
expect(radios.at(0).prop('checked')).toBeFalsy();
142+
expect(radios.at(0).prop('disabled')).toBeTruthy();
143+
expect(radios.at(1).prop('checked')).toBeFalsy();
144+
expect(radios.at(1).prop('disabled')).toBeTruthy();
145+
expect(radios.at(2).prop('checked')).toBeTruthy();
146+
expect(radios.at(2).prop('disabled')).toBeFalsy();
147+
expect(wrapper.find(Alert)).toHaveLength(0);
148+
149+
wrapper.unmount();
150+
});
151+
152+
test('With config, show = true', () => {
153+
const label = 'Sample/Aliquot Options';
154+
const warning =
155+
"Updating a 'Samples Only' field to be 'Samples and Aliquots' will blank out the field values for all aliquots. This action cannot be undone.";
12156
const props = {
13157
index: 1,
14158
domainIndex: 1,
15159
label,
16160
onChange: jest.fn(),
17161
lockType: DOMAIN_FIELD_NOT_LOCKED,
162+
config: {
163+
show: true,
164+
sectionTitle: 'Sample/Aliquot Options',
165+
labelAll: 'Separately editable for samples and aliquots',
166+
labelChild: 'Editable for aliquots only',
167+
labelParent: 'Editable for samples only (default)',
168+
helpLinkNode: <>help</>,
169+
scopeChangeWarning: warning,
170+
},
171+
isExistingField: true,
172+
value: DERIVATION_DATA_SCOPES.PARENT_ONLY,
18173
};
19174

20-
const aliquot = mount(<DerivationDataScopeFieldOptions {...props} />);
175+
const wrapper = mount(<DerivationDataScopeFieldOptions {...props} />);
21176

22-
// Verify label
23-
const sectionLabel = aliquot.find({ className: 'domain-field-section-heading domain-field-section-hdr' });
177+
const sectionLabel = wrapper.find({ className: 'domain-field-section-heading domain-field-section-hdr' });
24178
expect(sectionLabel.length).toEqual(1);
25179
expect(sectionLabel.text()).toEqual(label);
26180

27-
const fieldName = createFormInputId(DOMAIN_FIELD_DERIVATION_DATA_SCOPE, 1, 1);
28-
// Test format field initial value
29-
let checkbox = aliquot.find({ id: fieldName, bsClass: 'checkbox' });
30-
expect(checkbox.length).toEqual(1);
31-
expect(checkbox.props().checked).toEqual(false);
181+
const radios = wrapper.find(Radio);
182+
expect(radios).toHaveLength(3);
183+
expect(radios.at(0).prop('checked')).toBeTruthy();
184+
expect(radios.at(0).text()).toBe('Editable for samples only (default)');
185+
expect(radios.at(1).prop('checked')).toBeFalsy();
186+
expect(radios.at(1).text()).toBe('Editable for aliquots only');
187+
expect(radios.at(2).prop('checked')).toBeFalsy();
188+
expect(radios.at(2).text()).toBe('Separately editable for samples and aliquots');
189+
expect(wrapper.find(Alert)).toHaveLength(0);
32190

33-
// Verify format value changes with props
34-
aliquot.setProps({ value: 'ChildOnly' });
35-
checkbox = aliquot.find({ id: fieldName, bsClass: 'checkbox' });
36-
expect(checkbox.props().checked).toEqual(true);
191+
wrapper.unmount();
192+
});
37193

38-
aliquot.unmount();
194+
test('With config, show = false', () => {
195+
const label = 'Sample/Aliquot Options';
196+
const props = {
197+
index: 1,
198+
domainIndex: 1,
199+
label,
200+
onChange: jest.fn(),
201+
lockType: DOMAIN_FIELD_NOT_LOCKED,
202+
config: {
203+
show: false,
204+
},
205+
};
206+
207+
const wrapper = mount(<DerivationDataScopeFieldOptions {...props} />);
208+
expect(wrapper).toEqual({});
209+
wrapper.unmount();
39210
});
40211

41-
test('With config', () => {
42-
const label = 'Aliquot field';
212+
test('With config, isExistingField is not applicable', () => {
213+
const props = {
214+
index: 1,
215+
domainIndex: 1,
216+
label: null,
217+
onChange: jest.fn(),
218+
lockType: DOMAIN_FIELD_NOT_LOCKED,
219+
isExistingField: true,
220+
value: DERIVATION_DATA_SCOPES.ALL,
221+
config: {
222+
show: true,
223+
dataTypeFilter: (dataType: PropDescType) => !dataType.isUniqueId(),
224+
},
225+
fieldDataType: UNIQUE_ID_TYPE,
226+
};
227+
228+
const wrapper = mount(<DerivationDataScopeFieldOptions {...props} />);
43229

230+
expect(wrapper).toEqual({});
231+
232+
wrapper.unmount();
233+
});
234+
235+
test('With config, isExistingField is applicable', () => {
44236
const props = {
45237
index: 1,
46238
domainIndex: 1,
47-
label,
239+
label: null,
48240
onChange: jest.fn(),
49241
lockType: DOMAIN_FIELD_NOT_LOCKED,
242+
isExistingField: true,
243+
value: DERIVATION_DATA_SCOPES.ALL,
50244
config: {
51245
show: true,
52-
disable: true,
53-
sectionTitle: 'Aliquot field',
54-
fieldLabel: 'Aliquot Only',
246+
dataTypeFilter: (dataType: PropDescType) => !dataType.isUniqueId(),
55247
},
248+
fieldDataType: TEXT_TYPE,
56249
};
57250

58-
const aliquot = mount(<DerivationDataScopeFieldOptions {...props} />);
59-
const fieldName = createFormInputId(DOMAIN_FIELD_DERIVATION_DATA_SCOPE, 1, 1);
251+
const wrapper = mount(<DerivationDataScopeFieldOptions {...props} />);
252+
253+
const radios = wrapper.find(Radio);
254+
expect(radios).toHaveLength(3);
60255

61-
const checkbox = aliquot.find({ id: fieldName, bsClass: 'checkbox' });
62-
expect(checkbox.props().disabled).toEqual(true);
63-
aliquot.unmount();
256+
wrapper.unmount();
64257
});
65258
});

0 commit comments

Comments
 (0)