Files
orion/app/modules/tenancy/static/admin/js/platform-menu-config.js
Samir Boulahtit ce822af883
Some checks failed
CI / ruff (push) Successful in 9s
CI / pytest (push) Failing after 47m32s
CI / validate (push) Successful in 23s
CI / dependency-scanning (push) Successful in 29s
CI / docs (push) Has been skipped
CI / deploy (push) Has been skipped
feat: production launch — email audit, team invites, security headers, router fixes
- Fix loyalty & monitoring router bugs (_get_router → named routers)
- Implement team invitation email with send_template + seed templates (en/fr/de)
- Add SecurityHeadersMiddleware (nosniff, HSTS, referrer-policy, permissions-policy)
- Build email audit admin page: service, schemas, API, page route, menu, i18n, HTML, JS
- Clean stale TODO in platform-menu-config.js
- Add 67 tests (unit + integration) covering all new functionality

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 18:24:30 +01:00

208 lines
7.3 KiB
JavaScript

// static/admin/js/platform-menu-config.js
// Platform menu configuration management
//
// Sidebar updates correctly here via window.location.reload() after changes.
const menuConfigLog = window.LogConfig?.loggers?.menuConfig || window.LogConfig?.createLogger?.('menuConfig') || console;
function adminPlatformMenuConfig(platformCode) {
return {
// Inherit base layout functionality from init-alpine.js
...data(),
// Page-specific state
currentPage: 'platforms',
platformCode: platformCode,
loading: true,
error: null,
successMessage: null,
saving: false,
showShowAllModal: false,
showHideAllModal: false,
// Data
platform: null,
menuConfig: null,
frontendType: 'admin',
// Computed grouped items
get groupedItems() {
if (!this.menuConfig?.items) return [];
// Group items by section
const sections = {};
for (const item of this.menuConfig.items) {
const sectionId = item.section_id;
if (!sections[sectionId]) {
sections[sectionId] = {
id: sectionId,
label: item.section_label,
isSuperAdminOnly: item.is_super_admin_only,
items: [],
visibleCount: 0
};
}
sections[sectionId].items.push(item);
if (item.is_visible) {
sections[sectionId].visibleCount++;
}
}
// Convert to array and maintain order
return Object.values(sections);
},
async init() {
// Guard against duplicate initialization
if (window._platformMenuConfigInitialized) {
menuConfigLog.warn('Already initialized, skipping');
return;
}
window._platformMenuConfigInitialized = true;
menuConfigLog.info('=== PLATFORM MENU CONFIG PAGE INITIALIZING ===');
menuConfigLog.info('Platform code:', this.platformCode);
try {
// Load tenancy translations for confirmations
await I18n.loadModule('tenancy');
await this.loadPlatform();
await this.loadPlatformMenuConfig();
menuConfigLog.info('=== PLATFORM MENU CONFIG PAGE INITIALIZED ===');
} catch (error) {
menuConfigLog.error('Failed to initialize menu config page:', error);
this.error = 'Failed to load page data. Please refresh.';
}
},
async refresh() {
this.error = null;
this.successMessage = null;
await this.loadPlatformMenuConfig();
},
async loadPlatform() {
try {
this.platform = await apiClient.get(`/admin/platforms/${this.platformCode}`);
menuConfigLog.info('Loaded platform:', this.platform?.name);
} catch (error) {
menuConfigLog.error('Failed to load platform:', error);
throw error;
}
},
async loadPlatformMenuConfig() {
this.loading = true;
this.error = null;
try {
const platformId = this.platform?.id;
if (!platformId) {
throw new Error('Platform not loaded');
}
const params = new URLSearchParams({ frontend_type: this.frontendType });
this.menuConfig = await apiClient.get(`/admin/menu-config/platforms/${platformId}?${params}`);
menuConfigLog.info('Loaded menu config:', {
frontendType: this.frontendType,
totalItems: this.menuConfig?.total_items,
visibleItems: this.menuConfig?.visible_items
});
} catch (error) {
menuConfigLog.error('Failed to load menu config:', error);
this.error = error.message || 'Failed to load menu configuration';
} finally {
this.loading = false;
}
},
async toggleVisibility(item) {
if (item.is_mandatory) {
menuConfigLog.warn('Cannot toggle mandatory item:', item.id);
return;
}
this.saving = true;
this.error = null;
this.successMessage = null;
const newVisibility = !item.is_visible;
try {
const platformId = this.platform?.id;
const params = new URLSearchParams({ frontend_type: this.frontendType });
await apiClient.put(`/admin/menu-config/platforms/${platformId}?${params}`, {
menu_item_id: item.id,
is_visible: newVisibility
});
// Update local state
item.is_visible = newVisibility;
// Update counts
if (newVisibility) {
this.menuConfig.visible_items++;
this.menuConfig.hidden_items--;
} else {
this.menuConfig.visible_items--;
this.menuConfig.hidden_items++;
}
menuConfigLog.info('Toggled visibility:', item.id, newVisibility);
// Reload the page to refresh sidebar
window.location.reload();
} catch (error) {
menuConfigLog.error('Failed to toggle visibility:', error);
this.error = error.message || 'Failed to update menu visibility';
this.saving = false;
}
},
async showAll() {
this.saving = true;
this.error = null;
this.successMessage = null;
try {
const platformId = this.platform?.id;
const params = new URLSearchParams({ frontend_type: this.frontendType });
await apiClient.post(`/admin/menu-config/platforms/${platformId}/show-all?${params}`);
menuConfigLog.info('Showed all menu items');
// Reload the page to refresh sidebar
window.location.reload();
} catch (error) {
menuConfigLog.error('Failed to show all menu items:', error);
this.error = error.message || 'Failed to show all menu items';
this.saving = false;
}
},
async resetToDefaults() {
this.saving = true;
this.error = null;
this.successMessage = null;
try {
const platformId = this.platform?.id;
const params = new URLSearchParams({ frontend_type: this.frontendType });
await apiClient.post(`/admin/menu-config/platforms/${platformId}/reset?${params}`);
menuConfigLog.info('Reset menu config to defaults');
// Reload the page to refresh sidebar
window.location.reload();
} catch (error) {
menuConfigLog.error('Failed to reset menu config:', error);
this.error = error.message || 'Failed to reset menu configuration';
this.saving = false;
}
}
};
}