From 80e8cf95e63f09f6b987ee7840b99e64bfdcd939 Mon Sep 17 00:00:00 2001 From: jmbardallo Date: Mon, 26 Oct 2026 13:32:23 +0100 Subject: [PATCH] fix(plugins): preserve disabled state, keep sidebar accessible, load inactive translations --- .../plugin-settings.component.css | 55 +++++++++++++++++++ .../plugin-settings.component.html | 19 ++++++- .../plugin-settings.component.ts | 8 ++- .../app/layout/sidebar/sidebar.component.html | 16 +++--- .../src/app/services/plugin.service.ts | 12 +++- 5 files changed, 97 insertions(+), 13 deletions(-) diff --git a/ogWebconsole/src/app/components/plugins/plugin-settings/plugin-settings.component.css b/ogWebconsole/src/app/components/plugins/plugin-settings/plugin-settings.component.css index 243adc3..a0dd8b8 100644 --- a/ogWebconsole/src/app/components/plugins/plugin-settings/plugin-settings.component.css +++ b/ogWebconsole/src/app/components/plugins/plugin-settings/plugin-settings.component.css @@ -443,6 +443,61 @@ height: 48px; } +.plugin-disabled-card { + display: flex; + align-items: center; + gap: 24px; + background: #ffffff; + border: 1px dashed #cbd5e1; + border-radius: 12px; + padding: 36px 30px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.02); +} + +.plugin-disabled-icon-box { + display: flex; + align-items: center; + justify-content: center; + width: 56px; + height: 56px; + background: #f1f5f9; + color: #64748b; + border-radius: 12px; + flex-shrink: 0; +} + +.plugin-disabled-icon { + font-size: 32px; + width: 32px; + height: 32px; +} + +.plugin-disabled-content { + display: flex; + flex-direction: column; + gap: 6px; +} + +.plugin-disabled-title { + margin: 0; + font-size: 1.15rem; + font-weight: 700; + color: #334155; +} + +.plugin-disabled-text { + margin: 0; + color: #64748b; + font-size: 0.92rem; + line-height: 1.5; +} + +.plugin-disabled-hint { + margin: 4px 0 0 0; + color: #94a3b8; + font-size: 0.85rem; +} + @media (max-width: 900px) { .section-header-row { flex-direction: column; diff --git a/ogWebconsole/src/app/components/plugins/plugin-settings/plugin-settings.component.html b/ogWebconsole/src/app/components/plugins/plugin-settings/plugin-settings.component.html index 77ead50..9e3ef77 100644 --- a/ogWebconsole/src/app/components/plugins/plugin-settings/plugin-settings.component.html +++ b/ogWebconsole/src/app/components/plugins/plugin-settings/plugin-settings.component.html @@ -23,7 +23,8 @@ -
+ @if (plugin.enabled) { +
tune @@ -145,6 +146,22 @@ }
+ } @else { +
+
+ pause_circle_outline +
+
+

Plugin actualmente inactivo

+

+ Este plugin se encuentra desactivado. Sus comandos, reglas contextuales y badges están pausados y ocultos para los clientes del sistema. +

+

+ Para ver o modificar sus parámetros de configuración y reactivar sus funciones, activa el interruptor superior. +

+
+
+ } } @else {
info diff --git a/ogWebconsole/src/app/components/plugins/plugin-settings/plugin-settings.component.ts b/ogWebconsole/src/app/components/plugins/plugin-settings/plugin-settings.component.ts index 63e112d..2656de3 100644 --- a/ogWebconsole/src/app/components/plugins/plugin-settings/plugin-settings.component.ts +++ b/ogWebconsole/src/app/components/plugins/plugin-settings/plugin-settings.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit, OnChanges, OnDestroy, SimpleChanges, inject } from '@angular/core'; +import { Component, Input, OnInit, OnChanges, OnDestroy, SimpleChanges, ChangeDetectorRef, inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { PluginManifest, PluginService, SchemaField } from '@services/plugin.service'; import { ConfigService } from '@services/config.service'; @@ -20,6 +20,7 @@ export class PluginSettingsComponent implements OnInit, OnChanges, OnDestroy { editingScripts: Record = {}; private pluginSub?: Subscription; + private cdr = inject(ChangeDetectorRef); private sanitizer = inject(DomSanitizer); private http = inject(HttpClient); private configService = inject(ConfigService); @@ -53,10 +54,15 @@ export class PluginSettingsComponent implements OnInit, OnChanges, OnDestroy { this.schema = this.plugin.schema; this.configData = this.pluginService.getPluginConfig(this.pluginName); } + this.cdr.markForCheck(); } toggleEnabled(checked: boolean): void { if (!this.pluginName) return; + if (this.plugin) { + this.plugin.enabled = checked; + this.cdr.markForCheck(); + } this.pluginService.togglePlugin(this.pluginName, checked).subscribe({ next: () => { const statusText = checked ? 'activado' : 'desactivado'; diff --git a/ogWebconsole/src/app/layout/sidebar/sidebar.component.html b/ogWebconsole/src/app/layout/sidebar/sidebar.component.html index 9c46b80..f86e9b7 100644 --- a/ogWebconsole/src/app/layout/sidebar/sidebar.component.html +++ b/ogWebconsole/src/app/layout/sidebar/sidebar.component.html @@ -166,14 +166,12 @@ - @if (pluginService.hasPlugins()) { - - - extension - Plugins - - - } + + + extension + Plugins + + } \ No newline at end of file diff --git a/ogWebconsole/src/app/services/plugin.service.ts b/ogWebconsole/src/app/services/plugin.service.ts index aa62694..1eb7309 100644 --- a/ogWebconsole/src/app/services/plugin.service.ts +++ b/ogWebconsole/src/app/services/plugin.service.ts @@ -162,7 +162,11 @@ export class PluginService { const manifestRequests = plugins.map(p => this.http.get>(`${apiUrl}/plugins/${p.name}/manifest`).pipe( catchError(() => of({})), - map(extra => ({ ...p, ...extra })) + map(extra => ({ + ...p, + ...extra, + enabled: Boolean(p.enabled) // La base de datos es la única fuente de verdad para el estado de activación + })) ) ); @@ -191,7 +195,7 @@ export class PluginService { const currentLang = lang || this.translateService.currentLang || this.translateService.defaultLang || 'es'; const apiUrl = this.configService.apiUrl; - for (const plugin of this.activePlugins) { + for (const plugin of this.allPlugins) { // 1. Si el plugin declara i18n directamente en el manifest, lo inyectamos if (plugin.i18n && typeof plugin.i18n === 'object') { for (const [l, dict] of Object.entries(plugin.i18n)) { @@ -265,6 +269,10 @@ export class PluginService { } hasPlugins(): boolean { + return this.allPlugins.length > 0; + } + + hasActivePlugins(): boolean { return this.getPlugins().length > 0; }