fix(crowdsec-dashboard): Use baseclass.singleton for theme manager

Fix "not a constructor" error by using baseclass.singleton()
pattern instead of baseclass.extend() with manual instantiation.
Theme module now exports a singleton directly.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-01-30 09:30:54 +01:00
parent 2d15c641f1
commit b35b86684e
3 changed files with 13 additions and 22 deletions

View File

@ -3,7 +3,7 @@
'require uci'; 'require uci';
/** /**
* CrowdSec Dashboard Theme Manager * CrowdSec Dashboard Theme Manager (Singleton)
* Handles loading and switching between UI themes * Handles loading and switching between UI themes
* *
* Available themes: * Available themes:
@ -13,11 +13,10 @@
* *
* Profiles can extend themes with custom configurations * Profiles can extend themes with custom configurations
* *
* Usage: var theme = new (require('crowdsec-dashboard.theme'))(); * Usage: theme.init().then(function() { ... });
* theme.init().then(function() { ... });
*/ */
return baseclass.extend({ return baseclass.singleton({
// Available themes // Available themes
themes: { themes: {
'classic': { 'classic': {

View File

@ -5,7 +5,7 @@
'require ui'; 'require ui';
'require uci'; 'require uci';
'require crowdsec-dashboard.api as api'; 'require crowdsec-dashboard.api as api';
'require crowdsec-dashboard.theme as ThemeClass'; 'require crowdsec-dashboard.theme as theme';
/** /**
* CrowdSec SOC Dashboard - Overview * CrowdSec SOC Dashboard - Overview
@ -13,16 +13,12 @@
* Version 1.1.0 * Version 1.1.0
*/ */
var themeInstance = new ThemeClass();
return view.extend({ return view.extend({
title: _('CrowdSec SOC'), title: _('CrowdSec SOC'),
theme: themeInstance,
load: function() { load: function() {
var self = this;
return Promise.all([ return Promise.all([
self.theme.init(), theme.init(),
api.getOverview().catch(function() { return {}; }) api.getOverview().catch(function() { return {}; })
]); ]);
}, },
@ -34,7 +30,7 @@ return view.extend({
// Apply theme class // Apply theme class
document.body.classList.add('cs-fullwidth'); document.body.classList.add('cs-fullwidth');
var view = E('div', { 'class': self.theme.getDashboardClass() }, [ var view = E('div', { 'class': theme.getDashboardClass() }, [
this.renderHeader(status), this.renderHeader(status),
this.renderNav('overview'), this.renderNav('overview'),
E('div', { 'id': 'cs-stats' }, this.renderStats(status)), E('div', { 'id': 'cs-stats' }, this.renderStats(status)),

View File

@ -4,7 +4,7 @@
'require ui'; 'require ui';
'require uci'; 'require uci';
'require crowdsec-dashboard.api as api'; 'require crowdsec-dashboard.api as api';
'require crowdsec-dashboard.theme as ThemeClass'; 'require crowdsec-dashboard.theme as theme';
/** /**
* CrowdSec SOC - Settings View * CrowdSec SOC - Settings View
@ -12,19 +12,15 @@
* With theme/appearance settings * With theme/appearance settings
*/ */
var themeInstance = new ThemeClass();
return view.extend({ return view.extend({
title: _('Settings'), title: _('Settings'),
status: {}, status: {},
machines: [], machines: [],
collections: [], collections: [],
theme: themeInstance,
load: function() { load: function() {
var self = this;
return Promise.all([ return Promise.all([
self.theme.init(), theme.init(),
api.getStatus(), api.getStatus(),
api.getMachines(), api.getMachines(),
api.getCollections(), api.getCollections(),
@ -46,7 +42,7 @@ return view.extend({
document.body.classList.add('cs-fullwidth'); document.body.classList.add('cs-fullwidth');
return E('div', { 'class': self.theme.getDashboardClass() }, [ return E('div', { 'class': theme.getDashboardClass() }, [
this.renderHeader(), this.renderHeader(),
this.renderNav('settings'), this.renderNav('settings'),
E('div', { 'class': 'cs-stats' }, this.renderServiceStats()), E('div', { 'class': 'cs-stats' }, this.renderServiceStats()),
@ -93,8 +89,8 @@ return view.extend({
var currentTheme = uci.get('crowdsec-dashboard', 'main', 'theme') || 'classic'; var currentTheme = uci.get('crowdsec-dashboard', 'main', 'theme') || 'classic';
var currentProfile = uci.get('crowdsec-dashboard', 'main', 'profile') || 'default'; var currentProfile = uci.get('crowdsec-dashboard', 'main', 'profile') || 'default';
var themes = this.theme.getThemes(); var themes = theme.getThemes();
var profiles = this.theme.getProfiles(); var profiles = theme.getProfiles();
return E('div', {}, [ return E('div', {}, [
E('div', { 'style': 'margin-bottom: 16px;' }, [ E('div', { 'style': 'margin-bottom: 16px;' }, [
@ -131,11 +127,11 @@ return view.extend({
}, },
previewTheme: function(themeName) { previewTheme: function(themeName) {
this.theme.switchTheme(themeName); theme.switchTheme(themeName);
}, },
previewProfile: function(profileName) { previewProfile: function(profileName) {
this.theme.switchProfile(profileName); theme.switchProfile(profileName);
}, },
saveAppearance: function() { saveAppearance: function() {