fix(plugins): preserve disabled state, keep sidebar accessible, load inactive translations
parent
2aea3beab8
commit
80e8cf95e6
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-form-wrapper">
|
||||
@if (plugin.enabled) {
|
||||
<div class="settings-form-wrapper">
|
||||
<div class="section-header-row">
|
||||
<div class="section-title-box">
|
||||
<mat-icon class="section-icon">tune</mat-icon>
|
||||
|
|
@ -145,6 +146,22 @@
|
|||
}
|
||||
</div>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="plugin-disabled-card">
|
||||
<div class="plugin-disabled-icon-box">
|
||||
<mat-icon class="plugin-disabled-icon">pause_circle_outline</mat-icon>
|
||||
</div>
|
||||
<div class="plugin-disabled-content">
|
||||
<h3 class="plugin-disabled-title">Plugin actualmente inactivo</h3>
|
||||
<p class="plugin-disabled-text">
|
||||
Este plugin se encuentra desactivado. Sus comandos, reglas contextuales y badges están pausados y ocultos para los clientes del sistema.
|
||||
</p>
|
||||
<p class="plugin-disabled-hint">
|
||||
Para ver o modificar sus parámetros de configuración y reactivar sus funciones, activa el interruptor superior.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
} @else {
|
||||
<div class="no-plugin-box">
|
||||
<mat-icon class="no-plugin-icon">info</mat-icon>
|
||||
|
|
|
|||
|
|
@ -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<string, boolean> = {};
|
||||
|
||||
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';
|
||||
|
|
|
|||
|
|
@ -166,14 +166,12 @@
|
|||
</span>
|
||||
</mat-list-item>
|
||||
|
||||
@if (pluginService.hasPlugins()) {
|
||||
<mat-list-item routerLink="/plugins" (click)="onItemClick()"
|
||||
matTooltip="Plugins y Extensiones" matTooltipShowDelay="1000">
|
||||
<span class="entry">
|
||||
<mat-icon class="icon">extension</mat-icon>
|
||||
<span>Plugins</span>
|
||||
</span>
|
||||
</mat-list-item>
|
||||
}
|
||||
<mat-list-item routerLink="/plugins" (click)="onItemClick()"
|
||||
matTooltip="Plugins y Extensiones" matTooltipShowDelay="1000">
|
||||
<span class="entry">
|
||||
<mat-icon class="icon">extension</mat-icon>
|
||||
<span>Plugins</span>
|
||||
</span>
|
||||
</mat-list-item>
|
||||
}
|
||||
</mat-nav-list>
|
||||
|
|
@ -162,7 +162,11 @@ export class PluginService {
|
|||
const manifestRequests = plugins.map(p =>
|
||||
this.http.get<Partial<PluginManifest>>(`${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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue