diff --git a/packages/apostrophe/lib/compose-filters.js b/packages/apostrophe/lib/compose-filters.js new file mode 100644 index 0000000000..cb3c724052 --- /dev/null +++ b/packages/apostrophe/lib/compose-filters.js @@ -0,0 +1,51 @@ +/** + * Shared utility for composing filters in doc-type and page modules. + * + * Transforms a filters object (keyed by name) into an array of filter + * definitions with normalized inputType, default values, and null choices. + * + * This was previously duplicated between: + * - @apostrophecms/doc-type/index.js composeFilters() + * - @apostrophecms/page/index.js composeFilters() + * + * @param {Object} filters - An object keyed by filter name, where each value + * is a filter definition object. + * @returns {Array} An array of composed filter objects with `name` property added. + */ +module.exports = function composeFilters(filters) { + const composed = Object.entries(filters) + .map(([ name, filter ]) => ({ + name, + ...filter, + inputType: filter.inputType || 'select' + })); + + // Add a null choice if not already added or set to `required` + composed.forEach((filter) => { + if (Array.isArray(filter.choices)) { + if ( + !filter.required && + !filter.choices.find((choice) => choice.value === null) + ) { + filter.def = null; + filter.choices = filter.inputType === 'checkbox' + ? filter.choices + : filter.choices.concat({ + value: null, + label: 'apostrophe:none' + }); + } + } else { + // Dynamic choices from the REST API, but + // we need a label for "no opinion" + filter.nullLabel = filter.inputType === 'radio' + ? 'apostrophe:any' + : 'apostrophe:filterMenuChooseOne'; + } + if (filter.inputType === 'checkbox') { + filter.def = []; + } + }); + + return composed; +}; diff --git a/packages/apostrophe/modules/@apostrophecms/doc-type/index.js b/packages/apostrophe/modules/@apostrophecms/doc-type/index.js index 3b3bde0f7d..ed0593c3b0 100644 --- a/packages/apostrophe/modules/@apostrophecms/doc-type/index.js +++ b/packages/apostrophe/modules/@apostrophecms/doc-type/index.js @@ -1675,40 +1675,7 @@ module.exports = { }, composeFilters() { - // TODO: keep in sync with page/index.js composeFilters - self.filters = Object.entries(self.filters) - .map(([ name, filter ]) => ({ - name, - ...filter, - inputType: filter.inputType || 'select' - })); - - // Add a null choice if not already added or set to `required` - self.filters.forEach((filter) => { - if (Array.isArray(filter.choices)) { - if ( - !filter.required && - !filter.choices.find((choice) => choice.value === null) - ) { - filter.def = null; - filter.choices = filter.inputType === 'checkbox' - ? filter.choices - : filter.choices.concat({ - value: null, - label: 'apostrophe:none' - }); - } - } else { - // Dynamic choices from the REST API, but - // we need a label for "no opinion" - filter.nullLabel = filter.inputType === 'radio' - ? 'apostrophe:any' - : 'apostrophe:filterMenuChooseOne'; - } - if (filter.inputType === 'checkbox') { - filter.def = []; - } - }); + self.filters = require('../../../lib/compose-filters')(self.filters); }, composeColumns() { diff --git a/packages/apostrophe/modules/@apostrophecms/page/index.js b/packages/apostrophe/modules/@apostrophecms/page/index.js index e68c45e975..e05b07326c 100644 --- a/packages/apostrophe/modules/@apostrophecms/page/index.js +++ b/packages/apostrophe/modules/@apostrophecms/page/index.js @@ -3304,40 +3304,7 @@ database.`); }); }, composeFilters() { - // TODO: keep in sync with doc-type/index.js composeFilters - self.filters = Object.entries(self.filters) - .map(([ name, filter ]) => ({ - name, - ...filter, - inputType: filter.inputType || 'select' - })); - - // Add a null choice if not already added or set to `required` - self.filters.forEach((filter) => { - if (Array.isArray(filter.choices)) { - if ( - !filter.required && - !filter.choices.find((choice) => choice.value === null) - ) { - filter.def = null; - filter.choices = filter.inputType === 'checkbox' - ? filter.choices - : filter.choices.concat({ - value: null, - label: 'apostrophe:none' - }); - } - } else { - // Dynamic choices from the REST API, but - // we need a label for "no opinion" - filter.nullLabel = filter.inputType === 'radio' - ? 'apostrophe:any' - : 'apostrophe:filterMenuChooseOne'; - } - if (filter.inputType === 'checkbox') { - filter.def = []; - } - }); + self.filters = require('../../../lib/compose-filters')(self.filters); }, async getBatchArchivePatches(req, ids) { const batchReq = req.clone({