Add CommandDetailComponent and CreateCommandComponent
parent
9fb62a8f6e
commit
e852a7243f
|
@ -84,6 +84,8 @@ import { OgDhcpSubnetsComponent } from './components/ogdhcp/og-dhcp-subnets/og-d
|
|||
import { CreateSubnetComponent } from './components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component';
|
||||
import { AddClientsToSubnetComponent } from './components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component';
|
||||
import { CommandsComponent } from './components/commands/commands.component';
|
||||
import { CommandDetailComponent } from './components/commands/command-detail/command-detail/command-detail.component';
|
||||
import { CreateCommandComponent } from './components/commands/create-command/create-command.component';
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
|
@ -126,7 +128,9 @@ import { CommandsComponent } from './components/commands/commands.component';
|
|||
OgDhcpSubnetsComponent,
|
||||
CreateSubnetComponent,
|
||||
AddClientsToSubnetComponent,
|
||||
CommandsComponent
|
||||
CommandsComponent,
|
||||
CommandDetailComponent,
|
||||
CreateCommandComponent
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
imports: [BrowserModule,
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
.modal-container {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
width: calc(100% - 20px); /* Ajusta el ancho para dejar un margen */
|
||||
height: calc(100% - 20px); /* Ajusta la altura para dejar un margen */
|
||||
margin: 10px; /* Añade el margen para que no esté pegado a los bordes */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
box-sizing: border-box; /* Asegura que los bordes y el padding se incluyan en el tamaño */
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: 1.5em;
|
||||
margin-bottom: 15px;
|
||||
color: #333;
|
||||
border-bottom: 2px solid #eee;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
flex-grow: 1;
|
||||
overflow-y: auto;
|
||||
padding: 10px; /* Añade espacio entre el contenido y los bordes del modal */
|
||||
box-sizing: border-box; /* Asegura que el padding esté dentro del ancho del modal */
|
||||
}
|
||||
|
||||
.modal-content p {
|
||||
margin: 10px 0;
|
||||
font-size: 1em;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.script-display {
|
||||
margin-top: 20px;
|
||||
background-color: #282c34;
|
||||
color: #ffffff;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
font-size: 0.9em;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.button-row {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 20px;
|
||||
padding: 10px; /* Añade espacio en el borde inferior */
|
||||
}
|
||||
|
||||
.button-row button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.primary-button {
|
||||
background-color: #007bff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.accent-button {
|
||||
background-color: #17a2b8;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.cancel-button {
|
||||
background-color: #dc3545;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.primary-button:hover,
|
||||
.accent-button:hover,
|
||||
.cancel-button:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin: 0;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<div class="modal-container">
|
||||
<h3 class="modal-title">Detalles del Comando</h3>
|
||||
<div class="modal-content">
|
||||
<p><strong>Nombre:</strong> {{ data.name }}</p>
|
||||
<p><strong>Comentarios:</strong> {{ data.comments }}</p>
|
||||
<p><strong>Creado por:</strong> {{ data.createdBy }}</p>
|
||||
<p><strong>Fecha de Creación:</strong> {{ data.createdAt | date:'medium' }}</p>
|
||||
|
||||
<div class="script-display">
|
||||
<h4>Script:</h4>
|
||||
<pre>{{ data.script }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="button-row">
|
||||
<button mat-button color="primary" class="primary-button" (click)="execute()">Ejecutar</button>
|
||||
<button mat-button color="accent" class="accent-button" (click)="edit()">Editar</button>
|
||||
<button mat-button class="cancel-button" (click)="cancel()">Cancelar</button>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CommandDetailComponent } from './command-detail.component';
|
||||
|
||||
describe('CommandDetailComponent', () => {
|
||||
let component: CommandDetailComponent;
|
||||
let fixture: ComponentFixture<CommandDetailComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [CommandDetailComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(CommandDetailComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,40 @@
|
|||
import { Component, Inject } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import { CreateCommandComponent } from '../../create-command/create-command.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-command-detail',
|
||||
templateUrl: './command-detail.component.html',
|
||||
styleUrls: ['./command-detail.component.css']
|
||||
})
|
||||
export class CommandDetailComponent {
|
||||
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<CommandDetailComponent>,
|
||||
private dialog: MatDialog,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any // Recibe el comando desde el componente padre
|
||||
) {}
|
||||
|
||||
// Funciones para los botones
|
||||
execute(): void {
|
||||
console.log('Ejecutar comando:', this.data);
|
||||
this.dialogRef.close(); // Cierra el modal después de ejecutar
|
||||
}
|
||||
|
||||
edit(): void {
|
||||
const dialogRef = this.dialog.open(CreateCommandComponent, {
|
||||
width: '600px',
|
||||
data: { command: this.data }
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
cancel(): void {
|
||||
console.log('Comando recibido:', this.data); // Muestra el comando en la consola
|
||||
this.dialogRef.close(); // Cierra el modal sin hacer nada
|
||||
}
|
||||
}
|
|
@ -34,3 +34,11 @@ pre {
|
|||
margin: 0;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
}
|
||||
|
||||
.mat-elevation-z8{
|
||||
margin-top: 20px;
|
||||
}
|
||||
tr:hover {
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
cursor: pointer;
|
||||
}
|
|
@ -1,22 +1,25 @@
|
|||
<div class="commands-list">
|
||||
<h2>Lista de Comandos</h2>
|
||||
<ul>
|
||||
<li *ngFor="let command of commands" (click)="selectCommand(command)" class="command-item">
|
||||
<strong>{{ command.name }}</strong> - Creado por: {{ command.createdBy }} el {{ command.createdAt | date:'short' }}
|
||||
</li>
|
||||
</ul>
|
||||
<div class="header-container">
|
||||
<h2 class="title" i18n="@@subnetsTitle">Administrar comandos</h2>
|
||||
<div class="subnets-button-row">
|
||||
<button mat-flat-button color="primary" (click)="openCreateCommandModal()">Añadir Comando</button>
|
||||
</div>
|
||||
|
||||
<div *ngIf="selectedCommand" class="command-details">
|
||||
<h3>Detalles del Comando</h3>
|
||||
<p><strong>Nombre:</strong> {{ selectedCommand.name }}</p>
|
||||
<p><strong>Comentarios:</strong> {{ selectedCommand.comments }}</p>
|
||||
<p><strong>Creado por:</strong> {{ selectedCommand.createdBy }}</p>
|
||||
<p><strong>Fecha de Creación:</strong> {{ selectedCommand.createdAt | date:'medium' }}</p>
|
||||
|
||||
<div class="script-display">
|
||||
<h4>Script:</h4>
|
||||
<pre>{{ selectedCommand.script }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<table mat-table [dataSource]="commands" class="mat-elevation-z8">
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef> Nombre </th>
|
||||
<td mat-cell *matCellDef="let command"> {{ command.name }} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="createdBy">
|
||||
<th mat-header-cell *matHeaderCellDef> Creado por </th>
|
||||
<td mat-cell *matCellDef="let command"> {{ command.createdBy }} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="createdAt">
|
||||
<th mat-header-cell *matHeaderCellDef> Fecha de creación </th>
|
||||
<td mat-cell *matCellDef="let command"> {{ command.createdAt | date:'short' }} </td>
|
||||
</ng-container>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;" (click)="openCommandDetailModal(row)"></tr>
|
||||
</table>
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http'; // Importar HttpClient
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { CommandDetailComponent } from './command-detail/command-detail/command-detail.component';
|
||||
import { CreateCommandComponent } from './create-command/create-command.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-commands',
|
||||
|
@ -7,23 +10,20 @@ import { HttpClient } from '@angular/common/http'; // Importar HttpClient
|
|||
styleUrls: ['./commands.component.css']
|
||||
})
|
||||
export class CommandsComponent implements OnInit {
|
||||
|
||||
commands: any[] = [];
|
||||
selectedCommand: any = null;
|
||||
|
||||
// URL de la API
|
||||
displayedColumns: string[] = ['name', 'createdBy', 'createdAt'];
|
||||
private apiUrl = 'http://127.0.0.1:8001/commands?page=1&itemsPerPage=30';
|
||||
|
||||
constructor(private http: HttpClient) { }
|
||||
constructor(private http: HttpClient, private dialog: MatDialog) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadCommands(); // Llamada a la API cuando el componente se inicializa
|
||||
this.loadCommands();
|
||||
}
|
||||
|
||||
loadCommands(): void {
|
||||
this.http.get<any>(this.apiUrl).subscribe(
|
||||
(data) => {
|
||||
this.commands = data['hydra:member']; // Almacena los comandos en la variable
|
||||
this.commands = data['hydra:member'];
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error fetching commands', error);
|
||||
|
@ -31,7 +31,35 @@ export class CommandsComponent implements OnInit {
|
|||
);
|
||||
}
|
||||
|
||||
selectCommand(command: any): void {
|
||||
this.selectedCommand = command; // Almacena el comando seleccionado
|
||||
openCommandDetailModal(command: any): void {
|
||||
this.dialog.open(CommandDetailComponent, {
|
||||
width: '800px',
|
||||
data: command
|
||||
});
|
||||
}
|
||||
|
||||
openCreateCommandModal(): void {
|
||||
const dialogRef = this.dialog.open(CreateCommandComponent, {
|
||||
width: '600px'
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.loadCommands();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
openEditCommandModal(command: any): void {
|
||||
const dialogRef = this.dialog.open(CreateCommandComponent, {
|
||||
width: '600px',
|
||||
data: { command } // Pasar el comando para editar
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.loadCommands();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/* Estilo general para el modal */
|
||||
.mat-dialog-container {
|
||||
padding: 24px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Título del modal */
|
||||
.mat-dialog-title {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
/* Contenedor del formulario */
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* Espaciado entre campos */
|
||||
mat-form-field {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
/* Estilos para los botones */
|
||||
button {
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
/* Botón de añadir (primario) */
|
||||
button[mat-flat-button] {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Botón de cancelar (secundario) */
|
||||
button[mat-button] {
|
||||
color: #666;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
background: #f5f5f5;
|
||||
padding: 8px 16px;
|
||||
}
|
||||
|
||||
/* Botón de añadir (primario) */
|
||||
button[mat-flat-button][color="primary"] {
|
||||
background-color: #3f51b5;
|
||||
color: #fff;
|
||||
border-radius: 4px;
|
||||
padding: 8px 16px;
|
||||
}
|
||||
|
||||
mat-checkbox {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<h2 mat-dialog-title>{{ isEditMode ? 'Editar Comando' : 'Añadir Comando' }}</h2>
|
||||
|
||||
<form [formGroup]="createCommandForm" (ngSubmit)="onSubmit()">
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Nombre</mat-label>
|
||||
<input matInput formControlName="name" placeholder="Nombre del comando" required>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Script</mat-label>
|
||||
<textarea matInput formControlName="script" placeholder="Script del comando" required></textarea>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-checkbox formControlName="readOnly">Solo lectura</mat-checkbox>
|
||||
<mat-checkbox formControlName="enabled">Habilitado</mat-checkbox>
|
||||
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Comentarios</mat-label>
|
||||
<textarea matInput formControlName="comments" placeholder="Comentarios"></textarea>
|
||||
</mat-form-field>
|
||||
|
||||
<div mat-dialog-actions>
|
||||
<button mat-button (click)="onCancel()">Cancelar</button>
|
||||
<button mat-flat-button color="primary" type="submit">{{ isEditMode ? 'Guardar' : 'Añadir' }}</button>
|
||||
</div>
|
||||
</form>
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CreateCommandComponent } from './create-command.component';
|
||||
|
||||
describe('CreateCommandComponent', () => {
|
||||
let component: CreateCommandComponent;
|
||||
let fixture: ComponentFixture<CreateCommandComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [CreateCommandComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(CreateCommandComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,63 @@
|
|||
import { Component, Inject } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
@Component({
|
||||
selector: 'app-create-command',
|
||||
templateUrl: './create-command.component.html',
|
||||
styleUrls: ['./create-command.component.css']
|
||||
})
|
||||
export class CreateCommandComponent {
|
||||
createCommandForm!: FormGroup;
|
||||
isEditMode: boolean;
|
||||
private apiUrl = 'http://127.0.0.1:8080/commands'; // URL para añadir o editar el comando
|
||||
|
||||
constructor(
|
||||
private fb: FormBuilder,
|
||||
private http: HttpClient,
|
||||
public dialogRef: MatDialogRef<CreateCommandComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any
|
||||
) {
|
||||
this.isEditMode = data && data.command; // Verifica si `data` y `data.command` existen
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.createCommandForm = this.fb.group({
|
||||
name: [this.isEditMode ? this.data.command.name : '', Validators.required],
|
||||
script: [this.isEditMode ? this.data.command.script : '', Validators.required],
|
||||
readOnly: [this.isEditMode ? this.data.command.readOnly : false],
|
||||
enabled: [this.isEditMode ? this.data.command.enabled : true],
|
||||
comments: [this.isEditMode ? this.data.command.comments : '']
|
||||
});
|
||||
}
|
||||
|
||||
onCancel(): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
onSubmit(): void {
|
||||
if (this.createCommandForm.valid) {
|
||||
const commandData = this.createCommandForm.value;
|
||||
if (this.isEditMode) {
|
||||
this.http.patch(`${this.apiUrl}/${this.data.command.uuid}`, commandData).subscribe(
|
||||
response => {
|
||||
this.dialogRef.close(true);
|
||||
},
|
||||
error => {
|
||||
console.error('Error editing command', error);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.http.post(this.apiUrl, commandData).subscribe(
|
||||
response => {
|
||||
this.dialogRef.close(true);
|
||||
},
|
||||
error => {
|
||||
console.error('Error adding command', error);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue