@memberjunction/ng-entity-viewer 6.1.4 → 6.2.0-edge.1

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.
Files changed (81) hide show
  1. package/dist/lib/aggregate-panel/aggregate-panel.component.d.ts +18 -2
  2. package/dist/lib/aggregate-panel/aggregate-panel.component.d.ts.map +1 -1
  3. package/dist/lib/aggregate-panel/aggregate-panel.component.js +47 -18
  4. package/dist/lib/aggregate-panel/aggregate-panel.component.js.map +1 -1
  5. package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.d.ts +22 -0
  6. package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.d.ts.map +1 -1
  7. package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.js +57 -13
  8. package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.js.map +1 -1
  9. package/dist/lib/entity-cards/entity-cards.component.d.ts +68 -5
  10. package/dist/lib/entity-cards/entity-cards.component.d.ts.map +1 -1
  11. package/dist/lib/entity-cards/entity-cards.component.js +213 -73
  12. package/dist/lib/entity-cards/entity-cards.component.js.map +1 -1
  13. package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts +156 -14
  14. package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts.map +1 -1
  15. package/dist/lib/entity-data-grid/entity-data-grid.component.js +432 -138
  16. package/dist/lib/entity-data-grid/entity-data-grid.component.js.map +1 -1
  17. package/dist/lib/entity-data-grid/events/grid-events.js +67 -67
  18. package/dist/lib/entity-data-grid/events/grid-events.js.map +1 -1
  19. package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.d.ts +112 -8
  20. package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.d.ts.map +1 -1
  21. package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.js +255 -69
  22. package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.js.map +1 -1
  23. package/dist/lib/entity-viewer/entity-viewer.component.d.ts +11 -0
  24. package/dist/lib/entity-viewer/entity-viewer.component.d.ts.map +1 -1
  25. package/dist/lib/entity-viewer/entity-viewer.component.js +45 -8
  26. package/dist/lib/entity-viewer/entity-viewer.component.js.map +1 -1
  27. package/dist/lib/pill/pill.component.d.ts +13 -3
  28. package/dist/lib/pill/pill.component.d.ts.map +1 -1
  29. package/dist/lib/pill/pill.component.js +34 -10
  30. package/dist/lib/pill/pill.component.js.map +1 -1
  31. package/dist/lib/quick-save-dialog/quick-save-dialog.component.d.ts +29 -3
  32. package/dist/lib/quick-save-dialog/quick-save-dialog.component.d.ts.map +1 -1
  33. package/dist/lib/quick-save-dialog/quick-save-dialog.component.js +173 -114
  34. package/dist/lib/quick-save-dialog/quick-save-dialog.component.js.map +1 -1
  35. package/dist/lib/recycle-bin/recycle-bin.component.d.ts +4 -0
  36. package/dist/lib/recycle-bin/recycle-bin.component.d.ts.map +1 -1
  37. package/dist/lib/recycle-bin/recycle-bin.component.js +10 -2
  38. package/dist/lib/recycle-bin/recycle-bin.component.js.map +1 -1
  39. package/dist/lib/utils/aggregate-field.util.d.ts +21 -0
  40. package/dist/lib/utils/aggregate-field.util.d.ts.map +1 -0
  41. package/dist/lib/utils/aggregate-field.util.js +40 -0
  42. package/dist/lib/utils/aggregate-field.util.js.map +1 -0
  43. package/dist/lib/utils/highlight.util.d.ts +6 -0
  44. package/dist/lib/utils/highlight.util.d.ts.map +1 -1
  45. package/dist/lib/utils/highlight.util.js +23 -11
  46. package/dist/lib/utils/highlight.util.js.map +1 -1
  47. package/dist/lib/utils/record.util.d.ts +10 -0
  48. package/dist/lib/utils/record.util.d.ts.map +1 -1
  49. package/dist/lib/utils/record.util.js +20 -4
  50. package/dist/lib/utils/record.util.js.map +1 -1
  51. package/dist/lib/view-config-panel/view-config-panel.component.d.ts +22 -2
  52. package/dist/lib/view-config-panel/view-config-panel.component.d.ts.map +1 -1
  53. package/dist/lib/view-config-panel/view-config-panel.component.js +54 -14
  54. package/dist/lib/view-config-panel/view-config-panel.component.js.map +1 -1
  55. package/dist/lib/view-selector/view-selector.component.js +2 -2
  56. package/dist/lib/view-types/renderers/cards-view-renderer.component.d.ts +15 -3
  57. package/dist/lib/view-types/renderers/cards-view-renderer.component.d.ts.map +1 -1
  58. package/dist/lib/view-types/renderers/cards-view-renderer.component.js +33 -5
  59. package/dist/lib/view-types/renderers/cards-view-renderer.component.js.map +1 -1
  60. package/dist/lib/view-types/renderers/grid-view-renderer.component.d.ts +160 -5
  61. package/dist/lib/view-types/renderers/grid-view-renderer.component.d.ts.map +1 -1
  62. package/dist/lib/view-types/renderers/grid-view-renderer.component.js +576 -36
  63. package/dist/lib/view-types/renderers/grid-view-renderer.component.js.map +1 -1
  64. package/dist/lib/view-types/renderers/map-view-renderer.component.d.ts +16 -2
  65. package/dist/lib/view-types/renderers/map-view-renderer.component.d.ts.map +1 -1
  66. package/dist/lib/view-types/renderers/map-view-renderer.component.js +37 -9
  67. package/dist/lib/view-types/renderers/map-view-renderer.component.js.map +1 -1
  68. package/dist/lib/view-types/view-type.contracts.js.map +1 -1
  69. package/dist/lib/view-workspace/view-workspace.component.d.ts +235 -24
  70. package/dist/lib/view-workspace/view-workspace.component.d.ts.map +1 -1
  71. package/dist/lib/view-workspace/view-workspace.component.js +600 -174
  72. package/dist/lib/view-workspace/view-workspace.component.js.map +1 -1
  73. package/dist/module.d.ts +5 -4
  74. package/dist/module.d.ts.map +1 -1
  75. package/dist/module.js +8 -1
  76. package/dist/module.js.map +1 -1
  77. package/dist/public-api.d.ts +1 -0
  78. package/dist/public-api.d.ts.map +1 -1
  79. package/dist/public-api.js +1 -0
  80. package/dist/public-api.js.map +1 -1
  81. package/package.json +21 -20
@@ -1,7 +1,7 @@
1
1
  import { Component, Input, Output, EventEmitter } from '@angular/core';
2
2
  import { BaseAngularComponent } from '@memberjunction/ng-base-types';
3
- import { EntityInfo, RunView, EntityFieldValueListType } from '@memberjunction/core';
4
- import { buildCompositeKey, buildPkString } from '../utils/record.util';
3
+ import { EntityInfo, RunView, EntityFieldValueListType, IsDateOnlySQLType, FormatDateOnly } from '@memberjunction/core';
4
+ import { BuildCompositeKey, BuildPkString } from '../utils/record.util';
5
5
  import * as i0 from "@angular/core";
6
6
  import * as i1 from "@memberjunction/ng-shared-generic";
7
7
  import * as i2 from "@memberjunction/ng-ui-components";
@@ -393,21 +393,109 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
393
393
  entity = null;
394
394
  record = null;
395
395
  close = new EventEmitter();
396
- openRecord = new EventEmitter();
397
- navigateToRelated = new EventEmitter();
398
- openRelatedRecord = new EventEmitter();
399
- openForeignKeyRecord = new EventEmitter();
396
+ OpenRecord = new EventEmitter();
397
+ /**
398
+ * @deprecated Use {@link OpenRecord}.
399
+ *
400
+ * The same emitter under the old binding name, so a template still binding
401
+ * (openRecord) keeps working. Must stay AFTER OpenRecord: class fields
402
+ * initialise in order, and the other way round this captures undefined.
403
+ */
404
+ openRecord = this.OpenRecord;
405
+ NavigateToRelated = new EventEmitter();
406
+ /**
407
+ * @deprecated Use {@link NavigateToRelated}.
408
+ *
409
+ * The same emitter under the old binding name, so a template still binding
410
+ * (navigateToRelated) keeps working. Must stay AFTER NavigateToRelated: class fields
411
+ * initialise in order, and the other way round this captures undefined.
412
+ */
413
+ navigateToRelated = this.NavigateToRelated;
414
+ OpenRelatedRecord = new EventEmitter();
415
+ /**
416
+ * @deprecated Use {@link OpenRelatedRecord}.
417
+ *
418
+ * The same emitter under the old binding name, so a template still binding
419
+ * (openRelatedRecord) keeps working. Must stay AFTER OpenRelatedRecord: class fields
420
+ * initialise in order, and the other way round this captures undefined.
421
+ */
422
+ openRelatedRecord = this.OpenRelatedRecord;
423
+ OpenForeignKeyRecord = new EventEmitter();
424
+ /**
425
+ * @deprecated Use {@link OpenForeignKeyRecord}.
426
+ *
427
+ * The same emitter under the old binding name, so a template still binding
428
+ * (openForeignKeyRecord) keeps working. Must stay AFTER OpenForeignKeyRecord: class fields
429
+ * initialise in order, and the other way round this captures undefined.
430
+ */
431
+ openForeignKeyRecord = this.OpenForeignKeyRecord;
400
432
  // Related entity counts
401
- relatedEntities = [];
402
- isLoadingRelationships = false;
433
+ RelatedEntities = [];
434
+ /** @deprecated Use {@link RelatedEntities}. */
435
+ get relatedEntities() {
436
+ return this.RelatedEntities;
437
+ }
438
+ /** @deprecated Use {@link RelatedEntities}. */
439
+ set relatedEntities(value) {
440
+ this.RelatedEntities = value;
441
+ }
442
+ IsLoadingRelationships = false;
443
+ /** @deprecated Use {@link IsLoadingRelationships}. */
444
+ get isLoadingRelationships() {
445
+ return this.IsLoadingRelationships;
446
+ }
447
+ /** @deprecated Use {@link IsLoadingRelationships}. */
448
+ set isLoadingRelationships(value) {
449
+ this.IsLoadingRelationships = value;
450
+ }
403
451
  // Organic key match counts
404
- organicKeyMatches = [];
405
- isLoadingOrganicKeys = false;
452
+ OrganicKeyMatches = [];
453
+ /** @deprecated Use {@link OrganicKeyMatches}. */
454
+ get organicKeyMatches() {
455
+ return this.OrganicKeyMatches;
456
+ }
457
+ /** @deprecated Use {@link OrganicKeyMatches}. */
458
+ set organicKeyMatches(value) {
459
+ this.OrganicKeyMatches = value;
460
+ }
461
+ IsLoadingOrganicKeys = false;
462
+ /** @deprecated Use {@link IsLoadingOrganicKeys}. */
463
+ get isLoadingOrganicKeys() {
464
+ return this.IsLoadingOrganicKeys;
465
+ }
466
+ /** @deprecated Use {@link IsLoadingOrganicKeys}. */
467
+ set isLoadingOrganicKeys(value) {
468
+ this.IsLoadingOrganicKeys = value;
469
+ }
406
470
  metadata = this.ProviderToUse;
407
471
  // Sections expanded state
408
- detailsSectionExpanded = true;
409
- relationshipsSectionExpanded = true;
410
- organicKeysSectionExpanded = true;
472
+ DetailsSectionExpanded = true;
473
+ /** @deprecated Use {@link DetailsSectionExpanded}. */
474
+ get detailsSectionExpanded() {
475
+ return this.DetailsSectionExpanded;
476
+ }
477
+ /** @deprecated Use {@link DetailsSectionExpanded}. */
478
+ set detailsSectionExpanded(value) {
479
+ this.DetailsSectionExpanded = value;
480
+ }
481
+ RelationshipsSectionExpanded = true;
482
+ /** @deprecated Use {@link RelationshipsSectionExpanded}. */
483
+ get relationshipsSectionExpanded() {
484
+ return this.RelationshipsSectionExpanded;
485
+ }
486
+ /** @deprecated Use {@link RelationshipsSectionExpanded}. */
487
+ set relationshipsSectionExpanded(value) {
488
+ this.RelationshipsSectionExpanded = value;
489
+ }
490
+ OrganicKeysSectionExpanded = true;
491
+ /** @deprecated Use {@link OrganicKeysSectionExpanded}. */
492
+ get organicKeysSectionExpanded() {
493
+ return this.OrganicKeysSectionExpanded;
494
+ }
495
+ /** @deprecated Use {@link OrganicKeysSectionExpanded}. */
496
+ set organicKeysSectionExpanded(value) {
497
+ this.OrganicKeysSectionExpanded = value;
498
+ }
411
499
  constructor(cdr, ngZone) {
412
500
  super();
413
501
  this.cdr = cdr;
@@ -425,20 +513,20 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
425
513
  async loadRelationshipCounts() {
426
514
  if (!this.entity || !this.record)
427
515
  return;
428
- this.isLoadingRelationships = true;
429
- this.relatedEntities = [];
516
+ this.IsLoadingRelationships = true;
517
+ this.RelatedEntities = [];
430
518
  // Get relationships where this entity is the related entity (foreign keys pointing TO this record)
431
519
  const relationships = this.entity.RelatedEntities;
432
520
  if (relationships.length === 0) {
433
- this.isLoadingRelationships = false;
521
+ this.IsLoadingRelationships = false;
434
522
  return;
435
523
  }
436
524
  // Build a CompositeKey for the current record
437
- const compositeKey = buildCompositeKey(this.record, this.entity);
525
+ const compositeKey = BuildCompositeKey(this.record, this.entity);
438
526
  // Get the first PK value for the join field filter
439
527
  const pkValue = compositeKey.KeyValuePairs[0]?.Value;
440
528
  if (!pkValue) {
441
- this.isLoadingRelationships = false;
529
+ this.IsLoadingRelationships = false;
442
530
  return;
443
531
  }
444
532
  // Build batch query params for all relationships
@@ -451,7 +539,7 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
451
539
  const rv = RunView.FromMetadataProvider(this.ProviderToUse);
452
540
  const results = await rv.RunViews(viewParams);
453
541
  // Map results back to relationship data
454
- this.relatedEntities = relationships.map((rel, index) => {
542
+ this.RelatedEntities = relationships.map((rel, index) => {
455
543
  const result = results[index];
456
544
  return {
457
545
  relationship: rel,
@@ -466,7 +554,7 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
466
554
  catch (error) {
467
555
  console.warn('Failed to load relationship counts:', error);
468
556
  // Initialize with zero counts on error
469
- this.relatedEntities = relationships.map(rel => ({
557
+ this.RelatedEntities = relationships.map(rel => ({
470
558
  relationship: rel,
471
559
  relatedEntityName: rel.RelatedEntity,
472
560
  count: 0,
@@ -477,7 +565,7 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
477
565
  }
478
566
  finally {
479
567
  this.ngZone.run(() => {
480
- this.isLoadingRelationships = false;
568
+ this.IsLoadingRelationships = false;
481
569
  this.cdr.detectChanges();
482
570
  });
483
571
  }
@@ -491,7 +579,7 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
491
579
  return;
492
580
  const organicKeys = this.entity.OrganicKeys;
493
581
  if (!organicKeys || organicKeys.length === 0) {
494
- this.organicKeyMatches = [];
582
+ this.OrganicKeyMatches = [];
495
583
  return;
496
584
  }
497
585
  // Flatten all organic key related entities
@@ -502,11 +590,11 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
502
590
  }
503
591
  }
504
592
  if (allPairs.length === 0) {
505
- this.organicKeyMatches = [];
593
+ this.OrganicKeyMatches = [];
506
594
  return;
507
595
  }
508
- this.isLoadingOrganicKeys = true;
509
- this.organicKeyMatches = [];
596
+ this.IsLoadingOrganicKeys = true;
597
+ this.OrganicKeyMatches = [];
510
598
  // Build a mock BaseEntity-like object for BuildOrganicKeyViewParams
511
599
  // The static method only calls record.Get(fieldName), so we can duck-type it
512
600
  const mockRecord = {
@@ -522,7 +610,7 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
522
610
  try {
523
611
  const rv = RunView.FromMetadataProvider(this.ProviderToUse);
524
612
  const results = await rv.RunViews(viewParams);
525
- this.organicKeyMatches = allPairs.map((pair, index) => {
613
+ this.OrganicKeyMatches = allPairs.map((pair, index) => {
526
614
  const result = results[index];
527
615
  return {
528
616
  organicKey: pair.organicKey,
@@ -537,7 +625,7 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
537
625
  }
538
626
  catch (error) {
539
627
  console.warn('Failed to load organic key counts:', error);
540
- this.organicKeyMatches = allPairs.map(pair => ({
628
+ this.OrganicKeyMatches = allPairs.map(pair => ({
541
629
  organicKey: pair.organicKey,
542
630
  relatedEntity: pair.relatedEntity,
543
631
  relatedEntityName: pair.relatedEntity.DisplayName || pair.relatedEntity.RelatedEntity,
@@ -549,7 +637,7 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
549
637
  }
550
638
  finally {
551
639
  this.ngZone.run(() => {
552
- this.isLoadingOrganicKeys = false;
640
+ this.IsLoadingOrganicKeys = false;
553
641
  this.cdr.detectChanges();
554
642
  });
555
643
  }
@@ -557,13 +645,17 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
557
645
  /**
558
646
  * Get only organic key matches that have records (count > 0)
559
647
  */
648
+ get OrganicKeyMatchesWithRecords() {
649
+ return this.OrganicKeyMatches.filter(m => m.count > 0);
650
+ }
651
+ /** @deprecated Use {@link OrganicKeyMatchesWithRecords}. */
560
652
  get organicKeyMatchesWithRecords() {
561
- return this.organicKeyMatches.filter(m => m.count > 0);
653
+ return this.OrganicKeyMatchesWithRecords;
562
654
  }
563
655
  /**
564
656
  * Toggle expansion of an organic key match section and load records if needed
565
657
  */
566
- async toggleOrganicKeyExpansion(match, event) {
658
+ async ToggleOrganicKeyExpansion(match, event) {
567
659
  event.stopPropagation();
568
660
  if (match.count === 0)
569
661
  return;
@@ -572,6 +664,10 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
572
664
  await this.loadOrganicKeyRecords(match);
573
665
  }
574
666
  }
667
+ /** @deprecated Use {@link ToggleOrganicKeyExpansion}. */
668
+ async toggleOrganicKeyExpansion(match, event) {
669
+ return this.ToggleOrganicKeyExpansion(match, event);
670
+ }
575
671
  /**
576
672
  * Load actual records for an organic key match
577
673
  */
@@ -616,17 +712,21 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
616
712
  /**
617
713
  * Handle click on an organic key record
618
714
  */
619
- onOrganicKeyRecordClick(match, record, event) {
715
+ OnOrganicKeyRecordClick(match, record, event) {
620
716
  event.stopPropagation();
621
- this.openRelatedRecord.emit({
717
+ this.OpenRelatedRecord.emit({
622
718
  entityName: match.relatedEntity.RelatedEntity,
623
719
  record,
624
720
  });
625
721
  }
722
+ /** @deprecated Use {@link OnOrganicKeyRecordClick}. */
723
+ onOrganicKeyRecordClick(match, record, event) {
724
+ return this.OnOrganicKeyRecordClick(match, record, event);
725
+ }
626
726
  /**
627
727
  * Navigate to view all organic key matched records
628
728
  */
629
- onViewAllOrganicKey(match, event) {
729
+ OnViewAllOrganicKey(match, event) {
630
730
  event.stopPropagation();
631
731
  if (!this.record || !this.entity)
632
732
  return;
@@ -635,15 +735,19 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
635
735
  EntityInfo: this.entity,
636
736
  };
637
737
  const params = EntityInfo.BuildOrganicKeyViewParams(mockRecord, match.relatedEntity, match.organicKey);
638
- this.navigateToRelated.emit({
738
+ this.NavigateToRelated.emit({
639
739
  entityName: match.relatedEntity.RelatedEntity,
640
740
  filter: String(params.ExtraFilter || ''),
641
741
  });
642
742
  }
743
+ /** @deprecated Use {@link OnViewAllOrganicKey}. */
744
+ onViewAllOrganicKey(match, event) {
745
+ return this.OnViewAllOrganicKey(match, event);
746
+ }
643
747
  /**
644
748
  * Get display name for an organic key record
645
749
  */
646
- getOrganicKeyRecordDisplayName(match, record) {
750
+ GetOrganicKeyRecordDisplayName(match, record) {
647
751
  const entityInfo = this.metadata.Entities.find(e => e.Name === match.relatedEntity.RelatedEntity);
648
752
  if (entityInfo?.NameField) {
649
753
  const name = record[entityInfo.NameField.Name];
@@ -651,14 +755,18 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
651
755
  return String(name);
652
756
  }
653
757
  if (entityInfo) {
654
- return buildPkString(record, entityInfo);
758
+ return BuildPkString(record, entityInfo);
655
759
  }
656
760
  return 'Record';
657
761
  }
762
+ /** @deprecated Use {@link GetOrganicKeyRecordDisplayName}. */
763
+ getOrganicKeyRecordDisplayName(match, record) {
764
+ return this.GetOrganicKeyRecordDisplayName(match, record);
765
+ }
658
766
  /**
659
767
  * Get subtitle for an organic key record
660
768
  */
661
- getOrganicKeyRecordSubtitle(match, record) {
769
+ GetOrganicKeyRecordSubtitle(match, record) {
662
770
  const entityInfo = this.metadata.Entities.find(e => e.Name === match.relatedEntity.RelatedEntity);
663
771
  if (!entityInfo)
664
772
  return '';
@@ -668,26 +776,34 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
668
776
  if (field) {
669
777
  const value = record[field.Name];
670
778
  if (value !== null && value !== undefined) {
671
- return this.formatFieldValue(value, field.Name);
779
+ return this.formatFieldValue(value, field);
672
780
  }
673
781
  }
674
782
  }
675
783
  return '';
676
784
  }
785
+ /** @deprecated Use {@link GetOrganicKeyRecordSubtitle}. */
786
+ getOrganicKeyRecordSubtitle(match, record) {
787
+ return this.GetOrganicKeyRecordSubtitle(match, record);
788
+ }
677
789
  /**
678
790
  * Get icon for an organic key matched entity
679
791
  */
680
- getOrganicKeyEntityIcon(match) {
792
+ GetOrganicKeyEntityIcon(match) {
681
793
  const entityInfo = this.metadata.Entities.find(e => e.Name === match.relatedEntity.RelatedEntity);
682
794
  if (entityInfo?.Icon) {
683
795
  return this.formatEntityIcon(entityInfo.Icon);
684
796
  }
685
797
  return 'fa-solid fa-link';
686
798
  }
799
+ /** @deprecated Use {@link GetOrganicKeyEntityIcon}. */
800
+ getOrganicKeyEntityIcon(match) {
801
+ return this.GetOrganicKeyEntityIcon(match);
802
+ }
687
803
  /**
688
804
  * Get key fields to display in details section, categorized by type
689
805
  */
690
- get displayFields() {
806
+ get DisplayFields() {
691
807
  if (!this.entity || !this.record)
692
808
  return [];
693
809
  const fields = [];
@@ -731,11 +847,15 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
731
847
  type: isEnum ? 'enum' : 'regular',
732
848
  name: field.Name,
733
849
  label: this.formatFieldLabel(field),
734
- value: this.formatFieldValue(value, field.Name)
850
+ value: this.formatFieldValue(value, field)
735
851
  });
736
852
  }
737
853
  return fields;
738
854
  }
855
+ /** @deprecated Use {@link DisplayFields}. */
856
+ get displayFields() {
857
+ return this.DisplayFields;
858
+ }
739
859
  /**
740
860
  * Build display info for a foreign key field
741
861
  * Uses RelatedEntityNameFieldMap to get the human-readable name
@@ -796,12 +916,14 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
796
916
  /**
797
917
  * Format field value for display
798
918
  */
799
- formatFieldValue(value, fieldName) {
919
+ formatFieldValue(value, field) {
800
920
  if (value === null || value === undefined)
801
921
  return '-';
802
- // Handle dates
922
+ // Handle dates. A `date` column is a calendar day that arrives as UTC midnight; a local-zone
923
+ // formatter would land on the previous day for every reader west of Greenwich (MJ#4210).
924
+ // A timestamp names an instant and stays in local time.
803
925
  if (value instanceof Date) {
804
- return value.toLocaleDateString();
926
+ return IsDateOnlySQLType(field.Type) ? FormatDateOnly(value) : value.toLocaleDateString();
805
927
  }
806
928
  // Handle booleans
807
929
  if (typeof value === 'boolean') {
@@ -809,7 +931,7 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
809
931
  }
810
932
  // Handle numbers that look like currency
811
933
  if (typeof value === 'number') {
812
- const nameLower = fieldName.toLowerCase();
934
+ const nameLower = field.Name.toLowerCase();
813
935
  if (nameLower.includes('amount') ||
814
936
  nameLower.includes('price') ||
815
937
  nameLower.includes('cost') ||
@@ -829,7 +951,7 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
829
951
  /**
830
952
  * Get record title
831
953
  */
832
- get recordTitle() {
954
+ get RecordTitle() {
833
955
  if (!this.entity || !this.record)
834
956
  return 'Record';
835
957
  if (this.entity.NameField) {
@@ -837,26 +959,38 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
837
959
  if (name)
838
960
  return String(name);
839
961
  }
840
- return buildPkString(this.record, this.entity);
962
+ return BuildPkString(this.record, this.entity);
963
+ }
964
+ /** @deprecated Use {@link RecordTitle}. */
965
+ get recordTitle() {
966
+ return this.RecordTitle;
841
967
  }
842
968
  /**
843
969
  * Handle close button click
844
970
  */
845
- onClose() {
971
+ OnClose() {
846
972
  this.close.emit();
847
973
  }
974
+ /** @deprecated Use {@link OnClose}. */
975
+ onClose() {
976
+ return this.OnClose();
977
+ }
848
978
  /**
849
979
  * Handle open record button click
850
980
  */
851
- onOpenRecord() {
981
+ OnOpenRecord() {
852
982
  if (this.record) {
853
- this.openRecord.emit(this.record);
983
+ this.OpenRecord.emit(this.record);
854
984
  }
855
985
  }
986
+ /** @deprecated Use {@link OnOpenRecord}. */
987
+ onOpenRecord() {
988
+ return this.OnOpenRecord();
989
+ }
856
990
  /**
857
991
  * Copy primary key value to clipboard
858
992
  */
859
- copyToClipboard(value, event) {
993
+ CopyToClipboard(value, event) {
860
994
  event.stopPropagation();
861
995
  navigator.clipboard.writeText(value).then(() => {
862
996
  // Could add a toast notification here
@@ -865,31 +999,43 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
865
999
  console.error('Failed to copy:', err);
866
1000
  });
867
1001
  }
1002
+ /** @deprecated Use {@link CopyToClipboard}. */
1003
+ copyToClipboard(value, event) {
1004
+ return this.CopyToClipboard(value, event);
1005
+ }
868
1006
  /**
869
1007
  * Open a foreign key record (FK link click)
870
1008
  * Emits openForeignKeyRecord event for parent to handle opening the record
871
1009
  */
872
- onForeignKeyClick(field, event) {
1010
+ OnForeignKeyClick(field, event) {
873
1011
  event.stopPropagation();
874
1012
  if (field.relatedEntityName && field.relatedRecordId) {
875
- this.openForeignKeyRecord.emit({
1013
+ this.OpenForeignKeyRecord.emit({
876
1014
  entityName: field.relatedEntityName,
877
1015
  recordId: field.relatedRecordId
878
1016
  });
879
1017
  }
880
1018
  }
1019
+ /** @deprecated Use {@link OnForeignKeyClick}. */
1020
+ onForeignKeyClick(field, event) {
1021
+ return this.OnForeignKeyClick(field, event);
1022
+ }
881
1023
  /**
882
1024
  * Check if a FK display value is different from the raw ID (i.e., we have a name to show)
883
1025
  */
884
- hasFriendlyName(field) {
1026
+ HasFriendlyName(field) {
885
1027
  return field.type === 'foreign-key' &&
886
1028
  field.displayValue !== undefined &&
887
1029
  field.displayValue !== field.value;
888
1030
  }
1031
+ /** @deprecated Use {@link HasFriendlyName}. */
1032
+ hasFriendlyName(field) {
1033
+ return this.HasFriendlyName(field);
1034
+ }
889
1035
  /**
890
1036
  * Toggle expansion of related entity section and load records if needed
891
1037
  */
892
- async toggleRelatedEntityExpansion(relEntity, event) {
1038
+ async ToggleRelatedEntityExpansion(relEntity, event) {
893
1039
  event.stopPropagation();
894
1040
  if (relEntity.count === 0)
895
1041
  return;
@@ -899,13 +1045,17 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
899
1045
  await this.loadRelatedRecords(relEntity);
900
1046
  }
901
1047
  }
1048
+ /** @deprecated Use {@link ToggleRelatedEntityExpansion}. */
1049
+ async toggleRelatedEntityExpansion(relEntity, event) {
1050
+ return this.ToggleRelatedEntityExpansion(relEntity, event);
1051
+ }
902
1052
  /**
903
1053
  * Load actual records for a related entity
904
1054
  */
905
1055
  async loadRelatedRecords(relEntity) {
906
1056
  if (!this.record || !this.entity)
907
1057
  return;
908
- const compositeKey = buildCompositeKey(this.record, this.entity);
1058
+ const compositeKey = BuildCompositeKey(this.record, this.entity);
909
1059
  const pkValue = compositeKey.KeyValuePairs[0]?.Value;
910
1060
  if (!pkValue)
911
1061
  return;
@@ -944,33 +1094,41 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
944
1094
  /**
945
1095
  * Handle click on individual related record - opens in new tab
946
1096
  */
947
- onRelatedRecordClick(relEntity, record, event) {
1097
+ OnRelatedRecordClick(relEntity, record, event) {
948
1098
  event.stopPropagation();
949
- this.openRelatedRecord.emit({
1099
+ this.OpenRelatedRecord.emit({
950
1100
  entityName: relEntity.relatedEntityName,
951
1101
  record
952
1102
  });
953
1103
  }
1104
+ /** @deprecated Use {@link OnRelatedRecordClick}. */
1105
+ onRelatedRecordClick(relEntity, record, event) {
1106
+ return this.OnRelatedRecordClick(relEntity, record, event);
1107
+ }
954
1108
  /**
955
1109
  * Navigate to view all related records (when count > 10)
956
1110
  */
957
- onViewAllRelated(relEntity, event) {
1111
+ OnViewAllRelated(relEntity, event) {
958
1112
  event.stopPropagation();
959
1113
  if (!this.record || !this.entity)
960
1114
  return;
961
- const compositeKey = buildCompositeKey(this.record, this.entity);
1115
+ const compositeKey = BuildCompositeKey(this.record, this.entity);
962
1116
  const pkValue = compositeKey.KeyValuePairs[0]?.Value;
963
1117
  if (!pkValue)
964
1118
  return;
965
- this.navigateToRelated.emit({
1119
+ this.NavigateToRelated.emit({
966
1120
  entityName: relEntity.relatedEntityName,
967
1121
  filter: `${relEntity.relationship.RelatedEntityJoinField}='${pkValue}'`
968
1122
  });
969
1123
  }
1124
+ /** @deprecated Use {@link OnViewAllRelated}. */
1125
+ onViewAllRelated(relEntity, event) {
1126
+ return this.OnViewAllRelated(relEntity, event);
1127
+ }
970
1128
  /**
971
1129
  * Get display name for a related record
972
1130
  */
973
- getRelatedRecordDisplayName(relEntity, record) {
1131
+ GetRelatedRecordDisplayName(relEntity, record) {
974
1132
  const entityInfo = this.metadata.Entities.find(e => e.Name === relEntity.relatedEntityName);
975
1133
  if (entityInfo?.NameField) {
976
1134
  const name = record[entityInfo.NameField.Name];
@@ -978,14 +1136,18 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
978
1136
  return String(name);
979
1137
  }
980
1138
  if (entityInfo) {
981
- return buildPkString(record, entityInfo);
1139
+ return BuildPkString(record, entityInfo);
982
1140
  }
983
1141
  return 'Record';
984
1142
  }
1143
+ /** @deprecated Use {@link GetRelatedRecordDisplayName}. */
1144
+ getRelatedRecordDisplayName(relEntity, record) {
1145
+ return this.GetRelatedRecordDisplayName(relEntity, record);
1146
+ }
985
1147
  /**
986
1148
  * Get subtitle/secondary info for a related record
987
1149
  */
988
- getRelatedRecordSubtitle(relEntity, record) {
1150
+ GetRelatedRecordSubtitle(relEntity, record) {
989
1151
  const entityInfo = this.metadata.Entities.find(e => e.Name === relEntity.relatedEntityName);
990
1152
  if (!entityInfo)
991
1153
  return '';
@@ -996,37 +1158,53 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
996
1158
  if (field) {
997
1159
  const value = record[field.Name];
998
1160
  if (value !== null && value !== undefined) {
999
- return this.formatFieldValue(value, field.Name);
1161
+ return this.formatFieldValue(value, field);
1000
1162
  }
1001
1163
  }
1002
1164
  }
1003
1165
  return '';
1004
1166
  }
1167
+ /** @deprecated Use {@link GetRelatedRecordSubtitle}. */
1168
+ getRelatedRecordSubtitle(relEntity, record) {
1169
+ return this.GetRelatedRecordSubtitle(relEntity, record);
1170
+ }
1005
1171
  /**
1006
1172
  * Get only related entities that have records (count > 0)
1007
1173
  */
1174
+ get RelatedEntitiesWithRecords() {
1175
+ return this.RelatedEntities.filter(r => r.count > 0);
1176
+ }
1177
+ /** @deprecated Use {@link RelatedEntitiesWithRecords}. */
1008
1178
  get relatedEntitiesWithRecords() {
1009
- return this.relatedEntities.filter(r => r.count > 0);
1179
+ return this.RelatedEntitiesWithRecords;
1010
1180
  }
1011
1181
  /**
1012
1182
  * Get icon for related entity by looking up EntityInfo from Metadata
1013
1183
  */
1014
- getRelatedEntityIcon(relEntity) {
1184
+ GetRelatedEntityIcon(relEntity) {
1015
1185
  const entityInfo = this.metadata.Entities.find(e => e.Name === relEntity.relatedEntityName);
1016
1186
  if (entityInfo?.Icon) {
1017
1187
  return this.formatEntityIcon(entityInfo.Icon);
1018
1188
  }
1019
1189
  return 'fa-solid fa-table';
1020
1190
  }
1191
+ /** @deprecated Use {@link GetRelatedEntityIcon}. */
1192
+ getRelatedEntityIcon(relEntity) {
1193
+ return this.GetRelatedEntityIcon(relEntity);
1194
+ }
1021
1195
  /**
1022
1196
  * Get the icon class for the current entity
1023
1197
  */
1024
- getEntityIconClass() {
1198
+ GetEntityIconClass() {
1025
1199
  if (!this.entity?.Icon) {
1026
1200
  return 'fa-solid fa-table';
1027
1201
  }
1028
1202
  return this.formatEntityIcon(this.entity.Icon);
1029
1203
  }
1204
+ /** @deprecated Use {@link GetEntityIconClass}. */
1205
+ getEntityIconClass() {
1206
+ return this.GetEntityIconClass();
1207
+ }
1030
1208
  /**
1031
1209
  * Format entity icon to ensure proper Font Awesome class format
1032
1210
  */
@@ -1049,7 +1227,7 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
1049
1227
  return `fa-solid fa-${icon}`;
1050
1228
  }
1051
1229
  static ɵfac = function EntityRecordDetailPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EntityRecordDetailPanelComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i0.NgZone)); };
1052
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EntityRecordDetailPanelComponent, selectors: [["mj-entity-record-detail-panel"]], inputs: { entity: "entity", record: "record" }, outputs: { close: "close", openRecord: "openRecord", navigateToRelated: "navigateToRelated", openRelatedRecord: "openRelatedRecord", openForeignKeyRecord: "openForeignKeyRecord" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 24, vars: 9, consts: [[1, "entity-record-card-container"], [1, "panel-header"], [1, "panel-title-row"], [1, "entity-icon", 3, "class"], [1, "panel-title"], ["title", "Close", "aria-label", "Close panel", 1, "close-btn", 3, "click"], [1, "fa-solid", "fa-times"], [1, "panel-content"], [3, "ExpandedChange", "Expanded", "TitleIconMuted"], ["mjAccordionTitle", ""], ["Size", "compact", "Icon", "fa-solid fa-circle-info", "Title", "No details available"], [1, "relationships-loading"], ["Size", "compact", "Icon", "fa-solid fa-diagram-project", "Title", "No related records"], [3, "Expanded", "TitleIconMuted"], [1, "panel-footer"], [1, "open-record-btn", 3, "click"], [1, "fa-solid", "fa-external-link-alt"], [1, "entity-icon"], [1, "fa-solid", "fa-info-circle"], [1, "field-row", "field-row-pk"], [1, "field-row", "field-row-fk"], [1, "field-row"], [1, "pk-row"], [1, "fa-solid", "fa-key", "pk-icon"], [1, "field-label"], ["title", "Copy ID", 1, "copy-btn", 3, "click"], [1, "fa-solid", "fa-copy"], [1, "fk-value-row"], [1, "field-value", "fk-display-value"], [1, "field-value", "fk-id-value"], [1, "fk-link-btn", 3, "title"], [1, "fk-link-btn", 3, "click", "title"], [3, "value"], [1, "field-value"], [1, "fa-solid", "fa-project-diagram"], ["text", "Loading related records...", "size", "small"], [1, "related-entity-group", 3, "expanded"], [1, "related-entity-group"], [1, "related-entity-header", 3, "click"], [1, "fa-solid", "expand-chevron"], [1, "related-entity-name"], [1, "related-entity-count"], [1, "related-records-list"], [1, "records-loading"], ["text", "Loading...", "size", "small"], [1, "related-record-item"], [1, "view-all-link"], [1, "related-record-item", 3, "click"], [1, "record-info"], [1, "record-name"], [1, "record-subtitle"], [1, "fa-solid", "fa-external-link-alt", "record-open-icon"], [1, "view-all-link", 3, "click"], [1, "fa-solid", "fa-arrow-right"], ["Size", "compact", "Icon", "fa-solid fa-link", "Title", "No organic key matches"], [1, "fa-solid", "fa-link"], ["text", "Loading organic key matches...", "size", "small"]], template: function EntityRecordDetailPanelComponent_Template(rf, ctx) { if (rf & 1) {
1230
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EntityRecordDetailPanelComponent, selectors: [["mj-entity-record-detail-panel"]], inputs: { entity: "entity", record: "record" }, outputs: { close: "close", OpenRecord: "OpenRecord", openRecord: "openRecord", NavigateToRelated: "NavigateToRelated", navigateToRelated: "navigateToRelated", OpenRelatedRecord: "OpenRelatedRecord", openRelatedRecord: "openRelatedRecord", OpenForeignKeyRecord: "OpenForeignKeyRecord", openForeignKeyRecord: "openForeignKeyRecord" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 24, vars: 9, consts: [[1, "entity-record-card-container"], [1, "panel-header"], [1, "panel-title-row"], [1, "entity-icon", 3, "class"], [1, "panel-title"], ["title", "Close", "aria-label", "Close panel", 1, "close-btn", 3, "click"], [1, "fa-solid", "fa-times"], [1, "panel-content"], [3, "ExpandedChange", "Expanded", "TitleIconMuted"], ["mjAccordionTitle", ""], ["Size", "compact", "Icon", "fa-solid fa-circle-info", "Title", "No details available"], [1, "relationships-loading"], ["Size", "compact", "Icon", "fa-solid fa-diagram-project", "Title", "No related records"], [3, "Expanded", "TitleIconMuted"], [1, "panel-footer"], [1, "open-record-btn", 3, "click"], [1, "fa-solid", "fa-external-link-alt"], [1, "entity-icon"], [1, "fa-solid", "fa-info-circle"], [1, "field-row", "field-row-pk"], [1, "field-row", "field-row-fk"], [1, "field-row"], [1, "pk-row"], [1, "fa-solid", "fa-key", "pk-icon"], [1, "field-label"], ["title", "Copy ID", 1, "copy-btn", 3, "click"], [1, "fa-solid", "fa-copy"], [1, "fk-value-row"], [1, "field-value", "fk-display-value"], [1, "field-value", "fk-id-value"], [1, "fk-link-btn", 3, "title"], [1, "fk-link-btn", 3, "click", "title"], [3, "value"], [1, "field-value"], [1, "fa-solid", "fa-project-diagram"], ["text", "Loading related records...", "size", "small"], [1, "related-entity-group", 3, "expanded"], [1, "related-entity-group"], [1, "related-entity-header", 3, "click"], [1, "fa-solid", "expand-chevron"], [1, "related-entity-name"], [1, "related-entity-count"], [1, "related-records-list"], [1, "records-loading"], ["text", "Loading...", "size", "small"], [1, "related-record-item"], [1, "view-all-link"], [1, "related-record-item", 3, "click"], [1, "record-info"], [1, "record-name"], [1, "record-subtitle"], [1, "fa-solid", "fa-external-link-alt", "record-open-icon"], [1, "view-all-link", 3, "click"], [1, "fa-solid", "fa-arrow-right"], ["Size", "compact", "Icon", "fa-solid fa-link", "Title", "No organic key matches"], [1, "fa-solid", "fa-link"], ["text", "Loading organic key matches...", "size", "small"]], template: function EntityRecordDetailPanelComponent_Template(rf, ctx) { if (rf & 1) {
1053
1231
  i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2);
1054
1232
  i0.ɵɵconditionalCreate(3, EntityRecordDetailPanelComponent_Conditional_3_Template, 1, 2, "i", 3);
1055
1233
  i0.ɵɵelementStart(4, "h3", 4);
@@ -1107,12 +1285,20 @@ export class EntityRecordDetailPanelComponent extends BaseAngularComponent {
1107
1285
  type: Input
1108
1286
  }], close: [{
1109
1287
  type: Output
1288
+ }], OpenRecord: [{
1289
+ type: Output
1110
1290
  }], openRecord: [{
1111
1291
  type: Output
1292
+ }], NavigateToRelated: [{
1293
+ type: Output
1112
1294
  }], navigateToRelated: [{
1113
1295
  type: Output
1296
+ }], OpenRelatedRecord: [{
1297
+ type: Output
1114
1298
  }], openRelatedRecord: [{
1115
1299
  type: Output
1300
+ }], OpenForeignKeyRecord: [{
1301
+ type: Output
1116
1302
  }], openForeignKeyRecord: [{
1117
1303
  type: Output
1118
1304
  }] }); })();