fix(plugins): ensure reactive data binding and loading state on page reload
parent
c4aa997516
commit
49ccdfc4ec
|
|
@ -1,18 +1,20 @@
|
|||
import { Component, Input, OnInit, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { Component, Input, OnInit, OnChanges, OnDestroy, SimpleChanges } from '@angular/core';
|
||||
import { PluginManifest, PluginService, SchemaField } from '@services/plugin.service';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-plugin-settings',
|
||||
templateUrl: './plugin-settings.component.html',
|
||||
styleUrls: ['./plugin-settings.component.css']
|
||||
})
|
||||
export class PluginSettingsComponent implements OnInit, OnChanges {
|
||||
export class PluginSettingsComponent implements OnInit, OnChanges, OnDestroy {
|
||||
@Input() pluginName: string = '';
|
||||
|
||||
plugin?: PluginManifest;
|
||||
schema: SchemaField[] = [];
|
||||
configData: Record<string, any> = {};
|
||||
private pluginSub?: Subscription;
|
||||
|
||||
constructor(
|
||||
private pluginService: PluginService,
|
||||
|
|
@ -20,9 +22,16 @@ export class PluginSettingsComponent implements OnInit, OnChanges {
|
|||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.pluginSub = this.pluginService.plugins$.subscribe(() => {
|
||||
this.loadPluginData();
|
||||
});
|
||||
this.loadPluginData();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.pluginSub?.unsubscribe();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes['pluginName']) {
|
||||
this.loadPluginData();
|
||||
|
|
|
|||
|
|
@ -115,3 +115,36 @@
|
|||
font-size: 0.95rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.loading-plugins-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #ffffff;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 16px;
|
||||
padding: 60px 24px;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
border: 3px solid #e2e8f0;
|
||||
border-top-color: #1976d2;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
color: #64748b;
|
||||
font-size: 0.95rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@
|
|||
<div class="header-main-row">
|
||||
<mat-icon class="header-title-icon">extension</mat-icon>
|
||||
<h1 class="header-main-title">Plugins y Extensiones</h1>
|
||||
<span class="plugins-count-badge">{{ plugins.length }} Activo(s)</span>
|
||||
@if (!isLoading) {
|
||||
<span class="plugins-count-badge">{{ plugins.length }} Activo(s)</span>
|
||||
}
|
||||
</div>
|
||||
<p class="header-subtitle">
|
||||
Gestiona y personaliza los módulos y extensiones instalados en el servidor OpenGnsys. Cada plugin opera de manera desacoplada sin interferir con el núcleo del sistema.
|
||||
|
|
@ -12,7 +14,12 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
@if (plugins.length > 0) {
|
||||
@if (isLoading) {
|
||||
<div class="loading-plugins-box">
|
||||
<div class="loading-spinner"></div>
|
||||
<p class="loading-text">Cargando extensiones y plugins instalados...</p>
|
||||
</div>
|
||||
} @else if (plugins.length > 0) {
|
||||
<div class="plugins-content-card">
|
||||
<mat-tab-group [(selectedIndex)]="selectedTabIndex" class="custom-plugin-tabs" animationDuration="200ms">
|
||||
@for (plugin of plugins; track plugin.name) {
|
||||
|
|
@ -35,7 +42,7 @@
|
|||
<h3 class="empty-title">No hay plugins instalados</h3>
|
||||
<p class="empty-desc">
|
||||
Actualmente no hay ninguna extensión o plugin registrado en este servidor OpenGnsys.
|
||||
Cuando instales un paquete compatible (como <code>og-plugin-freeze</code>), aparecerá automáticamente aquí.
|
||||
Cuando instales un paquete compatible (como <code>ogfreeze</code>), aparecerá automáticamente aquí.
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,52 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, OnInit, OnDestroy, ChangeDetectorRef, inject } from '@angular/core';
|
||||
import { PluginManifest, PluginService } from '@services/plugin.service';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-plugins',
|
||||
templateUrl: './plugins.component.html',
|
||||
styleUrls: ['./plugins.component.css']
|
||||
})
|
||||
export class PluginsComponent implements OnInit {
|
||||
export class PluginsComponent implements OnInit, OnDestroy {
|
||||
plugins: PluginManifest[] = [];
|
||||
selectedTabIndex: number = 0;
|
||||
isLoading: boolean = true;
|
||||
private pluginSub?: Subscription;
|
||||
private cdr = inject(ChangeDetectorRef);
|
||||
|
||||
constructor(public pluginService: PluginService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
// 1. Asignar estado actual en memoria si ya existe
|
||||
this.plugins = this.pluginService.getPlugins();
|
||||
if (this.plugins.length > 0) {
|
||||
this.isLoading = false;
|
||||
}
|
||||
|
||||
// 2. Suscribirse reactivamente al flujo de plugins
|
||||
this.pluginSub = this.pluginService.plugins$.subscribe(plugins => {
|
||||
this.plugins = plugins || [];
|
||||
if (this.plugins.length > 0) {
|
||||
this.isLoading = false;
|
||||
}
|
||||
this.cdr.markForCheck();
|
||||
});
|
||||
|
||||
// 3. Forzar refresco desde el backend para garantizar datos actualizados
|
||||
this.pluginService.refreshPlugins().subscribe({
|
||||
next: (plugins) => {
|
||||
this.plugins = plugins || [];
|
||||
this.isLoading = false;
|
||||
this.cdr.markForCheck();
|
||||
},
|
||||
error: () => {
|
||||
this.isLoading = false;
|
||||
this.cdr.markForCheck();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.pluginSub?.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue