@memberjunction/ng-entity-card 6.1.2 → 6.2.0-edge.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.
|
@@ -165,6 +165,7 @@ export declare class MJEntityCardComponent extends BaseAngularComponent implemen
|
|
|
165
165
|
private resolveEntityIcon;
|
|
166
166
|
private resolveEntityDisplayName;
|
|
167
167
|
private FormatValue;
|
|
168
|
+
private isDateOnlyField;
|
|
168
169
|
private BuildEventPayload;
|
|
169
170
|
static ɵfac: i0.ɵɵFactoryDeclaration<MJEntityCardComponent, never>;
|
|
170
171
|
static ɵcmp: i0.ɵɵComponentDeclaration<MJEntityCardComponent, "mj-entity-card", never, { "EntityName": { "alias": "EntityName"; "required": false; }; "Entity": { "alias": "Entity"; "required": false; }; "Record": { "alias": "Record"; "required": false; }; "Variant": { "alias": "Variant"; "required": false; }; "Template": { "alias": "Template"; "required": false; }; "MaxDisplayFields": { "alias": "MaxDisplayFields"; "required": false; }; "ShowAvatar": { "alias": "ShowAvatar"; "required": false; }; "ShowOpenButton": { "alias": "ShowOpenButton"; "required": false; }; "ShowFieldLabels": { "alias": "ShowFieldLabels"; "required": false; }; "CssClass": { "alias": "CssClass"; "required": false; }; }, { "BeforeCardClick": "BeforeCardClick"; "CardClicked": "CardClicked"; "BeforeOpen": "BeforeOpen"; "OpenRequested": "OpenRequested"; }, never, never, true, never>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity-card.component.d.ts","sourceRoot":"","sources":["../../src/lib/entity-card.component.ts"],"names":[],"mappings":"AAAA,OAAO,EACuB,YAAY,EACtC,SAAS,EAAE,aAAa,EAC3B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"entity-card.component.d.ts","sourceRoot":"","sources":["../../src/lib/entity-card.component.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ChangeDetectorRef, inject } from '@angular/core';
|
|
2
|
+
import { IsDateOnlySQLType, FormatDateOnly } from '@memberjunction/core';
|
|
2
3
|
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
3
4
|
import { GenerateCardTemplate, GenerateCardTemplateFromMetadata, CombineTitleFields, FormatKeyAsLabel, } from './entity-card.types';
|
|
4
5
|
import * as i0 from "@angular/core";
|
|
@@ -493,7 +494,13 @@ export class MJEntityCardComponent extends BaseAngularComponent {
|
|
|
493
494
|
const d = value instanceof Date ? value : new Date(value);
|
|
494
495
|
if (isNaN(d.getTime()))
|
|
495
496
|
return String(value);
|
|
496
|
-
|
|
497
|
+
const options = { month: 'short', day: 'numeric', year: 'numeric' };
|
|
498
|
+
// A `date` column is a calendar day that arrives as UTC midnight; a local-zone
|
|
499
|
+
// formatter would land on the previous day for every reader west of Greenwich
|
|
500
|
+
// (MJ#4210). A timestamp names an instant and stays in local time.
|
|
501
|
+
if (this.isDateOnlyField(field.Name))
|
|
502
|
+
return FormatDateOnly(d, options);
|
|
503
|
+
return d.toLocaleDateString(undefined, options);
|
|
497
504
|
}
|
|
498
505
|
catch {
|
|
499
506
|
return String(value);
|
|
@@ -505,6 +512,9 @@ export class MJEntityCardComponent extends BaseAngularComponent {
|
|
|
505
512
|
}
|
|
506
513
|
}
|
|
507
514
|
}
|
|
515
|
+
isDateOnlyField(fieldName) {
|
|
516
|
+
return IsDateOnlySQLType(this.ResolvedEntity?.Fields?.find(f => f.Name === fieldName)?.Type);
|
|
517
|
+
}
|
|
508
518
|
BuildEventPayload() {
|
|
509
519
|
return {
|
|
510
520
|
EntityName: this.EntityDisplayName,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity-card.component.js","sourceRoot":"","sources":["../../src/lib/entity-card.component.ts","../../src/lib/entity-card.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component, Input, Output, EventEmitter,\n OnChanges, SimpleChanges, ChangeDetectionStrategy, ChangeDetectorRef, inject\n} from '@angular/core';\nimport { EntityInfo } from '@memberjunction/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport {\n EntityCardVariant, CardTemplate, CardDisplayField,\n CancelableCardEvent, CardRecordEvent,\n GenerateCardTemplate, GenerateCardTemplateFromMetadata,\n CombineTitleFields, FormatKeyAsLabel,\n} from './entity-card.types';\n\n/**\n * `MJEntityCardComponent` — A generic, metadata-driven entity record card.\n *\n * Renders a single entity record as a visual card with automatically prioritized\n * fields based on MemberJunction entity metadata (`IsNameField`, `DefaultInView`,\n * `Sequence`). Designed to work with both full entity records and sparse vector\n * metadata from the Knowledge Hub.\n *\n * ## Variants\n * - `compact` — Tooltip-sized. Title + 2-3 key fields. No avatar.\n * - `card` — Grid card. Avatar + title + subtitle + display fields + badge.\n * - `detail` — Full panel. All available fields with labels.\n *\n * ## Field Resolution\n * 1. **Title**: All `IsNameField` fields combined in Sequence order\n * 2. **Primary fields**: `DefaultInView=true` sorted by Sequence\n * 3. **Fallback**: First 5 non-PK/FK fields when no metadata flags are set\n *\n * ## Events\n * All interactions follow the `BeforeXXX` / `AfterXXX` cancelable event pattern.\n * Set `event.Cancel = true` in a `BeforeXXX` handler to prevent the default action.\n *\n * @example\n * ```html\n * <!-- From entity name + vector metadata -->\n * <mj-entity-card\n * [EntityName]=\"'Members'\"\n * [Record]=\"vectorMetadata\"\n * Variant=\"card\"\n * (CardClicked)=\"onCardClick($event)\">\n * </mj-entity-card>\n *\n * <!-- From EntityInfo + full record -->\n * <mj-entity-card\n * [Entity]=\"entityInfo\"\n * [Record]=\"record.GetAll()\"\n * Variant=\"detail\"\n * [ShowOpenButton]=\"true\"\n * (OpenRequested)=\"onOpen($event)\">\n * </mj-entity-card>\n * ```\n *\n * @selector mj-entity-card\n */\n@Component({\n standalone: true,\n selector: 'mj-entity-card',\n templateUrl: './entity-card.component.html',\n styleUrls: ['./entity-card.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MJEntityCardComponent extends BaseAngularComponent implements OnChanges {\n private cdr = inject(ChangeDetectorRef);\n\n // ================================================================\n // Data Inputs\n // ================================================================\n\n /**\n * The entity name (e.g., \"Members\"). Used to look up `EntityInfo` from\n * the MJ Metadata cache. Mutually exclusive with `Entity` — if both are\n * provided, `Entity` takes precedence.\n */\n @Input() EntityName: string | null = null;\n\n /**\n * Pre-resolved EntityInfo object. Takes precedence over `EntityName`.\n * Use this when you already have the EntityInfo to avoid a redundant lookup.\n */\n @Input() Entity: EntityInfo | null = null;\n\n /**\n * The record data as a plain key-value object. Works with both full entity\n * records (`record.GetAll()`) and sparse vector metadata.\n *\n * Fields not present in the record are gracefully skipped in the display.\n */\n @Input() Record: Record<string, unknown> = {};\n\n /**\n * Visual variant controlling size, layout, and detail level.\n * @default 'card'\n */\n @Input() Variant: EntityCardVariant = 'card';\n\n // ================================================================\n // Customization Inputs\n // ================================================================\n\n /**\n * Custom card template. When provided, overrides the auto-generated template.\n * Use `GenerateCardTemplate()` from the types module to build one programmatically.\n */\n @Input() Template: CardTemplate | null = null;\n\n /**\n * Maximum number of display fields in the card body.\n * Only applies when using the auto-generated template.\n * @default 4 for 'card', 2 for 'compact', unlimited for 'detail'\n */\n @Input() MaxDisplayFields: number | null = null;\n\n /**\n * Whether to show the entity icon/avatar.\n * @default true for 'card', false for 'compact', true for 'detail'\n */\n @Input() ShowAvatar: boolean | null = null;\n\n /**\n * Whether to show the \"Open Record\" button.\n * @default false\n */\n @Input() ShowOpenButton = false;\n\n /**\n * Whether to show field labels alongside values.\n * @default true for 'detail', false for 'compact', true for 'card'\n */\n @Input() ShowFieldLabels: boolean | null = null;\n\n /**\n * CSS class to apply to the outer container for custom styling.\n */\n @Input() CssClass = '';\n\n // ================================================================\n // Events — BeforeXXX / AfterXXX Pattern\n // ================================================================\n\n /**\n * Fires before the card is clicked. Set `Cancel = true` to prevent\n * the `CardClicked` event from firing.\n */\n @Output() BeforeCardClick = new EventEmitter<CancelableCardEvent<CardRecordEvent>>();\n\n /** Fires after the card is clicked (if not canceled). */\n @Output() CardClicked = new EventEmitter<CardRecordEvent>();\n\n /**\n * Fires before the \"Open Record\" button is clicked. Set `Cancel = true`\n * to prevent the `OpenRequested` event from firing.\n */\n @Output() BeforeOpen = new EventEmitter<CancelableCardEvent<CardRecordEvent>>();\n\n /** Fires when the \"Open Record\" button is clicked (if not canceled). */\n @Output() OpenRequested = new EventEmitter<CardRecordEvent>();\n\n // ================================================================\n // Computed State\n // ================================================================\n\n /** The resolved EntityInfo (from Entity input or EntityName lookup) */\n public ResolvedEntity: EntityInfo | null = null;\n\n /** The effective card template (custom or auto-generated) */\n public EffectiveTemplate: CardTemplate | null = null;\n\n /** The combined title string */\n public Title = '';\n\n /** The entity icon class (from vector metadata or entity info) */\n public EntityIcon = '';\n\n /** Resolved entity display name */\n public EntityDisplayName = '';\n\n // ================================================================\n // Lifecycle\n // ================================================================\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['Entity'] || changes['EntityName'] || changes['Record'] || changes['Template'] || changes['Variant']) {\n this.resolve();\n }\n }\n\n // ================================================================\n // Event Handlers\n // ================================================================\n\n /** @internal Handle card click with cancelable before/after pattern */\n public OnCardClick(): void {\n const payload = this.BuildEventPayload();\n const cancelable: CancelableCardEvent<CardRecordEvent> = { Data: payload, Cancel: false };\n this.BeforeCardClick.emit(cancelable);\n if (!cancelable.Cancel) {\n this.CardClicked.emit(payload);\n }\n }\n\n /** @internal Handle open button click with cancelable before/after pattern */\n public OnOpenClick(event: MouseEvent): void {\n event.stopPropagation();\n const payload = this.BuildEventPayload();\n const cancelable: CancelableCardEvent<CardRecordEvent> = { Data: payload, Cancel: false };\n this.BeforeOpen.emit(cancelable);\n if (!cancelable.Cancel) {\n this.OpenRequested.emit(payload);\n }\n }\n\n // ================================================================\n // Display Helpers (used in template)\n // ================================================================\n\n /** Get the resolved display fields, respecting maxFields for variant */\n public get DisplayFields(): CardDisplayField[] {\n if (!this.EffectiveTemplate) return [];\n const max = this.ResolvedMaxFields;\n return this.EffectiveTemplate.DisplayFields.slice(0, max);\n }\n\n /** Whether to show the avatar based on variant and input */\n public get ShouldShowAvatar(): boolean {\n if (this.ShowAvatar != null) return this.ShowAvatar;\n return this.Variant !== 'compact';\n }\n\n /** Whether to show field labels based on variant and input */\n public get ShouldShowLabels(): boolean {\n if (this.ShowFieldLabels != null) return this.ShowFieldLabels;\n return this.Variant !== 'compact';\n }\n\n /** Get formatted value for a display field */\n public GetFieldValue(field: CardDisplayField): string {\n const value = this.Record[field.Name];\n if (value == null || String(value).trim() === '') return '';\n return this.FormatValue(value, field);\n }\n\n /** Get the label for a field */\n public GetFieldLabel(fieldName: string): string {\n return this.EffectiveTemplate?.FieldLabels[fieldName] ?? FormatKeyAsLabel(fieldName);\n }\n\n /** Get initials from the title for avatar fallback */\n public get Initials(): string {\n if (!this.Title || this.Title === 'Unknown') return '?';\n const words = this.Title.split(/\\s+/).filter(w => w.length > 0);\n if (words.length === 1) return words[0].substring(0, 2).toUpperCase();\n return (words[0][0] + words[words.length - 1][0]).toUpperCase();\n }\n\n /** Get a deterministic color for the avatar based on the record */\n public get AvatarColor(): string {\n const colors = [\n 'var(--mj-brand-primary)', 'var(--mj-status-success)',\n 'var(--mj-status-warning)', 'var(--mj-status-info)',\n ];\n let hash = 0;\n const key = this.Title + (this.Record['RecordID'] ?? '');\n for (let i = 0; i < key.length; i++) {\n hash = key.charCodeAt(i) + ((hash << 5) - hash);\n }\n return colors[Math.abs(hash) % colors.length];\n }\n\n /** Get the subtitle value */\n public get Subtitle(): string {\n if (!this.EffectiveTemplate?.SubtitleField) return '';\n const v = this.Record[this.EffectiveTemplate.SubtitleField];\n return v != null ? String(v) : '';\n }\n\n /** Get the description value */\n public get Description(): string {\n if (!this.EffectiveTemplate?.DescriptionField) return '';\n const v = this.Record[this.EffectiveTemplate.DescriptionField];\n if (v == null) return '';\n const s = String(v);\n return s.length > 120 ? s.substring(0, 120) + '...' : s;\n }\n\n /** Check if a thumbnail is available */\n public get HasThumbnail(): boolean {\n if (!this.EffectiveTemplate?.ThumbnailFields) return false;\n return this.EffectiveTemplate.ThumbnailFields.some(f => {\n const v = this.Record[f];\n return v != null && String(v).trim() !== '';\n });\n }\n\n /** Get the thumbnail URL or icon class */\n public get ThumbnailValue(): string {\n if (!this.EffectiveTemplate?.ThumbnailFields) return '';\n for (const f of this.EffectiveTemplate.ThumbnailFields) {\n const v = this.Record[f];\n if (v != null && String(v).trim() !== '') return String(v);\n }\n return '';\n }\n\n /** Whether the thumbnail is an image URL */\n public get ThumbnailIsImage(): boolean {\n const v = this.ThumbnailValue;\n return v.startsWith('http://') || v.startsWith('https://') || v.startsWith('data:image/');\n }\n\n /** Whether the thumbnail is an icon class */\n public get ThumbnailIsIcon(): boolean {\n const v = this.ThumbnailValue.toLowerCase();\n return v.startsWith('fa-') || v.startsWith('fa ') || v.startsWith('fas ') || v.startsWith('far ');\n }\n\n // ================================================================\n // Private Methods\n // ================================================================\n\n private get ResolvedMaxFields(): number {\n if (this.MaxDisplayFields != null) return this.MaxDisplayFields;\n switch (this.Variant) {\n case 'compact': return 3;\n case 'card': return 4;\n case 'detail': return 999;\n }\n }\n\n private resolve(): void {\n this.ResolvedEntity = this.resolveEntity();\n this.EffectiveTemplate = this.resolveTemplate();\n this.Title = this.resolveTitle();\n this.EntityIcon = this.resolveEntityIcon();\n this.EntityDisplayName = this.resolveEntityDisplayName();\n this.cdr.markForCheck();\n }\n\n private resolveEntity(): EntityInfo | null {\n if (this.Entity) return this.Entity;\n if (!this.EntityName) return null;\n try {\n const md = this.ProviderToUse;\n return md.Entities.find(e => e.Name === this.EntityName) ?? null;\n } catch {\n return null;\n }\n }\n\n private resolveTemplate(): CardTemplate | null {\n if (this.Template) return this.Template;\n const entityName = this.Entity?.Name ?? this.EntityName;\n if (!entityName) return null;\n\n const metadataKeys = Object.keys(this.Record);\n if (this.ResolvedEntity) {\n const full = GenerateCardTemplate(this.ResolvedEntity, this.ResolvedMaxFields);\n // Filter to fields present in the record\n const keySet = new Set(metadataKeys);\n return {\n ...full,\n TitleFields: full.TitleFields.filter(f => keySet.has(f)),\n DisplayFields: full.DisplayFields.filter(f => keySet.has(f.Name)),\n SubtitleField: full.SubtitleField && keySet.has(full.SubtitleField) ? full.SubtitleField : null,\n DescriptionField: full.DescriptionField && keySet.has(full.DescriptionField) ? full.DescriptionField : null,\n ThumbnailFields: full.ThumbnailFields.filter(f => keySet.has(f)),\n BadgeField: full.BadgeField && keySet.has(full.BadgeField) ? full.BadgeField : null,\n };\n }\n\n return GenerateCardTemplateFromMetadata(entityName, metadataKeys, this.ResolvedMaxFields, this.ProviderToUse);\n }\n\n private resolveTitle(): string {\n if (!this.EffectiveTemplate || this.EffectiveTemplate.TitleFields.length === 0) {\n return String(this.Record['Name'] ?? this.Record['Title'] ?? 'Unknown');\n }\n return CombineTitleFields(this.Record, this.EffectiveTemplate.TitleFields);\n }\n\n private resolveEntityIcon(): string {\n // From vector metadata first\n const metaIcon = this.Record['EntityIcon'];\n if (metaIcon && typeof metaIcon === 'string') return metaIcon;\n // From entity info\n if (this.ResolvedEntity?.Icon) return this.ResolvedEntity.Icon;\n return 'fa-solid fa-table';\n }\n\n private resolveEntityDisplayName(): string {\n const metaEntity = this.Record['Entity'];\n if (metaEntity && typeof metaEntity === 'string') return metaEntity;\n return this.ResolvedEntity?.Name ?? this.EntityName ?? '';\n }\n\n private FormatValue(value: unknown, field: CardDisplayField): string {\n switch (field.Type) {\n case 'number': {\n const num = Number(value);\n if (isNaN(num)) return String(value);\n if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`;\n if (num >= 1000) return `${(num / 1000).toFixed(1)}K`;\n const nameLower = field.Name.toLowerCase();\n if (['amount', 'price', 'cost', 'value', 'revenue', 'total'].some(k => nameLower.includes(k))) {\n return `$${num.toLocaleString()}`;\n }\n return num.toLocaleString();\n }\n case 'boolean':\n return value ? 'Yes' : 'No';\n case 'date': {\n try {\n const d = value instanceof Date ? value : new Date(value as string | number);\n if (isNaN(d.getTime())) return String(value);\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' });\n } catch {\n return String(value);\n }\n }\n default: {\n const s = String(value);\n return s.length > 60 ? s.substring(0, 60) + '...' : s;\n }\n }\n }\n\n private BuildEventPayload(): CardRecordEvent {\n return {\n EntityName: this.EntityDisplayName,\n Record: this.Record,\n RecordID: String(this.Record['RecordID'] ?? this.Record['ID'] ?? ''),\n };\n }\n}\n","<div class=\"mj-entity-card\"\n [class]=\"'mj-entity-card--' + Variant + ' ' + CssClass\"\n (click)=\"OnCardClick()\">\n\n <!-- Avatar / Thumbnail -->\n @if (ShouldShowAvatar) {\n <div class=\"mj-ec-avatar-area\">\n @if (HasThumbnail && ThumbnailIsImage) {\n <div class=\"mj-ec-thumbnail\">\n <img [src]=\"ThumbnailValue\" alt=\"\" />\n </div>\n } @else if (HasThumbnail && ThumbnailIsIcon) {\n <div class=\"mj-ec-avatar\" [style.background]=\"AvatarColor\">\n <i [class]=\"ThumbnailValue\"></i>\n </div>\n } @else if (EntityIcon) {\n <div class=\"mj-ec-avatar\" [style.background]=\"AvatarColor\">\n <i [class]=\"EntityIcon\"></i>\n </div>\n } @else {\n <div class=\"mj-ec-avatar\" [style.background]=\"AvatarColor\">\n {{ Initials }}\n </div>\n }\n </div>\n }\n\n <!-- Content -->\n <div class=\"mj-ec-content\">\n <!-- Header: Title + Entity -->\n <div class=\"mj-ec-header\">\n <div class=\"mj-ec-title\">{{ Title }}</div>\n @if (EntityDisplayName && Variant !== 'compact') {\n <div class=\"mj-ec-entity\">{{ EntityDisplayName }}</div>\n }\n </div>\n\n <!-- Subtitle -->\n @if (Subtitle && Variant !== 'compact') {\n <div class=\"mj-ec-subtitle\">{{ Subtitle }}</div>\n }\n\n <!-- Description (detail variant only) -->\n @if (Description && Variant === 'detail') {\n <div class=\"mj-ec-description\">{{ Description }}</div>\n }\n\n <!-- Display Fields -->\n @if (DisplayFields.length > 0) {\n <div class=\"mj-ec-fields\" [class.mj-ec-fields--labeled]=\"ShouldShowLabels\">\n @for (field of DisplayFields; track field.Name) {\n @if (GetFieldValue(field); as value) {\n <div class=\"mj-ec-field\">\n @if (ShouldShowLabels) {\n <span class=\"mj-ec-field-label\">{{ field.Label }}</span>\n }\n <span class=\"mj-ec-field-value\">{{ value }}</span>\n </div>\n }\n }\n </div>\n }\n </div>\n\n <!-- Open Button -->\n @if (ShowOpenButton) {\n <button class=\"mj-ec-open-btn\" (click)=\"OnOpenClick($event)\" title=\"Open record\">\n <i class=\"fa-solid fa-external-link-alt\"></i>\n </button>\n }\n</div>\n"]}
|
|
1
|
+
{"version":3,"file":"entity-card.component.js","sourceRoot":"","sources":["../../src/lib/entity-card.component.ts","../../src/lib/entity-card.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component, Input, Output, EventEmitter,\n OnChanges, SimpleChanges, ChangeDetectionStrategy, ChangeDetectorRef, inject\n} from '@angular/core';\nimport { EntityInfo, IsDateOnlySQLType, FormatDateOnly } from '@memberjunction/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport {\n EntityCardVariant, CardTemplate, CardDisplayField,\n CancelableCardEvent, CardRecordEvent,\n GenerateCardTemplate, GenerateCardTemplateFromMetadata,\n CombineTitleFields, FormatKeyAsLabel,\n} from './entity-card.types';\n\n/**\n * `MJEntityCardComponent` — A generic, metadata-driven entity record card.\n *\n * Renders a single entity record as a visual card with automatically prioritized\n * fields based on MemberJunction entity metadata (`IsNameField`, `DefaultInView`,\n * `Sequence`). Designed to work with both full entity records and sparse vector\n * metadata from the Knowledge Hub.\n *\n * ## Variants\n * - `compact` — Tooltip-sized. Title + 2-3 key fields. No avatar.\n * - `card` — Grid card. Avatar + title + subtitle + display fields + badge.\n * - `detail` — Full panel. All available fields with labels.\n *\n * ## Field Resolution\n * 1. **Title**: All `IsNameField` fields combined in Sequence order\n * 2. **Primary fields**: `DefaultInView=true` sorted by Sequence\n * 3. **Fallback**: First 5 non-PK/FK fields when no metadata flags are set\n *\n * ## Events\n * All interactions follow the `BeforeXXX` / `AfterXXX` cancelable event pattern.\n * Set `event.Cancel = true` in a `BeforeXXX` handler to prevent the default action.\n *\n * @example\n * ```html\n * <!-- From entity name + vector metadata -->\n * <mj-entity-card\n * [EntityName]=\"'Members'\"\n * [Record]=\"vectorMetadata\"\n * Variant=\"card\"\n * (CardClicked)=\"onCardClick($event)\">\n * </mj-entity-card>\n *\n * <!-- From EntityInfo + full record -->\n * <mj-entity-card\n * [Entity]=\"entityInfo\"\n * [Record]=\"record.GetAll()\"\n * Variant=\"detail\"\n * [ShowOpenButton]=\"true\"\n * (OpenRequested)=\"onOpen($event)\">\n * </mj-entity-card>\n * ```\n *\n * @selector mj-entity-card\n */\n@Component({\n standalone: true,\n selector: 'mj-entity-card',\n templateUrl: './entity-card.component.html',\n styleUrls: ['./entity-card.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MJEntityCardComponent extends BaseAngularComponent implements OnChanges {\n private cdr = inject(ChangeDetectorRef);\n\n // ================================================================\n // Data Inputs\n // ================================================================\n\n /**\n * The entity name (e.g., \"Members\"). Used to look up `EntityInfo` from\n * the MJ Metadata cache. Mutually exclusive with `Entity` — if both are\n * provided, `Entity` takes precedence.\n */\n @Input() EntityName: string | null = null;\n\n /**\n * Pre-resolved EntityInfo object. Takes precedence over `EntityName`.\n * Use this when you already have the EntityInfo to avoid a redundant lookup.\n */\n @Input() Entity: EntityInfo | null = null;\n\n /**\n * The record data as a plain key-value object. Works with both full entity\n * records (`record.GetAll()`) and sparse vector metadata.\n *\n * Fields not present in the record are gracefully skipped in the display.\n */\n @Input() Record: Record<string, unknown> = {};\n\n /**\n * Visual variant controlling size, layout, and detail level.\n * @default 'card'\n */\n @Input() Variant: EntityCardVariant = 'card';\n\n // ================================================================\n // Customization Inputs\n // ================================================================\n\n /**\n * Custom card template. When provided, overrides the auto-generated template.\n * Use `GenerateCardTemplate()` from the types module to build one programmatically.\n */\n @Input() Template: CardTemplate | null = null;\n\n /**\n * Maximum number of display fields in the card body.\n * Only applies when using the auto-generated template.\n * @default 4 for 'card', 2 for 'compact', unlimited for 'detail'\n */\n @Input() MaxDisplayFields: number | null = null;\n\n /**\n * Whether to show the entity icon/avatar.\n * @default true for 'card', false for 'compact', true for 'detail'\n */\n @Input() ShowAvatar: boolean | null = null;\n\n /**\n * Whether to show the \"Open Record\" button.\n * @default false\n */\n @Input() ShowOpenButton = false;\n\n /**\n * Whether to show field labels alongside values.\n * @default true for 'detail', false for 'compact', true for 'card'\n */\n @Input() ShowFieldLabels: boolean | null = null;\n\n /**\n * CSS class to apply to the outer container for custom styling.\n */\n @Input() CssClass = '';\n\n // ================================================================\n // Events — BeforeXXX / AfterXXX Pattern\n // ================================================================\n\n /**\n * Fires before the card is clicked. Set `Cancel = true` to prevent\n * the `CardClicked` event from firing.\n */\n @Output() BeforeCardClick = new EventEmitter<CancelableCardEvent<CardRecordEvent>>();\n\n /** Fires after the card is clicked (if not canceled). */\n @Output() CardClicked = new EventEmitter<CardRecordEvent>();\n\n /**\n * Fires before the \"Open Record\" button is clicked. Set `Cancel = true`\n * to prevent the `OpenRequested` event from firing.\n */\n @Output() BeforeOpen = new EventEmitter<CancelableCardEvent<CardRecordEvent>>();\n\n /** Fires when the \"Open Record\" button is clicked (if not canceled). */\n @Output() OpenRequested = new EventEmitter<CardRecordEvent>();\n\n // ================================================================\n // Computed State\n // ================================================================\n\n /** The resolved EntityInfo (from Entity input or EntityName lookup) */\n public ResolvedEntity: EntityInfo | null = null;\n\n /** The effective card template (custom or auto-generated) */\n public EffectiveTemplate: CardTemplate | null = null;\n\n /** The combined title string */\n public Title = '';\n\n /** The entity icon class (from vector metadata or entity info) */\n public EntityIcon = '';\n\n /** Resolved entity display name */\n public EntityDisplayName = '';\n\n // ================================================================\n // Lifecycle\n // ================================================================\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['Entity'] || changes['EntityName'] || changes['Record'] || changes['Template'] || changes['Variant']) {\n this.resolve();\n }\n }\n\n // ================================================================\n // Event Handlers\n // ================================================================\n\n /** @internal Handle card click with cancelable before/after pattern */\n public OnCardClick(): void {\n const payload = this.BuildEventPayload();\n const cancelable: CancelableCardEvent<CardRecordEvent> = { Data: payload, Cancel: false };\n this.BeforeCardClick.emit(cancelable);\n if (!cancelable.Cancel) {\n this.CardClicked.emit(payload);\n }\n }\n\n /** @internal Handle open button click with cancelable before/after pattern */\n public OnOpenClick(event: MouseEvent): void {\n event.stopPropagation();\n const payload = this.BuildEventPayload();\n const cancelable: CancelableCardEvent<CardRecordEvent> = { Data: payload, Cancel: false };\n this.BeforeOpen.emit(cancelable);\n if (!cancelable.Cancel) {\n this.OpenRequested.emit(payload);\n }\n }\n\n // ================================================================\n // Display Helpers (used in template)\n // ================================================================\n\n /** Get the resolved display fields, respecting maxFields for variant */\n public get DisplayFields(): CardDisplayField[] {\n if (!this.EffectiveTemplate) return [];\n const max = this.ResolvedMaxFields;\n return this.EffectiveTemplate.DisplayFields.slice(0, max);\n }\n\n /** Whether to show the avatar based on variant and input */\n public get ShouldShowAvatar(): boolean {\n if (this.ShowAvatar != null) return this.ShowAvatar;\n return this.Variant !== 'compact';\n }\n\n /** Whether to show field labels based on variant and input */\n public get ShouldShowLabels(): boolean {\n if (this.ShowFieldLabels != null) return this.ShowFieldLabels;\n return this.Variant !== 'compact';\n }\n\n /** Get formatted value for a display field */\n public GetFieldValue(field: CardDisplayField): string {\n const value = this.Record[field.Name];\n if (value == null || String(value).trim() === '') return '';\n return this.FormatValue(value, field);\n }\n\n /** Get the label for a field */\n public GetFieldLabel(fieldName: string): string {\n return this.EffectiveTemplate?.FieldLabels[fieldName] ?? FormatKeyAsLabel(fieldName);\n }\n\n /** Get initials from the title for avatar fallback */\n public get Initials(): string {\n if (!this.Title || this.Title === 'Unknown') return '?';\n const words = this.Title.split(/\\s+/).filter(w => w.length > 0);\n if (words.length === 1) return words[0].substring(0, 2).toUpperCase();\n return (words[0][0] + words[words.length - 1][0]).toUpperCase();\n }\n\n /** Get a deterministic color for the avatar based on the record */\n public get AvatarColor(): string {\n const colors = [\n 'var(--mj-brand-primary)', 'var(--mj-status-success)',\n 'var(--mj-status-warning)', 'var(--mj-status-info)',\n ];\n let hash = 0;\n const key = this.Title + (this.Record['RecordID'] ?? '');\n for (let i = 0; i < key.length; i++) {\n hash = key.charCodeAt(i) + ((hash << 5) - hash);\n }\n return colors[Math.abs(hash) % colors.length];\n }\n\n /** Get the subtitle value */\n public get Subtitle(): string {\n if (!this.EffectiveTemplate?.SubtitleField) return '';\n const v = this.Record[this.EffectiveTemplate.SubtitleField];\n return v != null ? String(v) : '';\n }\n\n /** Get the description value */\n public get Description(): string {\n if (!this.EffectiveTemplate?.DescriptionField) return '';\n const v = this.Record[this.EffectiveTemplate.DescriptionField];\n if (v == null) return '';\n const s = String(v);\n return s.length > 120 ? s.substring(0, 120) + '...' : s;\n }\n\n /** Check if a thumbnail is available */\n public get HasThumbnail(): boolean {\n if (!this.EffectiveTemplate?.ThumbnailFields) return false;\n return this.EffectiveTemplate.ThumbnailFields.some(f => {\n const v = this.Record[f];\n return v != null && String(v).trim() !== '';\n });\n }\n\n /** Get the thumbnail URL or icon class */\n public get ThumbnailValue(): string {\n if (!this.EffectiveTemplate?.ThumbnailFields) return '';\n for (const f of this.EffectiveTemplate.ThumbnailFields) {\n const v = this.Record[f];\n if (v != null && String(v).trim() !== '') return String(v);\n }\n return '';\n }\n\n /** Whether the thumbnail is an image URL */\n public get ThumbnailIsImage(): boolean {\n const v = this.ThumbnailValue;\n return v.startsWith('http://') || v.startsWith('https://') || v.startsWith('data:image/');\n }\n\n /** Whether the thumbnail is an icon class */\n public get ThumbnailIsIcon(): boolean {\n const v = this.ThumbnailValue.toLowerCase();\n return v.startsWith('fa-') || v.startsWith('fa ') || v.startsWith('fas ') || v.startsWith('far ');\n }\n\n // ================================================================\n // Private Methods\n // ================================================================\n\n private get ResolvedMaxFields(): number {\n if (this.MaxDisplayFields != null) return this.MaxDisplayFields;\n switch (this.Variant) {\n case 'compact': return 3;\n case 'card': return 4;\n case 'detail': return 999;\n }\n }\n\n private resolve(): void {\n this.ResolvedEntity = this.resolveEntity();\n this.EffectiveTemplate = this.resolveTemplate();\n this.Title = this.resolveTitle();\n this.EntityIcon = this.resolveEntityIcon();\n this.EntityDisplayName = this.resolveEntityDisplayName();\n this.cdr.markForCheck();\n }\n\n private resolveEntity(): EntityInfo | null {\n if (this.Entity) return this.Entity;\n if (!this.EntityName) return null;\n try {\n const md = this.ProviderToUse;\n return md.Entities.find(e => e.Name === this.EntityName) ?? null;\n } catch {\n return null;\n }\n }\n\n private resolveTemplate(): CardTemplate | null {\n if (this.Template) return this.Template;\n const entityName = this.Entity?.Name ?? this.EntityName;\n if (!entityName) return null;\n\n const metadataKeys = Object.keys(this.Record);\n if (this.ResolvedEntity) {\n const full = GenerateCardTemplate(this.ResolvedEntity, this.ResolvedMaxFields);\n // Filter to fields present in the record\n const keySet = new Set(metadataKeys);\n return {\n ...full,\n TitleFields: full.TitleFields.filter(f => keySet.has(f)),\n DisplayFields: full.DisplayFields.filter(f => keySet.has(f.Name)),\n SubtitleField: full.SubtitleField && keySet.has(full.SubtitleField) ? full.SubtitleField : null,\n DescriptionField: full.DescriptionField && keySet.has(full.DescriptionField) ? full.DescriptionField : null,\n ThumbnailFields: full.ThumbnailFields.filter(f => keySet.has(f)),\n BadgeField: full.BadgeField && keySet.has(full.BadgeField) ? full.BadgeField : null,\n };\n }\n\n return GenerateCardTemplateFromMetadata(entityName, metadataKeys, this.ResolvedMaxFields, this.ProviderToUse);\n }\n\n private resolveTitle(): string {\n if (!this.EffectiveTemplate || this.EffectiveTemplate.TitleFields.length === 0) {\n return String(this.Record['Name'] ?? this.Record['Title'] ?? 'Unknown');\n }\n return CombineTitleFields(this.Record, this.EffectiveTemplate.TitleFields);\n }\n\n private resolveEntityIcon(): string {\n // From vector metadata first\n const metaIcon = this.Record['EntityIcon'];\n if (metaIcon && typeof metaIcon === 'string') return metaIcon;\n // From entity info\n if (this.ResolvedEntity?.Icon) return this.ResolvedEntity.Icon;\n return 'fa-solid fa-table';\n }\n\n private resolveEntityDisplayName(): string {\n const metaEntity = this.Record['Entity'];\n if (metaEntity && typeof metaEntity === 'string') return metaEntity;\n return this.ResolvedEntity?.Name ?? this.EntityName ?? '';\n }\n\n private FormatValue(value: unknown, field: CardDisplayField): string {\n switch (field.Type) {\n case 'number': {\n const num = Number(value);\n if (isNaN(num)) return String(value);\n if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`;\n if (num >= 1000) return `${(num / 1000).toFixed(1)}K`;\n const nameLower = field.Name.toLowerCase();\n if (['amount', 'price', 'cost', 'value', 'revenue', 'total'].some(k => nameLower.includes(k))) {\n return `$${num.toLocaleString()}`;\n }\n return num.toLocaleString();\n }\n case 'boolean':\n return value ? 'Yes' : 'No';\n case 'date': {\n try {\n const d = value instanceof Date ? value : new Date(value as string | number);\n if (isNaN(d.getTime())) return String(value);\n const options: Intl.DateTimeFormatOptions = { month: 'short', day: 'numeric', year: 'numeric' };\n // A `date` column is a calendar day that arrives as UTC midnight; a local-zone\n // formatter would land on the previous day for every reader west of Greenwich\n // (MJ#4210). A timestamp names an instant and stays in local time.\n if (this.isDateOnlyField(field.Name)) return FormatDateOnly(d, options);\n return d.toLocaleDateString(undefined, options);\n } catch {\n return String(value);\n }\n }\n default: {\n const s = String(value);\n return s.length > 60 ? s.substring(0, 60) + '...' : s;\n }\n }\n }\n\n private isDateOnlyField(fieldName: string): boolean {\n return IsDateOnlySQLType(this.ResolvedEntity?.Fields?.find(f => f.Name === fieldName)?.Type);\n }\n\n private BuildEventPayload(): CardRecordEvent {\n return {\n EntityName: this.EntityDisplayName,\n Record: this.Record,\n RecordID: String(this.Record['RecordID'] ?? this.Record['ID'] ?? ''),\n };\n }\n}\n","<div class=\"mj-entity-card\"\n [class]=\"'mj-entity-card--' + Variant + ' ' + CssClass\"\n (click)=\"OnCardClick()\">\n\n <!-- Avatar / Thumbnail -->\n @if (ShouldShowAvatar) {\n <div class=\"mj-ec-avatar-area\">\n @if (HasThumbnail && ThumbnailIsImage) {\n <div class=\"mj-ec-thumbnail\">\n <img [src]=\"ThumbnailValue\" alt=\"\" />\n </div>\n } @else if (HasThumbnail && ThumbnailIsIcon) {\n <div class=\"mj-ec-avatar\" [style.background]=\"AvatarColor\">\n <i [class]=\"ThumbnailValue\"></i>\n </div>\n } @else if (EntityIcon) {\n <div class=\"mj-ec-avatar\" [style.background]=\"AvatarColor\">\n <i [class]=\"EntityIcon\"></i>\n </div>\n } @else {\n <div class=\"mj-ec-avatar\" [style.background]=\"AvatarColor\">\n {{ Initials }}\n </div>\n }\n </div>\n }\n\n <!-- Content -->\n <div class=\"mj-ec-content\">\n <!-- Header: Title + Entity -->\n <div class=\"mj-ec-header\">\n <div class=\"mj-ec-title\">{{ Title }}</div>\n @if (EntityDisplayName && Variant !== 'compact') {\n <div class=\"mj-ec-entity\">{{ EntityDisplayName }}</div>\n }\n </div>\n\n <!-- Subtitle -->\n @if (Subtitle && Variant !== 'compact') {\n <div class=\"mj-ec-subtitle\">{{ Subtitle }}</div>\n }\n\n <!-- Description (detail variant only) -->\n @if (Description && Variant === 'detail') {\n <div class=\"mj-ec-description\">{{ Description }}</div>\n }\n\n <!-- Display Fields -->\n @if (DisplayFields.length > 0) {\n <div class=\"mj-ec-fields\" [class.mj-ec-fields--labeled]=\"ShouldShowLabels\">\n @for (field of DisplayFields; track field.Name) {\n @if (GetFieldValue(field); as value) {\n <div class=\"mj-ec-field\">\n @if (ShouldShowLabels) {\n <span class=\"mj-ec-field-label\">{{ field.Label }}</span>\n }\n <span class=\"mj-ec-field-value\">{{ value }}</span>\n </div>\n }\n }\n </div>\n }\n </div>\n\n <!-- Open Button -->\n @if (ShowOpenButton) {\n <button class=\"mj-ec-open-btn\" (click)=\"OnOpenClick($event)\" title=\"Open record\">\n <i class=\"fa-solid fa-external-link-alt\"></i>\n </button>\n }\n</div>\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/ng-entity-card",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.2.0-edge.0",
|
|
4
4
|
"description": "MemberJunction: Generic entity record card component with metadata-driven field prioritization",
|
|
5
5
|
"main": "./dist/public-api.js",
|
|
6
6
|
"typings": "./dist/public-api.d.ts",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"devDependencies": {
|
|
14
14
|
"@angular/compiler": "21.2.22",
|
|
15
15
|
"@angular/compiler-cli": "21.2.22",
|
|
16
|
-
"@memberjunction/ng-test-utils": "6.
|
|
16
|
+
"@memberjunction/ng-test-utils": "6.2.0-edge.0",
|
|
17
17
|
"vitest": "^4.0.18"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
"@angular/core": "^21.2.22"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@memberjunction/core": "6.
|
|
25
|
-
"@memberjunction/ng-base-types": "6.
|
|
26
|
-
"@memberjunction/global": "6.
|
|
24
|
+
"@memberjunction/core": "6.2.0-edge.0",
|
|
25
|
+
"@memberjunction/ng-base-types": "6.2.0-edge.0",
|
|
26
|
+
"@memberjunction/global": "6.2.0-edge.0",
|
|
27
27
|
"tslib": "^2.8.1"
|
|
28
28
|
},
|
|
29
29
|
"repository": {
|