feat: declarative plugin command status filtering and dynamic action labels v1.25.0
oggui-debian-package/pipeline/head This commit looks good Details
testing/ogGui-multibranch/pipeline/head There was a failure building this commit Details
oggui-debian-package/pipeline/tag This commit looks good Details

main 1.25.0
Juan Manuel Bardallo 2026-11-01 20:38:49 +01:00
parent dc4186ff4d
commit bfc7e07e2a
4 changed files with 77 additions and 15 deletions

View File

@ -1,5 +1,15 @@
# Changelog # Changelog
## [1.25.0] - 2026-11-01
### Added
- **Restricción Declarativa de Comandos de Plugins según Estado (`PluginService`, `ExecuteCommandComponent`)**:
- Incorporadas las propiedades opcionales `requireStatus` y `excludeStatus` en la interfaz `PluginCommand`, permitiendo a los plugins condicionar la disponibilidad de sus acciones en función del estado actual de los clientes.
- Implementado filtrado reactivo en `isCommandSupportedForClients`: los comandos solo se habilitan si el estado del equipo coincide con los estados requeridos (`requireStatus`) y no figura entre los estados excluidos (`excludeStatus`).
- Si un puesto de acceso libre (Aquarium) se encuentra desactivado (`DISABLED`), las opciones de reserva, liberación y renovación quedan deshabilitadas, permitiendo únicamente la acción de activación.
- Adaptación dinámica de etiqueta en comandos de conmutación de estado (`ogaquarium-toggle-status`): muestra "Activar puesto" o "Desactivar puesto" según el estado actual cuando se selecciona un único equipo.
- Suscripción reactiva a `statusUpdates$` en `ExecuteCommandComponent` para recalcular al instante la disponibilidad de acciones al recibir eventos Mercure en tiempo real.
## [1.24.7] - 2026-10-31 ## [1.24.7] - 2026-10-31
### Refactored ### Refactored

View File

@ -1,6 +1,6 @@
{ {
"name": "og-webconsole", "name": "og-webconsole",
"version": "1.24.7", "version": "1.25.0",
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"start": "ng serve", "start": "ng serve",

View File

@ -79,6 +79,9 @@ export class ExecuteCommandComponent implements OnInit {
this.pluginGroups = this.pluginService.getPluginGroups(); this.pluginGroups = this.pluginService.getPluginGroups();
this.updateCommandStates(); this.updateCommandStates();
}); });
this.pluginService.statusUpdates$.subscribe(() => {
this.updateCommandStates();
});
this.updateCommandStates(); this.updateCommandStates();
} }
@ -172,7 +175,24 @@ export class ExecuteCommandComponent implements OnInit {
if (this.pluginGroups && this.pluginGroups.length > 0) { if (this.pluginGroups && this.pluginGroups.length > 0) {
for (const group of this.pluginGroups) { for (const group of this.pluginGroups) {
for (const cmd of group.commands) { for (const cmd of group.commands) {
cmd.disabled = !hasClients || !this.pluginService.isCommandSupportedForClients(cmd, this.clientData); cmd.disabled = !hasClients || !this.pluginService.isCommandSupportedForClients(cmd, this.clientData, group.plugin.name);
// Adaptar dinámicamente la etiqueta de activar/desactivar en ogaquarium si hay un solo cliente seleccionado
if (cmd.slug === 'ogaquarium-toggle-status' && this.clientData.length === 1) {
const client = this.clientData[0];
const idKey = client.id ? String(client.id) : null;
const uuidKey = client.uuid || client.name;
const currentStatus = (idKey ? this.pluginService.getPluginStatus(group.plugin.name, idKey) : null)
|| (uuidKey ? this.pluginService.getPluginStatus(group.plugin.name, uuidKey) : null)
|| 'DISABLED';
if (currentStatus === 'DISABLED') {
cmd.label = this.translate.instant('ogaquarium.commands.activate') || 'Activar puesto';
} else {
cmd.label = this.translate.instant('ogaquarium.commands.deactivate') || 'Desactivar puesto';
}
cmd.labelKey = undefined;
}
} }
} }
} }

View File

@ -29,6 +29,8 @@ export interface PluginCommand {
confirm?: string; confirm?: string;
confirmKey?: string; confirmKey?: string;
roles?: string[]; // Roles autorizados por defecto (ej. ['ROLE_SUPER_ADMIN', 'ROLE_ORGANIZATIONAL_UNIT_ADMIN']) roles?: string[]; // Roles autorizados por defecto (ej. ['ROLE_SUPER_ADMIN', 'ROLE_ORGANIZATIONAL_UNIT_ADMIN'])
requireStatus?: string[]; // Estados requeridos del plugin para habilitar el comando
excludeStatus?: string[]; // Estados del plugin que deshabilitan el comando
} }
export interface RoleDefinition { export interface RoleDefinition {
@ -648,27 +650,57 @@ export class PluginService {
return this.getCommands().find(c => c.slug === slug); return this.getCommands().find(c => c.slug === slug);
} }
isCommandSupportedForClients(command: PluginCommand, clients: any[]): boolean { isCommandSupportedForClients(command: PluginCommand, clients: any[], pluginName?: string): boolean {
if (!command.os || command.os.length === 0) {
return true;
}
if (!clients || clients.length === 0) { if (!clients || clients.length === 0) {
return true; return true;
} }
const requiredOsList = command.os.map(os => os.toLowerCase()); if (command.os && command.os.length > 0) {
const requiredOsList = command.os.map(os => os.toLowerCase());
const osSupported = clients.every(client => {
const statusStr = (client.status || '').toLowerCase();
const matchesStatus = requiredOsList.some(req => statusStr.includes(req));
return clients.every(client => { const hasMatchingPartition = (client.partitions || []).some((partition: any) => {
const statusStr = (client.status || '').toLowerCase(); const osName = (partition.operativeSystem?.name || partition.operativeSystem || '').toLowerCase();
const matchesStatus = requiredOsList.some(req => statusStr.includes(req)); return requiredOsList.some(req => osName.includes(req));
});
const hasMatchingPartition = (client.partitions || []).some((partition: any) => { return matchesStatus || hasMatchingPartition;
const osName = (partition.operativeSystem?.name || partition.operativeSystem || '').toLowerCase();
return requiredOsList.some(req => osName.includes(req));
}); });
return matchesStatus || hasMatchingPartition; if (!osSupported) {
}); return false;
}
}
if (pluginName && (command.requireStatus || command.excludeStatus)) {
return clients.every(client => {
const idKey = client.id ? String(client.id) : null;
const uuidKey = client.uuid || client.name;
const currentStatus = (idKey ? this.getPluginStatus(pluginName, idKey) : null)
|| (uuidKey ? this.getPluginStatus(pluginName, uuidKey) : null)
|| 'DISABLED';
if (command.excludeStatus && command.excludeStatus.length > 0) {
const excludedUpper = command.excludeStatus.map(s => s.toUpperCase());
if (excludedUpper.includes(currentStatus.toUpperCase())) {
return false;
}
}
if (command.requireStatus && command.requireStatus.length > 0) {
const requiredUpper = command.requireStatus.map(s => s.toUpperCase());
if (!requiredUpper.includes(currentStatus.toUpperCase())) {
return false;
}
}
return true;
});
}
return true;
} }
getClientBadges(client: any): PluginBadge[] { getClientBadges(client: any): PluginBadge[] {