diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fb3c746f2..13de03d97b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ did not actually use any noncompliant cookie names or values, so there was no vu ### Changes * Removes postcss plugin and webpack loader used for breakpoint preview mode. Uses instead the new `postcss-viewport-to-container-toggle` plugin in the webpack config. +* Removes error messages in server console for hidden fields. These messages should not have been printed out in the server console in the first place. +* Removes invalid error messages on select fields appearing while opening an existing valid document. ## 4.9.0 (2024-10-31) diff --git a/modules/@apostrophecms/schema/index.js b/modules/@apostrophecms/schema/index.js index 018cad830b..66cec3f1d7 100644 --- a/modules/@apostrophecms/schema/index.js +++ b/modules/@apostrophecms/schema/index.js @@ -577,10 +577,21 @@ module.exports = { // `destination` (the current level). This allows resolution of relative // `following` paths during sanitization. - async convert(req, schema, data, destination, { fetchRelationships = true, ancestors = [] } = {}) { + async convert( + req, + schema, + data, + destination, + { + fetchRelationships = true, + ancestors = [], + isParentVisible = true + } = {} + ) { const options = { fetchRelationships, - ancestors + ancestors, + isParentVisible }; if (Array.isArray(req)) { throw new Error('convert invoked without a req, do you have one in your context?'); @@ -603,6 +614,9 @@ module.exports = { if (convert) { try { + const isAllParentsVisible = isParentVisible === false + ? false + : await self.isVisible(req, schema, destination, field.name); const isRequired = await self.isFieldRequired(req, field, destination); await convert( req, @@ -612,7 +626,10 @@ module.exports = { }, data, destination, - options + { + ...options, + isParentVisible: isAllParentsVisible + } ); } catch (error) { if (Array.isArray(error)) { @@ -635,7 +652,9 @@ module.exports = { if (error.path) { // `self.isVisible` will only throw for required fields that have // an external condition containing an unknown module or method: - const isVisible = await self.isVisible(req, schema, destination, error.path); + const isVisible = isParentVisible === false + ? false + : await self.isVisible(req, schema, destination, error.path); if (!isVisible) { // It is not reasonable to enforce required, @@ -652,10 +671,15 @@ module.exports = { // for a field that is not visible should be quietly discarded. // We only worry about this if the value is not valid, as otherwise // it's a kindness to save the work so the user can toggle back to it - destination[field.name] = klona((field.def !== undefined) ? field.def : self.fieldTypes[field.type]?.def); + destination[field.name] = klona((field.def !== undefined) + ? field.def + : self.fieldTypes[field.type]?.def); continue; } } + if (isParentVisible === false) { + continue; + } } if (!Array.isArray(error) && typeof error !== 'string') { @@ -907,7 +931,7 @@ module.exports = { const find = manager.find; const options = { - find: find, + find, builders: { relationships: withRelationshipsNext[relationship._dotPath] || false } }; const subname = relationship.name + ':' + type; @@ -960,7 +984,7 @@ module.exports = { const find = manager.find; const options = { - find: find, + find, builders: { relationships: withRelationshipsNext[relationship._dotPath] || false } }; @@ -1195,7 +1219,7 @@ module.exports = { const idsStorage = field.idsStorage; const ids = await query.toDistinct(idsStorage); const manager = self.apos.doc.getManager(field.withType); - const relationshipQuery = manager.find(query.req, { aposDocId: { $in: ids } }).project(manager.getRelationshipQueryBuilderChoicesProjection({ field: field })); + const relationshipQuery = manager.find(query.req, { aposDocId: { $in: ids } }).project(manager.getRelationshipQueryBuilderChoicesProjection({ field })); if (field.builders) { relationshipQuery.applyBuilders(field.builders); } @@ -1798,9 +1822,9 @@ module.exports = { const values = await query.toDistinct(field.name); const choices = _.map(values, function (value) { - const choice = _.find(allChoices, { value: value }); + const choice = _.find(allChoices, { value }); return { - value: value, + value, label: choice && (choice.label || value) }; }); @@ -1983,7 +2007,7 @@ module.exports = { fields[name] = component; } browserOptions.action = self.action; - browserOptions.components = { fields: fields }; + browserOptions.components = { fields }; browserOptions.fieldMetadataComponents = self.fieldMetadataComponents; browserOptions.customCellIndicators = self.uiManagerIndicators; return browserOptions; diff --git a/modules/@apostrophecms/schema/lib/addFieldTypes.js b/modules/@apostrophecms/schema/lib/addFieldTypes.js index 3741962f2c..1cf220f2c5 100644 --- a/modules/@apostrophecms/schema/lib/addFieldTypes.js +++ b/modules/@apostrophecms/schema/lib/addFieldTypes.js @@ -756,7 +756,17 @@ module.exports = (self) => { self.addFieldType({ name: 'array', - async convert(req, field, data, destination, { fetchRelationships = true, ancestors = [] } = {}) { + async convert( + req, + field, + data, + destination, + { + fetchRelationships = true, + ancestors = [], + isParentVisible = true + } = {} + ) { const schema = field.schema; data = data[field.name]; if (!Array.isArray(data)) { @@ -779,7 +789,8 @@ module.exports = (self) => { try { const options = { fetchRelationships, - ancestors: [ ...ancestors, destination ] + ancestors: [ ...ancestors, destination ], + isParentVisible }; await self.convert(req, schema, datum, result, options); } catch (e) { @@ -861,9 +872,18 @@ module.exports = (self) => { self.addFieldType({ name: 'object', - async convert(req, field, data, destination, { - fetchRelationships = true, ancestors = {}, doc = {} - } = {}) { + async convert( + req, + field, + data, + destination, + { + fetchRelationships = true, + ancestors = {}, + isParentVisible = true, + doc = {} + } = {} + ) { data = data[field.name]; const schema = field.schema; const errors = []; @@ -873,7 +893,8 @@ module.exports = (self) => { }; const options = { fetchRelationships, - ancestors: [ ...ancestors, destination ] + ancestors: [ ...ancestors, destination ], + isParentVisible }; if (data == null || typeof data !== 'object' || Array.isArray(data)) { data = {}; @@ -963,8 +984,20 @@ module.exports = (self) => { // properties is handled at a lower level in a beforeSave // handler of the doc-type module. - async convert(req, field, data, destination, { fetchRelationships = true } = {}) { - const options = { fetchRelationships }; + async convert( + req, + field, + data, + destination, + { + fetchRelationships = true, + isParentVisible = true + } = {} + ) { + const options = { + fetchRelationships, + isParentVisible + }; const manager = self.apos.doc.getManager(field.withType); if (!manager) { throw Error('relationship with type ' + field.withType + ' unrecognized'); diff --git a/modules/@apostrophecms/schema/ui/apos/mixins/AposInputChoicesMixin.js b/modules/@apostrophecms/schema/ui/apos/mixins/AposInputChoicesMixin.js index c83d6e4615..b74fb2ca90 100644 --- a/modules/@apostrophecms/schema/ui/apos/mixins/AposInputChoicesMixin.js +++ b/modules/@apostrophecms/schema/ui/apos/mixins/AposInputChoicesMixin.js @@ -10,7 +10,8 @@ const DEBOUNCE_TIMEOUT = 500; export default { data() { return { - choices: [] + choices: [], + enableValidate: false }; }, @@ -33,6 +34,7 @@ export default { methods: { async getChoices() { + this.enableValidate = false; if (typeof this.field.choices === 'string') { const action = this.options.action; const response = await apos.http.post( @@ -58,10 +60,12 @@ export default { } }, updateChoices(choices) { + this.enableValidate = true; this.choices = choices; if (this.field.type === 'select') { this.prependEmptyChoice(); } + this.validate(this.next); }, prependEmptyChoice() { // Using `hasOwn` here, not simply checking if `field.def` is truthy diff --git a/modules/@apostrophecms/schema/ui/apos/mixins/AposInputMixin.js b/modules/@apostrophecms/schema/ui/apos/mixins/AposInputMixin.js index ddd76e6580..2ee7702682 100644 --- a/modules/@apostrophecms/schema/ui/apos/mixins/AposInputMixin.js +++ b/modules/@apostrophecms/schema/ui/apos/mixins/AposInputMixin.js @@ -136,6 +136,9 @@ export default { // You must supply the validate method. It receives the // internal representation used for editing (a string, for instance) validateAndEmit () { + if (this.enableValidate === false) { + return; + } // If the field is conditional and isn't shown, disregard any errors. const error = this.conditionMet === false ? false : this.validate(this.next);