feat: add module info and configuration pages to admin panel
Add dedicated pages for viewing module details and configuring module settings. Includes routes, templates, and JS components for module info page showing features, menu items, dependencies, and self-contained module paths. Also adds View/Configure navigation buttons to the platform modules list. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
166
static/admin/js/module-info.js
Normal file
166
static/admin/js/module-info.js
Normal file
@@ -0,0 +1,166 @@
|
||||
// static/admin/js/module-info.js
|
||||
// Module info/detail page management
|
||||
|
||||
const moduleInfoLog = window.LogConfig?.loggers?.moduleInfo || window.LogConfig?.createLogger?.('moduleInfo') || console;
|
||||
|
||||
function adminModuleInfo(platformCode, moduleCode) {
|
||||
return {
|
||||
// Inherit base layout functionality from init-alpine.js
|
||||
...data(),
|
||||
|
||||
// Page-specific state
|
||||
currentPage: 'platforms',
|
||||
platformCode: platformCode,
|
||||
moduleCode: moduleCode,
|
||||
loading: true,
|
||||
error: null,
|
||||
successMessage: null,
|
||||
saving: false,
|
||||
|
||||
// Data
|
||||
platform: null,
|
||||
module: null,
|
||||
|
||||
// Module icons mapping (must match icons.js definitions)
|
||||
getModuleIcon(code) {
|
||||
const icons = {
|
||||
'core': 'home',
|
||||
'platform-admin': 'office-building',
|
||||
'billing': 'credit-card',
|
||||
'inventory': 'archive',
|
||||
'orders': 'shopping-cart',
|
||||
'marketplace': 'shopping-bag',
|
||||
'customers': 'users',
|
||||
'cms': 'document-text',
|
||||
'analytics': 'chart-bar',
|
||||
'messaging': 'chat',
|
||||
'dev-tools': 'code',
|
||||
'monitoring': 'chart-pie'
|
||||
};
|
||||
return icons[code] || 'puzzle-piece';
|
||||
},
|
||||
|
||||
// Modules with configuration options
|
||||
hasConfig(code) {
|
||||
return ['billing', 'inventory', 'orders', 'marketplace',
|
||||
'customers', 'cms', 'analytics', 'messaging', 'monitoring'].includes(code);
|
||||
},
|
||||
|
||||
async init() {
|
||||
// Guard against duplicate initialization
|
||||
if (window._moduleInfoInitialized) {
|
||||
moduleInfoLog.warn('Already initialized, skipping');
|
||||
return;
|
||||
}
|
||||
window._moduleInfoInitialized = true;
|
||||
|
||||
moduleInfoLog.info('=== MODULE INFO PAGE INITIALIZING ===');
|
||||
moduleInfoLog.info('Platform code:', this.platformCode);
|
||||
moduleInfoLog.info('Module code:', this.moduleCode);
|
||||
|
||||
try {
|
||||
await this.loadPlatform();
|
||||
await this.loadModuleInfo();
|
||||
moduleInfoLog.info('=== MODULE INFO PAGE INITIALIZED ===');
|
||||
} catch (error) {
|
||||
moduleInfoLog.error('Failed to initialize module info page:', error);
|
||||
this.error = 'Failed to load page data. Please refresh.';
|
||||
}
|
||||
},
|
||||
|
||||
async refresh() {
|
||||
this.error = null;
|
||||
this.successMessage = null;
|
||||
await this.loadModuleInfo();
|
||||
},
|
||||
|
||||
async loadPlatform() {
|
||||
try {
|
||||
this.platform = await apiClient.get(`/admin/platforms/${this.platformCode}`);
|
||||
moduleInfoLog.info('Loaded platform:', this.platform?.name);
|
||||
} catch (error) {
|
||||
moduleInfoLog.error('Failed to load platform:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
async loadModuleInfo() {
|
||||
this.loading = true;
|
||||
this.error = null;
|
||||
|
||||
try {
|
||||
const platformId = this.platform?.id;
|
||||
if (!platformId) {
|
||||
throw new Error('Platform not loaded');
|
||||
}
|
||||
|
||||
// Get all modules and find the specific one
|
||||
const moduleConfig = await apiClient.get(`/admin/modules/platforms/${platformId}`);
|
||||
this.module = moduleConfig.modules?.find(m => m.code === this.moduleCode);
|
||||
|
||||
if (!this.module) {
|
||||
throw new Error(`Module '${this.moduleCode}' not found`);
|
||||
}
|
||||
|
||||
moduleInfoLog.info('Loaded module info:', {
|
||||
code: this.module.code,
|
||||
name: this.module.name,
|
||||
is_enabled: this.module.is_enabled,
|
||||
is_core: this.module.is_core
|
||||
});
|
||||
} catch (error) {
|
||||
moduleInfoLog.error('Failed to load module info:', error);
|
||||
this.error = error.message || 'Failed to load module information';
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
async toggleModule() {
|
||||
if (this.module?.is_core) {
|
||||
moduleInfoLog.warn('Cannot toggle core module:', this.moduleCode);
|
||||
return;
|
||||
}
|
||||
|
||||
this.saving = true;
|
||||
this.error = null;
|
||||
this.successMessage = null;
|
||||
|
||||
const action = this.module.is_enabled ? 'disable' : 'enable';
|
||||
|
||||
try {
|
||||
const platformId = this.platform?.id;
|
||||
const endpoint = `/admin/modules/platforms/${platformId}/${action}`;
|
||||
|
||||
const result = await apiClient.post(endpoint, {
|
||||
module_code: this.moduleCode
|
||||
});
|
||||
|
||||
moduleInfoLog.info(`${action}d module:`, this.moduleCode, result);
|
||||
|
||||
// Show success message
|
||||
if (result.also_enabled?.length > 0) {
|
||||
this.successMessage = `Module '${this.module.name}' enabled. Also enabled dependencies: ${result.also_enabled.join(', ')}`;
|
||||
} else if (result.also_disabled?.length > 0) {
|
||||
this.successMessage = `Module '${this.module.name}' disabled. Also disabled dependents: ${result.also_disabled.join(', ')}`;
|
||||
} else {
|
||||
this.successMessage = `Module '${this.module.name}' ${action}d successfully`;
|
||||
}
|
||||
|
||||
// Reload module info to get updated state
|
||||
await this.loadModuleInfo();
|
||||
|
||||
// Clear success message after delay
|
||||
setTimeout(() => {
|
||||
this.successMessage = null;
|
||||
}, 5000);
|
||||
|
||||
} catch (error) {
|
||||
moduleInfoLog.error(`Failed to ${action} module:`, error);
|
||||
this.error = error.message || `Failed to ${action} module`;
|
||||
} finally {
|
||||
this.saving = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -58,6 +58,12 @@ function adminPlatformModules(platformCode) {
|
||||
return icons[moduleCode] || 'puzzle-piece';
|
||||
},
|
||||
|
||||
// Modules with configuration options
|
||||
hasConfig(moduleCode) {
|
||||
return ['billing', 'inventory', 'orders', 'marketplace',
|
||||
'customers', 'cms', 'analytics', 'messaging', 'monitoring'].includes(moduleCode);
|
||||
},
|
||||
|
||||
async init() {
|
||||
// Guard against duplicate initialization
|
||||
if (window._platformModulesInitialized) {
|
||||
|
||||
Reference in New Issue
Block a user