pict-section-recordset 1.20.0 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pict-section-recordset",
3
- "version": "1.20.0",
3
+ "version": "1.21.0",
4
4
  "description": "Pict dynamic record set management views",
5
5
  "main": "source/Pict-Section-RecordSet.js",
6
6
  "files": [
@@ -395,6 +395,32 @@ class PictRecordSetAssociationManager extends libPictProvider
395
395
  * @param {string|number} pThisID
396
396
  * @return {Promise<Array<any>>}
397
397
  */
398
+ /**
399
+ * Does this join row reference a real other-side record? An unset key (undefined / null / '') is
400
+ * not an association; nor is 0 / '0' on an id-keyed side, where 0 is never a real auto-increment id
401
+ * (Meadow ids start at 1). Some hosts park sentinel rows in the join table — e.g. a "default set"
402
+ * keyed by IDProject = 0 that a SynthesizeDefaults hook reads — and those must not surface as broken
403
+ * "#0" rows in the editor. The 0-guard is gated to id-keyed sides (JoinField === IDField) so a
404
+ * name-keyed side, where '0' could pathologically be a real key, is never affected.
405
+ *
406
+ * @param {Record<string, any>} pJoin - a join row.
407
+ * @param {Record<string, any>} pOtherSide - the resolved other side.
408
+ * @return {Boolean}
409
+ */
410
+ _joinReferencesRealRecord(pJoin, pOtherSide)
411
+ {
412
+ const tmpValue = pJoin[pOtherSide.JoinField];
413
+ if ((tmpValue === undefined) || (tmpValue === null) || (tmpValue === ''))
414
+ {
415
+ return false;
416
+ }
417
+ if ((pOtherSide.JoinField === pOtherSide.IDField) && ((tmpValue === 0) || (tmpValue === '0')))
418
+ {
419
+ return false;
420
+ }
421
+ return true;
422
+ }
423
+
398
424
  async listAssociatedIDs(pAssociationHash, pThisRecordSetName, pThisID)
399
425
  {
400
426
  const tmpSides = this.resolveSides(pAssociationHash, pThisRecordSetName);
@@ -404,8 +430,8 @@ class PictRecordSetAssociationManager extends libPictProvider
404
430
  }
405
431
  const tmpJoins = await this.listJoinRecords(pAssociationHash, pThisRecordSetName, pThisID);
406
432
  return tmpJoins
407
- .map((pJoin) => pJoin[tmpSides.otherSide.JoinField])
408
- .filter((pValue) => (pValue !== undefined && pValue !== null && pValue !== ''));
433
+ .filter((pJoin) => this._joinReferencesRealRecord(pJoin, tmpSides.otherSide))
434
+ .map((pJoin) => pJoin[tmpSides.otherSide.JoinField]);
409
435
  }
410
436
 
411
437
  /**
@@ -428,9 +454,10 @@ class PictRecordSetAssociationManager extends libPictProvider
428
454
  }
429
455
  const tmpJoinIDField = this.getJoinIDField(tmpSides.association);
430
456
  const tmpJoins = await this.listJoinRecords(pAssociationHash, pThisRecordSetName, pThisID);
431
- const tmpOtherIDs = tmpJoins
432
- .map((pJoin) => pJoin[tmpSides.otherSide.JoinField])
433
- .filter((pValue) => (pValue !== undefined && pValue !== null && pValue !== ''));
457
+ // Drop sentinel / unset rows (e.g. a "default set" keyed by other-side id 0) so they don't
458
+ // surface as broken "#0" rows; everything downstream works off the real-association set.
459
+ const tmpRealJoins = tmpJoins.filter((pJoin) => this._joinReferencesRealRecord(pJoin, tmpSides.otherSide));
460
+ const tmpOtherIDs = tmpRealJoins.map((pJoin) => pJoin[tmpSides.otherSide.JoinField]);
434
461
 
435
462
  let tmpByID = {};
436
463
  if (tmpOtherIDs.length > 0)
@@ -455,8 +482,7 @@ class PictRecordSetAssociationManager extends libPictProvider
455
482
  }
456
483
  }
457
484
 
458
- return tmpJoins
459
- .filter((pJoin) => (pJoin[tmpSides.otherSide.JoinField] !== undefined && pJoin[tmpSides.otherSide.JoinField] !== null && pJoin[tmpSides.otherSide.JoinField] !== ''))
485
+ return tmpRealJoins
460
486
  .map((pJoin) =>
461
487
  {
462
488
  const tmpOtherID = pJoin[tmpSides.otherSide.JoinField];
@@ -31,6 +31,12 @@ const _DEFAULT_CONFIGURATION_AssociationEditor = (
31
31
  DefaultDestinationAddress: '#PRSP_AssociationEditor_Container',
32
32
  DefaultTemplateRecordAddress: false,
33
33
 
34
+ // Show the "Add defaults" affordance when the association has a defaults synthesizer. Set false
35
+ // on an instance where synthesis is directionally meaningless (e.g. anchored on the type side of
36
+ // a "seed a project with default types" synthesizer) — the synthesizer stays registered for the
37
+ // side it applies to; this just hides the button on the side it does not.
38
+ AllowSynthesize: true,
39
+
34
40
  AutoInitialize: false,
35
41
  AutoInitializeOrdinal: 0,
36
42
  AutoRender: false,
@@ -265,8 +271,10 @@ class viewRecordSetAssociationEditor extends libPictView
265
271
  // One-or-zero-element slot drives the empty-state line (TS parses inner tags; NE would not).
266
272
  EmptySlot: (tmpItems.length === 0) ? [ { EmptyText: `No ${tmpOtherLabel} associated yet — use the search above to add some.` } ] : [],
267
273
  PickerMissing: !tmpPickerPresent,
268
- // The "Add defaults" button shows only when the host registered a defaults synthesizer.
269
- SynthesizeSlot: this.manager.hasDefaultSynthesizer(this.options.AssociationHash) ? [ { ViewHash: this.Hash } ] : [],
274
+ // The "Add defaults" button shows only when the host registered a defaults synthesizer AND this
275
+ // instance opts in (AllowSynthesize, default true) an embedding anchored on the side the
276
+ // synthesizer does not apply to sets AllowSynthesize:false to hide it.
277
+ SynthesizeSlot: ((this.options.AllowSynthesize !== false) && this.manager.hasDefaultSynthesizer(this.options.AssociationHash)) ? [ { ViewHash: this.Hash } ] : [],
270
278
  };
271
279
 
272
280
  return new Promise((resolve) =>