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

CC-872/DRYD-1047: Cloneable now takes a function as well as boolean #142

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 9 additions & 2 deletions docs/configuration/FieldConfiguration.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type FieldDescriptor = {
```
```
type FieldConfig = {
cloneable: boolean,
cloneable: boolean | function,
defaultValue: Immutable.Map | Immutable.List | string,
dataType: string,
messages: MessageDescriptorMap,
Expand Down Expand Up @@ -98,10 +98,17 @@ The field configuration object may contain the following properties:

### cloneable
```
cloneable: boolean = true
required: boolean | (computeContext) => boolean
```
If true, when a record is cloned, the value of this field is cloned to the new record. Otherwise, the field in the new record will be set to the default value if one exists; otherwise, it will be empty.

If a function is provided, the function will be called with a computeContext object as an argument, and must return a boolean.The computeContext has the following properties:

| Property | Type | Description |
| ----------------- | -------------- | ----------- |
| `form` | String | The name of the form (template) that is in use. |
| `roleNames` | Immutable.List | The current user's roles. |

### defaultValue
```
defaultValue: Array | Object | string | number | boolean
Expand Down
2 changes: 1 addition & 1 deletion src/actions/partialTermSearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const addTerm = (recordTypeConfig, vocabulary, displayName, partialTerm,
vocabulary,
},
});

let newRecordData = Immutable.Map();

if (clone) {
Expand Down
10 changes: 9 additions & 1 deletion src/actions/record.js
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,7 @@ export const readRecord = (config, recordTypeConfig, vocabularyConfig, csid, opt
export const createNewRecord = (config, recordTypeConfig, vocabularyConfig, cloneCsid) => (
(dispatch, getState) => {
let readClone;
const state = getState();

if (cloneCsid) {
const data = getRecordData(getState(), cloneCsid);
Expand All @@ -555,14 +556,20 @@ export const createNewRecord = (config, recordTypeConfig, vocabularyConfig, clon
});
}

const computeContext = {
form: getForm(state, recordTypeConfig.name),
roleNames: getUserRoleNames(state),
};

return (
readClone.then(() => dispatch({
type: CREATE_NEW_RECORD,
meta: {
config,
recordTypeConfig,
cloneCsid,
stickyFields: getStickyFields(getState()),
stickyFields: getStickyFields(state),
computeContext,
},
}))
);
Expand Down Expand Up @@ -610,6 +617,7 @@ export const createNewSubrecord = (
cloneCsid,
isDefault,
stickyFields: getStickyFields(getState()),
form: getForm(getState()),
},
}))
);
Expand Down
12 changes: 9 additions & 3 deletions src/helpers/configHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -490,13 +490,19 @@ export const isAutocompleteField = (fieldDescriptor) => {
return (JSON.stringify(viewType) === '"AutocompleteInput"');
};

export const isFieldCloneable = (fieldDescriptor) => {
export const isFieldCloneable = (fieldDescriptor, computeContext) => {
const config = fieldDescriptor[configKey];

if (config && 'cloneable' in config) {
return config.cloneable;
}

// eslint-disable-next-line prefer-destructuring
let cloneable = config.cloneable;

if (typeof (cloneable) === 'function') {
cloneable = cloneable(computeContext);
}
return !!cloneable;
}
return true;
};

Expand Down
14 changes: 7 additions & 7 deletions src/helpers/recordDataHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -350,12 +350,12 @@ export const createRecordData = (recordTypeConfig) => applyDefaults(
* Clear uncloneable fields from record data. Existing (not undefined) values in fields that are
* not cloneable are set to the default value if one exists, or undefined otherwise.
*/
export const clearUncloneable = (fieldDescriptor, data) => {
export const clearUncloneable = (fieldDescriptor, data, computeContext) => {
if (!fieldDescriptor) {
return data;
}
}

if (typeof data !== 'undefined' && !isFieldCloneable(fieldDescriptor)) {
if (typeof data !== 'undefined' && !isFieldCloneable(fieldDescriptor, computeContext)) {
// If the field has been configured as not cloneable and there is an existing value, replace
// the existing value with the default value if there is one, or undefined otherwise. The old
// UI did not set uncloneable fields to the default value, but I think this was an oversight.
Expand All @@ -369,13 +369,13 @@ export const clearUncloneable = (fieldDescriptor, data) => {

if (Immutable.Map.isMap(data)) {
return data.reduce((updatedData, child, name) => updatedData.set(
name, clearUncloneable(fieldDescriptor[name], child),
name, clearUncloneable(fieldDescriptor[name], child, computeContext),
), data);
}

if (Immutable.List.isList(data)) {
return data.reduce((updatedData, child, index) => updatedData.set(
index, clearUncloneable(fieldDescriptor, child),
index, clearUncloneable(fieldDescriptor, child, computeContext),
), data);
}

Expand Down Expand Up @@ -411,7 +411,7 @@ export const prepareClonedHierarchy = (fromCsid, data) => {
/**
* Create a new record as a clone of a given record.
*/
export const cloneRecordData = (recordTypeConfig, csid, data) => {
export const cloneRecordData = (recordTypeConfig, csid, data, computeContext) => {
if (!data) {
return data;
}
Expand All @@ -424,8 +424,8 @@ export const cloneRecordData = (recordTypeConfig, csid, data) => {
clone = clone.deleteIn(['document', `${NS_PREFIX}:account_permission`]);

// Reset fields that are configured as not cloneable.
clone = clearUncloneable(recordTypeConfig.fields, clone, computeContext);

clone = clearUncloneable(recordTypeConfig.fields, clone);
clone = prepareClonedHierarchy(csid, clone);

return clone;
Expand Down
13 changes: 9 additions & 4 deletions src/reducers/record.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ const sortFieldInstances = (state, action) => {
return setCurrentData(state, csid, updatedData);
};

const doCreateNew = (state, config, recordTypeConfig, options = {}) => {
const doCreateNew = (state, config, recordTypeConfig, computeContext, options = {}) => {

const {
cloneCsid,
subrecordName,
Expand All @@ -167,7 +168,7 @@ const doCreateNew = (state, config, recordTypeConfig, options = {}) => {
let data;

if (cloneCsid) {
data = cloneRecordData(recordTypeConfig, cloneCsid, getCurrentData(state, cloneCsid));
data = cloneRecordData(recordTypeConfig, cloneCsid, getCurrentData(state, cloneCsid), computeContext);
}

if (!data) {
Expand Down Expand Up @@ -210,6 +211,7 @@ const doCreateNew = (state, config, recordTypeConfig, options = {}) => {
nextState,
config,
subrecordTypeConfig,
computeContext,
{
cloneCsid: subrecordCsid,
subrecordName: name,
Expand Down Expand Up @@ -242,9 +244,10 @@ const createNewRecord = (state, action) => {
recordTypeConfig,
cloneCsid,
stickyFields,
computeContext,
} = action.meta;

return doCreateNew(state, config, recordTypeConfig, {
return doCreateNew(state, config, recordTypeConfig, computeContext, {
cloneCsid,
stickyFields,
});
Expand Down Expand Up @@ -519,9 +522,11 @@ const createNewSubrecord = (state, action) => {
cloneCsid,
isDefault,
stickyFields,
computeContext,
form,
} = action.meta;

let nextState = doCreateNew(state, config, subrecordTypeConfig, {
let nextState = doCreateNew(state, config, subrecordTypeConfig, computeContext, {
cloneCsid,
subrecordName,
stickyFields,
Expand Down
29 changes: 28 additions & 1 deletion test/specs/actions/record.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ describe('record action creator', () => {
it('should dispatch CREATE_NEW_RECORD', () => {
const store = mockStore({
prefs: Immutable.Map(),
user: Immutable.Map(),
authz: Immutable.Map(),
});

const config = {
Expand All @@ -134,6 +136,11 @@ describe('record action creator', () => {

const cloneCsid = undefined;

const computeContext = {
form: undefined,
roleNames: undefined,
};

return store.dispatch(createNewRecord(config, recordTypeConfig, vocabularyConfig, cloneCsid))
.then(() => {
const actions = store.getActions();
Expand All @@ -147,14 +154,14 @@ describe('record action creator', () => {
recordTypeConfig,
cloneCsid,
stickyFields: undefined,
computeContext,
},
});
});
});

it('should read the record to be cloned', () => {
const servicePath = 'collectionobjects';

const config = {
foo: 'abc',
};
Expand All @@ -177,8 +184,15 @@ describe('record action creator', () => {
const store = mockStore({
prefs: Immutable.Map(),
record: Immutable.Map(),
user: Immutable.Map(),
authz: Immutable.Map(),
});

const computeContext = {
form: undefined,
roleNames: undefined,
};

return store.dispatch(createNewRecord(config, recordTypeConfig, vocabularyConfig, cloneCsid))
.then(() => {
const actions = store.getActions();
Expand Down Expand Up @@ -215,6 +229,7 @@ describe('record action creator', () => {
recordTypeConfig,
cloneCsid,
stickyFields: undefined,
computeContext,
},
});
});
Expand Down Expand Up @@ -243,6 +258,8 @@ describe('record action creator', () => {
it('should dispatch CREATE_NEW_SUBRECORD', () => {
const store = mockStore({
prefs: Immutable.Map(),
user: Immutable.Map(),
authz: Immutable.Map(),
});

const config = {
Expand All @@ -264,6 +281,11 @@ describe('record action creator', () => {
const cloneCsid = undefined;
const isDefault = true;

// const computeContext = {
// form: undefined,
// roleNames: undefined,
// };

return store.dispatch(createNewSubrecord(
config, csid, csidField, subrecordName,
subrecordTypeConfig, subrecordVocabularyConfig, cloneCsid, isDefault,
Expand All @@ -284,6 +306,7 @@ describe('record action creator', () => {
cloneCsid,
isDefault,
stickyFields: undefined,
form: undefined,
},
});
});
Expand All @@ -293,6 +316,9 @@ describe('record action creator', () => {
const store = mockStore({
prefs: Immutable.Map(),
record: Immutable.Map(),
user: Immutable.Map(),
authz: Immutable.Map(),
// form: Immutable.Map(),
});

const config = {
Expand Down Expand Up @@ -364,6 +390,7 @@ describe('record action creator', () => {
cloneCsid,
isDefault,
stickyFields: undefined,
form: undefined,
},
});
});
Expand Down
4 changes: 2 additions & 2 deletions test/specs/components/sections/Footer.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe('Footer', () => {
const lists = this.container.querySelectorAll('ul');
const items = lists[1].querySelectorAll('li');

items[0].textContent.should.equal('Release 5.1');
items[0].textContent.should.equal('Release 5.1-1');
});

it('should render no version number if it is not present in system info', function test() {
Expand Down Expand Up @@ -120,6 +120,6 @@ describe('Footer', () => {
const lists = this.container.querySelectorAll('ul');
const items = lists[1].querySelectorAll('li');

items[2].textContent.should.equal('formatted somePlugin.name version 1.2.3');
items[2].textContent.should.equal('UC Berkeley formatted somePlugin.name version 1.2.3');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const store = mockStore({
},
},
}),
user: Immutable.Map(),
});

const context = {
Expand Down