diff --git a/src/web/forms/DynamicForm.js b/src/web/forms/DynamicForm.js index 513addfe..2d21f0fa 100644 --- a/src/web/forms/DynamicForm.js +++ b/src/web/forms/DynamicForm.js @@ -35,7 +35,7 @@ import { } from '../../actions'; import { - checkVisibility, + referAndGetBool, } from './utils'; import FieldInsertPanel from './editor/FieldInsertPanel'; import FieldEditor from './editor/FieldEditor'; @@ -63,10 +63,16 @@ function makeCreateChildFields( const elements = !styles ? [] : styles.map((field, i) => { // Handle "show" prop - if (!checkVisibility(state, rootModel, field.show)) { + if (!referAndGetBool(state, rootModel, field.show)) { return null; } + // Translate "disabled" and "enabled" prop to boolean value + const disabled = ( + referAndGetBool(state, rootModel, field.disabled, false) || + !referAndGetBool(state, rootModel, field.enabled, true) + ); + const childFieldPath = `${fieldPath}[${i}]`; const component = fieldComponents[field.class] || fieldComponents.textinput; let children = null; @@ -108,15 +114,15 @@ function makeCreateChildFields( component, { key: i, + ...field, model: field.field ? `${rootModel}.${field.field}` : null, - label: field.label, fieldOptions: fieldOptions[field.field], + disabled, warning: warnings[field.field], rootModel, fieldEditProps, getPreviousData: field.ditto && getPreviousData && (() => getPreviousData && getPreviousData(field.field)), - ...field, }, children ); diff --git a/src/web/forms/__tests__/utils-test.js b/src/web/forms/__tests__/utils-test.js index ad062cda..fdab577b 100644 --- a/src/web/forms/__tests__/utils-test.js +++ b/src/web/forms/__tests__/utils-test.js @@ -19,11 +19,21 @@ jest.unmock('lodash.get'); jest.unmock('../utils'); -import { checkVisibility } from '../utils'; +import { referAndGetBool } from '../utils'; -describe('checkVisibility', () => { - it('returns false if `show` prop is false', () => { - expect(checkVisibility({}, 'hoge', false)).toBe(false); +describe('referAndGetBool', () => { + it('returns false if orgProp is false', () => { + expect(referAndGetBool({}, 'hoge', false)).toBe(false); + }); + + it('returns true if orgProp is true', () => { + expect(referAndGetBool({}, 'hoge', true)).toBe(true); + }); + + it('returns defaultValue if orgProp is undefined', () => { + expect(referAndGetBool({}, 'hoge', undefined)).toBe(true); + expect(referAndGetBool({}, 'hoge', undefined, true)).toBe(true); + expect(referAndGetBool({}, 'hoge', undefined, false)).toBe(false); }); it('returns referred value if show prop is given as string', () => { @@ -38,8 +48,8 @@ describe('checkVisibility', () => { }, }; - expect(checkVisibility(state, 'root', 'foo.bar')).toBe(true); - expect(checkVisibility(state, 'root', 'hoge.fuga')).toBe(false); + expect(referAndGetBool(state, 'root', 'foo.bar')).toBe(true); + expect(referAndGetBool(state, 'root', 'hoge.fuga')).toBe(false); }); it('handles Array as referent', () => { @@ -49,8 +59,8 @@ describe('checkVisibility', () => { }, }; - expect(checkVisibility(state, 'root', 'foo:aaa')).toBe(true); - expect(checkVisibility(state, 'root', 'foo:bbb')).toBe(false); + expect(referAndGetBool(state, 'root', 'foo:aaa')).toBe(true); + expect(referAndGetBool(state, 'root', 'foo:bbb')).toBe(false); }); it('handles an empty array as falthy', () => { @@ -60,7 +70,7 @@ describe('checkVisibility', () => { }, }; - expect(checkVisibility(state, 'root', 'foo')).toBe(false); + expect(referAndGetBool(state, 'root', 'foo')).toBe(false); }); it('handles empty rootPath', () => { @@ -71,8 +81,8 @@ describe('checkVisibility', () => { }, }; - expect(checkVisibility(state, null, 'foo')).toBe(true); - expect(checkVisibility(state, 'hoge', 'foo')).toBe(false); + expect(referAndGetBool(state, null, 'foo')).toBe(true); + expect(referAndGetBool(state, 'hoge', 'foo')).toBe(false); }); it('handles OR condition', () => { @@ -83,7 +93,7 @@ describe('checkVisibility', () => { }, }; - expect(checkVisibility(state, 'root', 'foo|bar')).toBe(true); + expect(referAndGetBool(state, 'root', 'foo|bar')).toBe(true); }); it('handles negative', () => { @@ -98,8 +108,8 @@ describe('checkVisibility', () => { }, }; - expect(checkVisibility(state, 'root', '!foo.bar')).toBe(false); - expect(checkVisibility(state, 'root', '!hoge.fuga')).toBe(true); + expect(referAndGetBool(state, 'root', '!foo.bar')).toBe(false); + expect(referAndGetBool(state, 'root', '!hoge.fuga')).toBe(true); }); it('handles negative on Array referent', () => { @@ -109,7 +119,7 @@ describe('checkVisibility', () => { }, }; - expect(checkVisibility(state, 'root', '!foo:aaa')).toBe(false); - expect(checkVisibility(state, 'root', '!foo:bbb')).toBe(true); + expect(referAndGetBool(state, 'root', '!foo:aaa')).toBe(false); + expect(referAndGetBool(state, 'root', '!foo:bbb')).toBe(true); }); }); diff --git a/src/web/forms/fields/SubformList/Row.js b/src/web/forms/fields/SubformList/Row.js index 5dedbeef..3b3bdec9 100644 --- a/src/web/forms/fields/SubformList/Row.js +++ b/src/web/forms/fields/SubformList/Row.js @@ -19,7 +19,7 @@ import React from 'react'; import classNames from 'classnames'; import _get from 'lodash.get'; import type { FormFieldDefinition } from '.'; -import { checkVisibility } from '../../utils'; +import { referAndGetBool } from '../../utils'; import { TextInputComponent } from '../TextInput'; import { CheckboxComponent } from '../Checkbox'; @@ -68,13 +68,8 @@ export default ({
{fields.map((field, i) => { - if (typeof field.show !== 'undefined' - && !checkVisibility(_value, null, field.show)) { - return null; - } else if (typeof field.hide !== 'undefined' - && checkVisibility(_value, null, field.hide)) { - return null; - } + if (!referAndGetBool(_value, null, field.show, true)) return null; + if (referAndGetBool(_value, null, field.hide, false)) return null; const component = typeof field.class === 'string' ? fieldComponents[field.class] : field.class; diff --git a/src/web/forms/fields/SubformList/__tests__/Row-test.js b/src/web/forms/fields/SubformList/__tests__/Row-test.js index b6a051de..0b6537a8 100644 --- a/src/web/forms/fields/SubformList/__tests__/Row-test.js +++ b/src/web/forms/fields/SubformList/__tests__/Row-test.js @@ -20,6 +20,7 @@ jest.unmock('react-redux'); jest.unmock('lodash.get'); jest.unmock('lodash.set'); jest.unmock('../Row'); +jest.unmock('../../../utils'); jest.unmock('../../common/fieldify'); import React from 'react'; diff --git a/src/web/forms/fields/TextInput/index.js b/src/web/forms/fields/TextInput/index.js index a9b5aead..53ddd0c0 100644 --- a/src/web/forms/fields/TextInput/index.js +++ b/src/web/forms/fields/TextInput/index.js @@ -60,6 +60,7 @@ const ReadOnly = ({ export const TextInputComponent = ({ value, onChange, + disabled = false, style, type = 'text', prefix, @@ -80,6 +81,7 @@ export const TextInputComponent = ({ }: { value: ?string, onChange: (newValue: string) => void, + disabled: boolean, style?: Object, type?: string, prefix?: string, @@ -152,6 +154,7 @@ export const TextInputComponent = ({ [`is-${size}`]: size, } )} + disabled={disabled} style={{ ...style, ...overrideStyle, diff --git a/src/web/forms/utils.js b/src/web/forms/utils.js index 1e2d1ebc..2cabcb87 100644 --- a/src/web/forms/utils.js +++ b/src/web/forms/utils.js @@ -37,13 +37,17 @@ function checkCondition(state: Object, rootPath: ?string, condition: string): bo return !!referent; } -export function checkVisibility(state: Object, rootPath: ?string, showProp: string|boolean = true) { - if (showProp === false) { - return false; - } +export function referAndGetBool( + state: Object, + rootPath: ?string, + orgProp: string|boolean, + defaultValue: boolean=true +) { + if (typeof orgProp === 'undefined') return defaultValue; + if (typeof orgProp === 'boolean') return orgProp; - if (typeof showProp === 'string') { - const conditions = showProp.split('|'); + if (typeof orgProp === 'string') { + const conditions = orgProp.split('|'); return conditions.some(condition => { let _condition = condition;