@memberjunction/ng-shared
Version:
MemberJunction: MJ Explorer Angular Shared Package - utility functions and other reusable elements used across other MJ Angular packages within the MJ Explorer App - do not use outside of MJ Explorer.
198 lines • 6.49 kB
JavaScript
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { Metadata } from '@memberjunction/core';
import { UserInfoEngine } from '@memberjunction/core-entities';
import * as i0 from "@angular/core";
/**
* Setting key for developer mode in MJ: User Settings entity
*/
const DEVELOPER_MODE_SETTING_KEY = 'Explorer.DeveloperMode';
/**
* Service to manage Developer Mode functionality across Explorer apps.
*
* Developer Mode shows additional debugging tools and developer-focused
* features in the UI. Only users with Developer, Admin, or System Administrator
* roles can enable developer mode.
*
* Settings are persisted using the MJ: User Settings entity via UserInfoEngine.
*
* Usage:
* ```typescript
* constructor(private devMode: DeveloperModeService) {}
*
* async ngOnInit() {
* await this.devMode.Initialize(userEntity);
*
* // Subscribe to changes
* this.devMode.IsEnabled$.subscribe(enabled => {
* this.showDevTools = enabled;
* });
* }
* ```
*/
export class DeveloperModeService {
_isEnabled$ = new BehaviorSubject(false);
_isDeveloper$ = new BehaviorSubject(false);
_initialized = false;
_currentUser = null;
/**
* Optional explicit metadata provider. Set via `setProvider()` from a
* caller with provider context. Falls back to `Metadata.Provider` when
* not set.
*/
_provider = null;
set Provider(value) {
this._provider = value;
}
get Provider() {
return this._provider ?? Metadata.Provider;
}
// Role names that qualify as "developer"
static DEVELOPER_ROLES = [
'Developer',
'Admin',
'System Administrator',
'Integration'
];
/**
* Observable for developer mode enabled state.
* Emits whenever developer mode is toggled.
*/
get IsEnabled$() {
return this._isEnabled$.asObservable();
}
/**
* Observable for whether user has developer role.
* This determines if they CAN enable developer mode.
*/
get IsDeveloper$() {
return this._isDeveloper$.asObservable();
}
/**
* Current enabled state (synchronous access)
*/
get IsEnabled() {
return this._isEnabled$.value;
}
/**
* Whether user has developer role (synchronous access)
*/
get IsDeveloper() {
return this._isDeveloper$.value;
}
/**
* Whether the service has been initialized
*/
get IsInitialized() {
return this._initialized;
}
/**
* Initialize service with current user.
* Call this after login/authentication completes.
*/
async Initialize(user) {
if (this._initialized) {
return;
}
this._currentUser = user;
// Check if user has a developer role (in-memory, no DB round-trip)
const hasDeveloperRole = this.checkDeveloperRole(user);
this._isDeveloper$.next(hasDeveloperRole);
// Load saved preference from User Settings (only if user is a developer)
if (hasDeveloperRole) {
const savedState = await this.loadSetting();
this._isEnabled$.next(savedState);
}
else {
// Non-developers always have dev mode disabled
this._isEnabled$.next(false);
}
this._initialized = true;
}
/**
* Toggle developer mode on/off.
* Only works if user has developer role.
* @returns The new state, or false if user cannot enable dev mode
*/
async Toggle() {
if (!this.IsDeveloper) {
console.warn('Developer mode not available - user does not have Developer role');
return false;
}
const newState = !this.IsEnabled;
this._isEnabled$.next(newState);
await this.saveSetting(newState);
return newState;
}
/**
* Enable developer mode (if user has developer role)
*/
async Enable() {
if (this.IsDeveloper) {
this._isEnabled$.next(true);
await this.saveSetting(true);
}
}
/**
* Disable developer mode
*/
async Disable() {
this._isEnabled$.next(false);
await this.saveSetting(false);
}
/**
* Reset the service (e.g., on logout)
*/
Reset() {
this._isEnabled$.next(false);
this._isDeveloper$.next(false);
this._initialized = false;
this._currentUser = null;
}
/**
* Load the developer mode setting from User Settings entity
*/
async loadSetting() {
try {
const engine = UserInfoEngine.Instance;
const settingValue = engine.GetSetting(DEVELOPER_MODE_SETTING_KEY);
return settingValue === 'true';
}
catch (error) {
console.warn('Failed to load developer mode setting:', error);
return false;
}
}
/**
* Save the developer mode setting to User Settings entity
*/
async saveSetting(enabled) {
try {
const engine = UserInfoEngine.Instance;
await engine.SetSetting(DEVELOPER_MODE_SETTING_KEY, String(enabled));
}
catch (error) {
console.warn('Failed to save developer mode setting:', error);
}
}
/**
* Check if user has a developer role using the in-memory UserInfo.UserRoles
* already loaded by the provider. No DB round-trip required — role names
* are denormalized onto each UserRoleInfo as `Role`.
*/
checkDeveloperRole(user) {
const currentUser = this.Provider.CurrentUser;
if (!currentUser?.UserRoles?.length) {
return false;
}
const developerRoleSet = new Set(DeveloperModeService.DEVELOPER_ROLES.map(r => r.toLowerCase()));
return currentUser.UserRoles.some(ur => ur.Role && developerRoleSet.has(ur.Role.toLowerCase()));
}
static ɵfac = function DeveloperModeService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DeveloperModeService)(); };
static ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: DeveloperModeService, factory: DeveloperModeService.ɵfac, providedIn: 'root' });
}
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(DeveloperModeService, [{
type: Injectable,
args: [{ providedIn: 'root' }]
}], null, null); })();
//# sourceMappingURL=developer-mode.service.js.map