@memberjunction/ng-shared-generic 5.4.1 → 5.6.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.
@@ -1 +1 @@
1
- {"version":3,"file":"recent-access.service.d.ts","sourceRoot":"","sources":["../../src/lib/recent-access.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,YAAY,EAAmC,MAAM,sBAAsB,CAAC;AAExG,OAAO,EAAmB,UAAU,EAAE,MAAM,MAAM,CAAC;;AAEnD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,IAAI,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,6EAA6E;IAC7E,YAAY,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,QAAQ,CAAC;CACvE;AAED;;;GAGG;AACH,qBAGa,mBAAmB;IAC9B,OAAO,CAAC,MAAM,CAAC,SAAS,CAAsB;IAC9C,OAAO,CAAC,aAAa,CAA+C;IACpE,OAAO,CAAC,WAAW,CAAuC;IAC1D,OAAO,CAAC,SAAS,CAAS;;IAS1B,WAAkB,QAAQ,IAAI,mBAAmB,CAEhD;IAED;;OAEG;IACH,IAAW,WAAW,IAAI,UAAU,CAAC,gBAAgB,EAAE,CAAC,CAEvD;IAED;;OAEG;IACH,IAAW,gBAAgB,IAAI,gBAAgB,EAAE,CAEhD;IAED;;OAEG;IACH,IAAW,SAAS,IAAI,UAAU,CAAC,OAAO,CAAC,CAE1C;IAED;;;;;;;OAOG;IACU,SAAS,CACpB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GAAG,YAAY,EAC/B,YAAY,GAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,QAAmB,GAC/E,OAAO,CAAC,IAAI,CAAC;IA8DhB;;;;OAIG;IACU,eAAe,CAAC,QAAQ,GAAE,MAAW,EAAE,YAAY,GAAE,OAAe,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAgD/G;;OAEG;IACU,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIhD;;;OAGG;YACW,kBAAkB;IA+BhC;;;;;OAKG;IACH,OAAO,CAAC,0BAA0B;IA0BlC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAmB7B;;OAEG;IACI,UAAU,IAAI,IAAI;yCAxQd,mBAAmB;6CAAnB,mBAAmB;CA4Q/B"}
1
+ {"version":3,"file":"recent-access.service.d.ts","sourceRoot":"","sources":["../../src/lib/recent-access.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,YAAY,EAAmC,MAAM,sBAAsB,CAAC;AAGxG,OAAO,EAAmB,UAAU,EAAE,MAAM,MAAM,CAAC;;AAEnD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,IAAI,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,6EAA6E;IAC7E,YAAY,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,QAAQ,CAAC;CACvE;AAED;;;GAGG;AACH,qBAGa,mBAAmB;IAC9B,OAAO,CAAC,MAAM,CAAC,SAAS,CAAsB;IAC9C,OAAO,CAAC,aAAa,CAA+C;IACpE,OAAO,CAAC,WAAW,CAAuC;IAC1D,OAAO,CAAC,SAAS,CAAS;;IAS1B,WAAkB,QAAQ,IAAI,mBAAmB,CAEhD;IAED;;OAEG;IACH,IAAW,WAAW,IAAI,UAAU,CAAC,gBAAgB,EAAE,CAAC,CAEvD;IAED;;OAEG;IACH,IAAW,gBAAgB,IAAI,gBAAgB,EAAE,CAEhD;IAED;;OAEG;IACH,IAAW,SAAS,IAAI,UAAU,CAAC,OAAO,CAAC,CAE1C;IAED;;;;;;;OAOG;IACU,SAAS,CACpB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GAAG,YAAY,EAC/B,YAAY,GAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,QAAmB,GAC/E,OAAO,CAAC,IAAI,CAAC;IA8DhB;;;;OAIG;IACU,eAAe,CAAC,QAAQ,GAAE,MAAW,EAAE,YAAY,GAAE,OAAe,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAgD/G;;OAEG;IACU,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIhD;;;OAGG;YACW,kBAAkB;IA+BhC;;;;;OAKG;IACH,OAAO,CAAC,0BAA0B;IA0BlC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAmB7B;;OAEG;IACI,UAAU,IAAI,IAAI;yCAxQd,mBAAmB;6CAAnB,mBAAmB;CA4Q/B"}
@@ -1,6 +1,7 @@
1
1
  import { Injectable } from '@angular/core';
2
2
  import { Metadata, RunView, CompositeKey, LogError } from '@memberjunction/core';
3
3
  import { UserInfoEngine } from '@memberjunction/core-entities';
4
+ import { UUIDsEqual } from '@memberjunction/global';
4
5
  import { BehaviorSubject } from 'rxjs';
5
6
  import * as i0 from "@angular/core";
6
7
  /**
@@ -119,7 +120,7 @@ export class RecentAccessService {
119
120
  const userRecordLogs = UserInfoEngine.Instance.UserRecordLogs.slice(0, maxItems);
120
121
  const items = [];
121
122
  for (const log of userRecordLogs) {
122
- const entityInfo = md.Entities.find(e => e.ID === log.EntityID);
123
+ const entityInfo = md.Entities.find(e => UUIDsEqual(e.ID, log.EntityID));
123
124
  if (!entityInfo)
124
125
  continue;
125
126
  // Determine resource type based on entity name
@@ -1 +1 @@
1
- {"version":3,"file":"recent-access.service.js","sourceRoot":"","sources":["../../src/lib/recent-access.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { Metadata, RunView, CompositeKey, LogError, EntityRecordNameInput } from '@memberjunction/core';\nimport { MJUserRecordLogEntity, UserInfoEngine } from '@memberjunction/core-entities';\nimport { BehaviorSubject, Observable } from 'rxjs';\n\n/**\n * Represents a recently accessed resource\n */\nexport interface RecentAccessItem {\n id: string;\n entityId: string;\n entityName: string;\n recordId: string;\n recordName?: string;\n latestAt: Date;\n totalCount: number;\n /** Resource type for special handling (record, view, dashboard, artifact) */\n resourceType: 'record' | 'view' | 'dashboard' | 'artifact' | 'report';\n}\n\n/**\n * Service for tracking and retrieving recently accessed resources.\n * Uses the User Record Logs entity to persist access history.\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class RecentAccessService {\n private static _instance: RecentAccessService;\n private _recentItems$ = new BehaviorSubject<RecentAccessItem[]>([]);\n private _isLoading$ = new BehaviorSubject<boolean>(false);\n private _isLoaded = false;\n\n constructor() {\n if (RecentAccessService._instance) {\n return RecentAccessService._instance;\n }\n RecentAccessService._instance = this;\n }\n\n public static get Instance(): RecentAccessService {\n return RecentAccessService._instance;\n }\n\n /**\n * Observable of recent access items, sorted by most recent first\n */\n public get RecentItems(): Observable<RecentAccessItem[]> {\n return this._recentItems$.asObservable();\n }\n\n /**\n * Current value of recent items\n */\n public get RecentItemsValue(): RecentAccessItem[] {\n return this._recentItems$.value;\n }\n\n /**\n * Observable loading state\n */\n public get IsLoading(): Observable<boolean> {\n return this._isLoading$.asObservable();\n }\n\n /**\n * Logs access to a record. Creates or updates the User Record Log entry.\n * This is a fire-and-forget operation - errors are logged but don't interrupt the user.\n *\n * @param entityName - The name of the entity being accessed\n * @param recordId - The record ID (single value or CompositeKey string)\n * @param resourceType - The type of resource being accessed\n */\n public async logAccess(\n entityName: string,\n recordId: string | CompositeKey,\n resourceType: 'record' | 'view' | 'dashboard' | 'artifact' | 'report' = 'record'\n ): Promise<void> {\n try {\n const md = new Metadata();\n const entityInfo = md.Entities.find(e => e.Name === entityName);\n if (!entityInfo) {\n console.warn(`RecentAccessService: Entity \"${entityName}\" not found in metadata`);\n return;\n }\n\n // Convert CompositeKey to string if needed\n const recordIdString = recordId instanceof CompositeKey\n ? recordId.Values(',') // Values() returns joined string with specified delimiter\n : recordId;\n\n // Check if we already have a log entry for this user/entity/record combination\n const rv = new RunView();\n const existingResult = await rv.RunView<MJUserRecordLogEntity>({\n EntityName: 'MJ: User Record Logs',\n ExtraFilter: `UserID='${md.CurrentUser.ID}' AND EntityID='${entityInfo.ID}' AND RecordID='${recordIdString}'`,\n ResultType: 'entity_object',\n MaxRows: 1\n });\n\n if (!existingResult.Success) {\n console.error('RecentAccessService: Failed to check existing log', existingResult.ErrorMessage);\n return;\n }\n\n if (existingResult.Results && existingResult.Results.length > 0) {\n // Update existing entry\n const existing = existingResult.Results[0];\n existing.LatestAt = new Date();\n existing.TotalCount = (existing.TotalCount || 0) + 1;\n\n const saveResult = await existing.Save();\n if (!saveResult) {\n console.error('RecentAccessService: Failed to update log entry');\n }\n } else {\n // Create new entry\n const newLog = await md.GetEntityObject<MJUserRecordLogEntity>('MJ: User Record Logs');\n newLog.UserID = md.CurrentUser.ID;\n newLog.EntityID = entityInfo.ID;\n newLog.RecordID = recordIdString;\n // EarliestAt and LatestAt have default values of getdate() in the DB\n // TotalCount defaults to 0, so we set it to 1\n newLog.TotalCount = 1;\n\n const saveResult = await newLog.Save();\n if (!saveResult) {\n console.error('RecentAccessService: Failed to create log entry');\n }\n }\n\n // Refresh the recent items list in background\n this.refreshRecentItems();\n } catch (error) {\n // Don't throw - this is non-critical functionality\n console.error('RecentAccessService: Error logging access', error);\n }\n }\n\n /**\n * Loads recent access items for the current user using UserInfoEngine (cached).\n * @param maxItems - Maximum number of items to return (default 15)\n * @param forceRefresh - Force refresh even if already loaded\n */\n public async loadRecentItems(maxItems: number = 15, forceRefresh: boolean = false): Promise<RecentAccessItem[]> {\n if (this._isLoaded && !forceRefresh) {\n return this._recentItems$.value;\n }\n\n try {\n this._isLoading$.next(true);\n\n const md = new Metadata();\n\n // Get recent records, limited to maxItems (already ordered by LatestAt DESC in engine)\n const userRecordLogs = UserInfoEngine.Instance.UserRecordLogs.slice(0, maxItems);\n\n const items: RecentAccessItem[] = [];\n\n for (const log of userRecordLogs) {\n const entityInfo = md.Entities.find(e => e.ID === log.EntityID);\n if (!entityInfo) continue;\n\n // Determine resource type based on entity name\n const resourceType = this.determineResourceType(entityInfo.Name);\n\n items.push({\n id: log.ID,\n entityId: log.EntityID,\n entityName: entityInfo.Name,\n recordId: log.RecordID,\n latestAt: log.LatestAt,\n totalCount: log.TotalCount,\n resourceType\n });\n }\n\n // Batch-resolve record names for all items\n await this.resolveRecordNames(items, md);\n\n this._recentItems$.next(items);\n this._isLoaded = true;\n\n return items;\n } catch (error) {\n LogError('RecentAccessService: Error loading recent items', undefined, error);\n return [];\n } finally {\n this._isLoading$.next(false);\n }\n }\n\n /**\n * Refresh recent items in background\n */\n public async refreshRecentItems(): Promise<void> {\n await this.loadRecentItems(15, true);\n }\n\n /**\n * Batch-resolve record names for a list of recent access items using GetEntityRecordNames().\n * Mutates the items in-place to set recordName where resolved.\n */\n private async resolveRecordNames(items: RecentAccessItem[], md: Metadata): Promise<void> {\n const nameInputs: EntityRecordNameInput[] = [];\n const indexMap = new Map<string, number>();\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const compositeKey = this.buildCompositeKeyForRecord(item.entityName, item.recordId, md);\n if (!compositeKey) continue;\n\n nameInputs.push({ EntityName: item.entityName, CompositeKey: compositeKey });\n indexMap.set(`${item.entityName}||${compositeKey.ToConcatenatedString()}`, i);\n }\n\n if (nameInputs.length === 0) return;\n\n try {\n const nameResults = await md.GetEntityRecordNames(nameInputs);\n for (const result of nameResults) {\n if (result.Success && result.RecordName) {\n const key = `${result.EntityName}||${result.CompositeKey.ToConcatenatedString()}`;\n const index = indexMap.get(key);\n if (index !== undefined) {\n items[index].recordName = result.RecordName;\n }\n }\n }\n } catch (error) {\n console.warn('RecentAccessService: Failed to resolve record names', error);\n }\n }\n\n /**\n * Build a CompositeKey for a record. RecordID may be stored as either:\n * - Concatenated format: \"FieldName|Value\" or \"Field1|Val1||Field2|Val2\"\n * - Plain value: just the raw value (e.g. a GUID)\n * Detects the format and constructs the key accordingly.\n */\n private buildCompositeKeyForRecord(entityName: string, recordId: string, md: Metadata): CompositeKey | null {\n if (!recordId) return null;\n\n // If recordId contains '|', it's in concatenated format\n if (recordId.includes('|')) {\n try {\n const compositeKey = new CompositeKey();\n compositeKey.LoadFromConcatenatedString(recordId);\n if (compositeKey.KeyValuePairs.length > 0) return compositeKey;\n } catch {\n // Fall through to entity-based lookup\n }\n }\n\n // Plain value — look up entity primary key field(s) to construct the key\n const entityInfo = md.Entities.find(e => e.Name === entityName);\n if (!entityInfo) return null;\n\n const pkField = entityInfo.FirstPrimaryKey;\n if (!pkField) return null;\n\n const compositeKey = new CompositeKey();\n compositeKey.KeyValuePairs = [{ FieldName: pkField.Name, Value: recordId }];\n return compositeKey;\n }\n\n /**\n * Determines the resource type based on entity name\n */\n private determineResourceType(entityName: string): 'record' | 'view' | 'dashboard' | 'artifact' | 'report' {\n const normalizedName = entityName.toLowerCase();\n\n if (normalizedName === 'user views') {\n return 'view';\n }\n if (normalizedName === 'dashboards') {\n return 'dashboard';\n }\n if (normalizedName === 'mj: conversation artifacts' || normalizedName === 'conversation artifacts') {\n return 'artifact';\n }\n if (normalizedName === 'reports') {\n return 'report';\n }\n\n return 'record';\n }\n\n /**\n * Clears the cached recent items (useful for logout)\n */\n public clearCache(): void {\n this._recentItems$.next([]);\n this._isLoaded = false;\n }\n}\n"]}
1
+ {"version":3,"file":"recent-access.service.js","sourceRoot":"","sources":["../../src/lib/recent-access.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { Metadata, RunView, CompositeKey, LogError, EntityRecordNameInput } from '@memberjunction/core';\nimport { MJUserRecordLogEntity, UserInfoEngine } from '@memberjunction/core-entities';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { BehaviorSubject, Observable } from 'rxjs';\n\n/**\n * Represents a recently accessed resource\n */\nexport interface RecentAccessItem {\n id: string;\n entityId: string;\n entityName: string;\n recordId: string;\n recordName?: string;\n latestAt: Date;\n totalCount: number;\n /** Resource type for special handling (record, view, dashboard, artifact) */\n resourceType: 'record' | 'view' | 'dashboard' | 'artifact' | 'report';\n}\n\n/**\n * Service for tracking and retrieving recently accessed resources.\n * Uses the User Record Logs entity to persist access history.\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class RecentAccessService {\n private static _instance: RecentAccessService;\n private _recentItems$ = new BehaviorSubject<RecentAccessItem[]>([]);\n private _isLoading$ = new BehaviorSubject<boolean>(false);\n private _isLoaded = false;\n\n constructor() {\n if (RecentAccessService._instance) {\n return RecentAccessService._instance;\n }\n RecentAccessService._instance = this;\n }\n\n public static get Instance(): RecentAccessService {\n return RecentAccessService._instance;\n }\n\n /**\n * Observable of recent access items, sorted by most recent first\n */\n public get RecentItems(): Observable<RecentAccessItem[]> {\n return this._recentItems$.asObservable();\n }\n\n /**\n * Current value of recent items\n */\n public get RecentItemsValue(): RecentAccessItem[] {\n return this._recentItems$.value;\n }\n\n /**\n * Observable loading state\n */\n public get IsLoading(): Observable<boolean> {\n return this._isLoading$.asObservable();\n }\n\n /**\n * Logs access to a record. Creates or updates the User Record Log entry.\n * This is a fire-and-forget operation - errors are logged but don't interrupt the user.\n *\n * @param entityName - The name of the entity being accessed\n * @param recordId - The record ID (single value or CompositeKey string)\n * @param resourceType - The type of resource being accessed\n */\n public async logAccess(\n entityName: string,\n recordId: string | CompositeKey,\n resourceType: 'record' | 'view' | 'dashboard' | 'artifact' | 'report' = 'record'\n ): Promise<void> {\n try {\n const md = new Metadata();\n const entityInfo = md.Entities.find(e => e.Name === entityName);\n if (!entityInfo) {\n console.warn(`RecentAccessService: Entity \"${entityName}\" not found in metadata`);\n return;\n }\n\n // Convert CompositeKey to string if needed\n const recordIdString = recordId instanceof CompositeKey\n ? recordId.Values(',') // Values() returns joined string with specified delimiter\n : recordId;\n\n // Check if we already have a log entry for this user/entity/record combination\n const rv = new RunView();\n const existingResult = await rv.RunView<MJUserRecordLogEntity>({\n EntityName: 'MJ: User Record Logs',\n ExtraFilter: `UserID='${md.CurrentUser.ID}' AND EntityID='${entityInfo.ID}' AND RecordID='${recordIdString}'`,\n ResultType: 'entity_object',\n MaxRows: 1\n });\n\n if (!existingResult.Success) {\n console.error('RecentAccessService: Failed to check existing log', existingResult.ErrorMessage);\n return;\n }\n\n if (existingResult.Results && existingResult.Results.length > 0) {\n // Update existing entry\n const existing = existingResult.Results[0];\n existing.LatestAt = new Date();\n existing.TotalCount = (existing.TotalCount || 0) + 1;\n\n const saveResult = await existing.Save();\n if (!saveResult) {\n console.error('RecentAccessService: Failed to update log entry');\n }\n } else {\n // Create new entry\n const newLog = await md.GetEntityObject<MJUserRecordLogEntity>('MJ: User Record Logs');\n newLog.UserID = md.CurrentUser.ID;\n newLog.EntityID = entityInfo.ID;\n newLog.RecordID = recordIdString;\n // EarliestAt and LatestAt have default values of getdate() in the DB\n // TotalCount defaults to 0, so we set it to 1\n newLog.TotalCount = 1;\n\n const saveResult = await newLog.Save();\n if (!saveResult) {\n console.error('RecentAccessService: Failed to create log entry');\n }\n }\n\n // Refresh the recent items list in background\n this.refreshRecentItems();\n } catch (error) {\n // Don't throw - this is non-critical functionality\n console.error('RecentAccessService: Error logging access', error);\n }\n }\n\n /**\n * Loads recent access items for the current user using UserInfoEngine (cached).\n * @param maxItems - Maximum number of items to return (default 15)\n * @param forceRefresh - Force refresh even if already loaded\n */\n public async loadRecentItems(maxItems: number = 15, forceRefresh: boolean = false): Promise<RecentAccessItem[]> {\n if (this._isLoaded && !forceRefresh) {\n return this._recentItems$.value;\n }\n\n try {\n this._isLoading$.next(true);\n\n const md = new Metadata();\n\n // Get recent records, limited to maxItems (already ordered by LatestAt DESC in engine)\n const userRecordLogs = UserInfoEngine.Instance.UserRecordLogs.slice(0, maxItems);\n\n const items: RecentAccessItem[] = [];\n\n for (const log of userRecordLogs) {\n const entityInfo = md.Entities.find(e => UUIDsEqual(e.ID, log.EntityID));\n if (!entityInfo) continue;\n\n // Determine resource type based on entity name\n const resourceType = this.determineResourceType(entityInfo.Name);\n\n items.push({\n id: log.ID,\n entityId: log.EntityID,\n entityName: entityInfo.Name,\n recordId: log.RecordID,\n latestAt: log.LatestAt,\n totalCount: log.TotalCount,\n resourceType\n });\n }\n\n // Batch-resolve record names for all items\n await this.resolveRecordNames(items, md);\n\n this._recentItems$.next(items);\n this._isLoaded = true;\n\n return items;\n } catch (error) {\n LogError('RecentAccessService: Error loading recent items', undefined, error);\n return [];\n } finally {\n this._isLoading$.next(false);\n }\n }\n\n /**\n * Refresh recent items in background\n */\n public async refreshRecentItems(): Promise<void> {\n await this.loadRecentItems(15, true);\n }\n\n /**\n * Batch-resolve record names for a list of recent access items using GetEntityRecordNames().\n * Mutates the items in-place to set recordName where resolved.\n */\n private async resolveRecordNames(items: RecentAccessItem[], md: Metadata): Promise<void> {\n const nameInputs: EntityRecordNameInput[] = [];\n const indexMap = new Map<string, number>();\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const compositeKey = this.buildCompositeKeyForRecord(item.entityName, item.recordId, md);\n if (!compositeKey) continue;\n\n nameInputs.push({ EntityName: item.entityName, CompositeKey: compositeKey });\n indexMap.set(`${item.entityName}||${compositeKey.ToConcatenatedString()}`, i);\n }\n\n if (nameInputs.length === 0) return;\n\n try {\n const nameResults = await md.GetEntityRecordNames(nameInputs);\n for (const result of nameResults) {\n if (result.Success && result.RecordName) {\n const key = `${result.EntityName}||${result.CompositeKey.ToConcatenatedString()}`;\n const index = indexMap.get(key);\n if (index !== undefined) {\n items[index].recordName = result.RecordName;\n }\n }\n }\n } catch (error) {\n console.warn('RecentAccessService: Failed to resolve record names', error);\n }\n }\n\n /**\n * Build a CompositeKey for a record. RecordID may be stored as either:\n * - Concatenated format: \"FieldName|Value\" or \"Field1|Val1||Field2|Val2\"\n * - Plain value: just the raw value (e.g. a GUID)\n * Detects the format and constructs the key accordingly.\n */\n private buildCompositeKeyForRecord(entityName: string, recordId: string, md: Metadata): CompositeKey | null {\n if (!recordId) return null;\n\n // If recordId contains '|', it's in concatenated format\n if (recordId.includes('|')) {\n try {\n const compositeKey = new CompositeKey();\n compositeKey.LoadFromConcatenatedString(recordId);\n if (compositeKey.KeyValuePairs.length > 0) return compositeKey;\n } catch {\n // Fall through to entity-based lookup\n }\n }\n\n // Plain value — look up entity primary key field(s) to construct the key\n const entityInfo = md.Entities.find(e => e.Name === entityName);\n if (!entityInfo) return null;\n\n const pkField = entityInfo.FirstPrimaryKey;\n if (!pkField) return null;\n\n const compositeKey = new CompositeKey();\n compositeKey.KeyValuePairs = [{ FieldName: pkField.Name, Value: recordId }];\n return compositeKey;\n }\n\n /**\n * Determines the resource type based on entity name\n */\n private determineResourceType(entityName: string): 'record' | 'view' | 'dashboard' | 'artifact' | 'report' {\n const normalizedName = entityName.toLowerCase();\n\n if (normalizedName === 'user views') {\n return 'view';\n }\n if (normalizedName === 'dashboards') {\n return 'dashboard';\n }\n if (normalizedName === 'mj: conversation artifacts' || normalizedName === 'conversation artifacts') {\n return 'artifact';\n }\n if (normalizedName === 'reports') {\n return 'report';\n }\n\n return 'record';\n }\n\n /**\n * Clears the cached recent items (useful for logout)\n */\n public clearCache(): void {\n this._recentItems$.next([]);\n this._isLoaded = false;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-shared-generic",
3
- "version": "5.4.1",
3
+ "version": "5.6.0",
4
4
  "description": "MemberJunction: Generic Angular Shared Package - utility services and reusable elements used in any Angular application.",
5
5
  "main": "./dist/public-api.js",
6
6
  "typings": "./dist/public-api.d.ts",
@@ -31,8 +31,8 @@
31
31
  "rxjs": "^7.8.2"
32
32
  },
33
33
  "dependencies": {
34
- "@memberjunction/core": "5.4.1",
35
- "@memberjunction/core-entities": "5.4.1",
34
+ "@memberjunction/core": "5.6.0",
35
+ "@memberjunction/core-entities": "5.6.0",
36
36
  "tslib": "^2.8.1"
37
37
  },
38
38
  "sideEffects": false,