Refactor groups view and update styles
parent
21078a8ab0
commit
252f961b73
|
@ -133,22 +133,17 @@ mat-card-actions {
|
|||
.details-wrapper {
|
||||
width: 95%;
|
||||
padding: 20px;
|
||||
/* Asegúrate de que no haya propiedades que centren el contenido */
|
||||
display: block;
|
||||
}
|
||||
|
||||
.details-placeholder {
|
||||
width: 100%;
|
||||
/* Elimina max-width si existe */
|
||||
/* max-width: none; */
|
||||
/* Otros estilos existentes */
|
||||
}
|
||||
|
||||
button[mat-raised-button] {
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.card-container {
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
|
@ -195,9 +190,10 @@ mat-tree {
|
|||
padding: 10px;
|
||||
}
|
||||
|
||||
button{
|
||||
button {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
mat-tree mat-tree-node {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@ -247,29 +243,27 @@ mat-tree mat-tree-node:hover mat-icon {
|
|||
color: black;
|
||||
}
|
||||
|
||||
/* Iconos por tipo */
|
||||
mat-tree mat-tree-node mat-icon.node-icon {
|
||||
color: #757575;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
mat-tree mat-tree-node mat-icon.node-icon.organizational-unit {
|
||||
color: #1976d2; /* Azul para unidades organizativas */
|
||||
color: #1976d2;
|
||||
}
|
||||
|
||||
mat-tree mat-tree-node mat-icon.node-icon.classroom {
|
||||
color: #757575; /* Verde para aulas */
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
mat-tree mat-tree-node mat-icon.node-icon.client {
|
||||
color: #757575; /* Naranja para clientes */
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
mat-tree mat-tree-node mat-icon.node-icon.group {
|
||||
color: #757575; /* Rojo para grupos */
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
|
||||
mat-tree mat-tree-node button.mat-icon-button {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
@ -281,10 +275,9 @@ mat-tree mat-tree-node button.mat-icon-button.disabled-toggle {
|
|||
}
|
||||
|
||||
mat-tree mat-tree-node button.mat-icon-button.disabled-toggle:hover {
|
||||
background-color: transparent; /* Desactiva hover */
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
|
||||
mat-tree mat-tree-node:hover {
|
||||
background-color: #e3f2fd;
|
||||
cursor: pointer;
|
||||
|
@ -295,7 +288,13 @@ mat-tree mat-tree-node.disabled {
|
|||
}
|
||||
|
||||
mat-tree mat-tree-node.disabled:hover {
|
||||
background-color: transparent; /* Desactiva hover */
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.selected-node {
|
||||
background-color: #e0f7fa;
|
||||
border-left: 4px solid #3F51B5;
|
||||
padding-left: calc(16px - 4px);
|
||||
}
|
||||
|
||||
.mat-menu-item .mat-menu-item-submenu-icon {
|
||||
|
@ -313,38 +312,33 @@ mat-tree mat-tree-node.disabled:hover {
|
|||
flex: 1 1 100%;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.pc-og-live {
|
||||
/* Estilo para clientes con status 'og-live' */
|
||||
color: #4caf50; /* Verde */
|
||||
color: #4caf50;
|
||||
}
|
||||
|
||||
.pc-busy {
|
||||
/* Estilo para clientes ocupados */
|
||||
color: #ff9800; /* Naranja */
|
||||
color: #ff9800;
|
||||
}
|
||||
|
||||
.pc-windows {
|
||||
/* Estilo para clientes con Windows */
|
||||
color: #0078d7; /* Azul Windows */
|
||||
color: #0078d7;
|
||||
}
|
||||
|
||||
.pc-linux {
|
||||
/* Estilo para clientes con Linux */
|
||||
color: #f0ad4e; /* Amarillo */
|
||||
color: #f0ad4e;
|
||||
}
|
||||
|
||||
.pc-macos {
|
||||
/* Estilo para clientes con macOS */
|
||||
color: #999999; /* Gris */
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.pc-off {
|
||||
/* Estilo para clientes apagados */
|
||||
color: #f44336; /* Rojo */
|
||||
color: #f44336;
|
||||
}
|
||||
|
||||
.clients-card-container {
|
||||
|
@ -356,7 +350,7 @@ mat-tree mat-tree-node.disabled:hover {
|
|||
}
|
||||
|
||||
.classroom-item {
|
||||
flex: 1 1 calc(25% - 16px); /* Ajusta este valor para controlar cuántas tarjetas caben en una fila */
|
||||
flex: 1 1 calc(25% - 16px);
|
||||
max-width: calc(25% - 16px);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
@ -399,20 +393,19 @@ mat-tree mat-tree-node.disabled:hover {
|
|||
}
|
||||
|
||||
.tree-container {
|
||||
width: 25%; /* El árbol ocupa el 25% del ancho */
|
||||
width: 25%;
|
||||
padding: 16px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto; /* Scroll si hay muchos nodos */
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.clients-container {
|
||||
width: 75%; /* Los clientes ocupan el 75% del ancho */
|
||||
width: 75%;
|
||||
padding: 16px;
|
||||
box-sizing: border-box;
|
||||
overflow-y: auto; /* Scroll si hay muchos clientes */
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
|
||||
.clients-container h3 {
|
||||
margin-bottom: 15px;
|
||||
font-size: 1.5em;
|
||||
|
@ -450,7 +443,6 @@ mat-tree mat-tree-node.disabled:hover {
|
|||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
|
||||
.client-details {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
@ -463,7 +455,6 @@ mat-tree mat-tree-node.disabled:hover {
|
|||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
|
||||
.client-ip {
|
||||
display: block;
|
||||
font-size: 0.9em;
|
||||
|
@ -474,9 +465,6 @@ button[mat-raised-button] {
|
|||
margin-top: 15px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.clients-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
|
@ -503,43 +491,6 @@ button[mat-raised-button] {
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
.view-toggle-container {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.clients-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.clients-list .list-item-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.client-card, .list-item-content {
|
||||
border: 1px solid #ccc;
|
||||
padding: 1rem;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.client-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.client-image {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.view-toggle-container {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
|
@ -585,7 +536,7 @@ button[mat-raised-button] {
|
|||
}
|
||||
|
||||
.back-button {
|
||||
flex-shrink: 0; /* Asegura que el botón Back no se reduzca */
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.view-toggle-container {
|
||||
|
@ -596,13 +547,13 @@ button[mat-raised-button] {
|
|||
|
||||
.filters-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap; /* Permite que los elementos pasen a la siguiente línea si no caben */
|
||||
gap: 16px; /* Espaciado entre los elementos */
|
||||
margin: 16px 0; /* Separación con otros elementos */
|
||||
padding: 0 16px; /* Opcional, para añadir un poco de espacio interno */
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
margin: 16px 0;
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.filters-container mat-form-field {
|
||||
flex: 1 1 300px; /* Toma todo el ancho disponible hasta 300px por elemento */
|
||||
max-width: 300px; /* Limita el ancho máximo */
|
||||
flex: 1 1 300px;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
|
|
@ -1,390 +1,309 @@
|
|||
<!-- <mat-tab-group (selectedTabChange)="onTabChange($event)">
|
||||
<mat-tab label="{{ 'generalTabLabel' | translate }}"> -->
|
||||
<div class="header-container" joyrideStep="tabsStep" text="{{ 'tabsStepText' | translate }}">
|
||||
<button mat-icon-button color="primary" (click)="iniciarTour()">
|
||||
<mat-icon>help</mat-icon>
|
||||
</button>
|
||||
<h2 class="title" joyrideStep="groupsTitleStepText" text="{{ 'groupsTitleStepText' | translate }}">
|
||||
{{ 'adminGroupsTitle' | translate }}
|
||||
</h2>
|
||||
<div class="groups-button-row" joyrideStep="addStep" text="{{ 'groupsAddStepText' | translate }}">
|
||||
<button mat-flat-button color="primary" (click)="addOU($event)"
|
||||
matTooltip="{{ 'newOrganizationalUnitTooltip' | translate }}" matTooltipShowDelay="1000">
|
||||
{{ 'newOrganizationalUnitButton' | translate }}
|
||||
</button>
|
||||
<button mat-flat-button color="primary" (click)="addClient($event)" matTooltipShowDelay="1000">
|
||||
{{ 'newClientButton' | translate }}
|
||||
</button>
|
||||
<button mat-flat-button (click)="openBottomSheet()" joyrideStep="keyStep" text="{{ 'keyStepText' | translate }}"
|
||||
matTooltipShowDelay="1000">
|
||||
{{ 'legendButton' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- HEADER -->
|
||||
<div class="header-container" joyrideStep="tabsStep" text="{{ 'tabsStepText' | translate }}">
|
||||
<button mat-icon-button color="primary" (click)="iniciarTour()">
|
||||
<mat-icon>help</mat-icon>
|
||||
<mat-expansion-panel *ngIf="isTreeViewActive" class="filters-panel">
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>Filtros</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
<div class="filters-container">
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-select (selectionChange)="loadSelectedFilter($event.value)" placeholder="Cargar filtro">
|
||||
<mat-option *ngFor="let savedFilter of savedFilterNames" [value]="savedFilter">
|
||||
{{ savedFilter[0] }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Buscar en el árbol</mat-label>
|
||||
<input matInput (input)="onTreeFilterInput($event)" placeholder="Buscar nombre o tipo">
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Filtrar por tipo</mat-label>
|
||||
<mat-select [(value)]="selectedTreeFilter" (selectionChange)="filterTree(searchTerm, $event.value)">
|
||||
<mat-option [value]="">Todos</mat-option>
|
||||
<mat-option value="organizational-unit">Grupos de aulas</mat-option>
|
||||
<mat-option value="classroom">Aulas</mat-option>
|
||||
<mat-option value="group">Grupos de ordenadores</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Buscar cliente</mat-label>
|
||||
<input matInput (input)="onClientFilterInput($event)" placeholder="Buscar nombre, IP, estado o MAC">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
|
||||
<div *ngIf="!selectedUnidad; else detailsTemplate" class="card-container">
|
||||
<mat-card *ngFor="let unidad of organizationalUnits"
|
||||
[ngClass]="{'selected-item': unidad === selectedUnidad, 'clickable-item': true}"
|
||||
(click)="onSelectUnidad(unidad)" class="unidad-card small-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>
|
||||
<mat-icon>apartment</mat-icon> {{ unidad.name }}
|
||||
</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-actions>
|
||||
<div class="button-container">
|
||||
<button mat-raised-button color="primary" [matMenuTriggerFor]="menu" (click)="$event.stopPropagation()">
|
||||
<mat-icon>menu</mat-icon>
|
||||
{{ 'Menu' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
<mat-menu #menu="matMenu">
|
||||
<button mat-menu-item (click)="onEditClick($event, unidad.type, unidad.uuid)">
|
||||
<mat-icon matTooltip="{{ 'editUnitTooltip' | translate }}" matTooltipHideDelay="0">edit</mat-icon>
|
||||
<span>{{ 'editUnitMenu' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onShowDetailsClick($event, unidad)">
|
||||
<mat-icon matTooltip="{{ 'viewUnitTooltip' | translate }}" matTooltipHideDelay="0">visibility</mat-icon>
|
||||
<span>{{ 'viewUnitMenu' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="addOU($event, unidad)">
|
||||
<mat-icon matTooltip="{{ 'addInternalUnitTooltip' | translate }}" matTooltipHideDelay="0">add_home_work</mat-icon>
|
||||
<span>{{ 'addInternalUnitMenu' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="addClient($event, unidad)">
|
||||
<mat-icon matTooltip="{{ 'addClientTooltip' | translate }}" matTooltipHideDelay="0">devices</mat-icon>
|
||||
<span>{{ 'addClientMenu' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onTreeClick($event, unidad)">
|
||||
<mat-icon matTooltip="{{ 'viewTreeTooltip' | translate }}" matTooltipHideDelay="0">account_tree</mat-icon>
|
||||
<span>{{ 'viewTreeMenu' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onDeleteClick($event, unidad)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span>Delete</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
</div>
|
||||
|
||||
<ng-template #detailsTemplate>
|
||||
<div class="header-actions-container">
|
||||
<button mat-raised-button color="primary" (click)="clearSelection()" class="back-button">
|
||||
<mat-icon>arrow_back</mat-icon>
|
||||
{{ 'Back' | translate }}
|
||||
</button>
|
||||
<div class="view-toggle-container" *ngIf="selectedDetail">
|
||||
<button mat-button color="primary" (click)="toggleView('card')" [disabled]="currentView === 'card'">
|
||||
<mat-icon>grid_view</mat-icon> {{ 'Vista Tarjeta' | translate }}
|
||||
</button>
|
||||
<button mat-button color="primary" (click)="toggleView('list')" [disabled]="currentView === 'list'">
|
||||
<mat-icon>list</mat-icon> {{ 'Vista Lista' | translate }}
|
||||
</button>
|
||||
<h2 class="title" joyrideStep="groupsTitleStepText" text="{{ 'groupsTitleStepText' | translate }}">
|
||||
{{ 'adminGroupsTitle' | translate }}
|
||||
</h2>
|
||||
<div class="groups-button-row" joyrideStep="addStep" text="{{ 'groupsAddStepText' | translate }}">
|
||||
<button mat-flat-button color="primary" (click)="addOU($event)"
|
||||
matTooltip="{{ 'newOrganizationalUnitTooltip' | translate }}" matTooltipShowDelay="1000">
|
||||
{{ 'newOrganizationalUnitButton' | translate }}
|
||||
</button>
|
||||
<button mat-flat-button color="primary" (click)="addClient($event)" matTooltipShowDelay="1000">
|
||||
{{ 'newClientButton' | translate }}
|
||||
</button>
|
||||
<button mat-flat-button (click)="openBottomSheet()" joyrideStep="keyStep" text="{{ 'keyStepText' | translate }}"
|
||||
matTooltipShowDelay="1000">
|
||||
{{ 'legendButton' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- -->
|
||||
</div>
|
||||
<mat-expansion-panel *ngIf="isTreeViewActive" class="filters-panel">
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
Filtros
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<!-- Contenedor de filtros -->
|
||||
<div class="filters-container">
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-select (selectionChange)="loadSelectedFilter($event.value)" placeholder="Cargar filtro">
|
||||
<mat-option *ngFor="let savedFilter of savedFilterNames" [value]="savedFilter">
|
||||
{{ savedFilter[0] }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Buscar en el árbol</mat-label>
|
||||
<input matInput (input)="onTreeFilterInput($event)" placeholder="Buscar nombre o tipo">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Filtrar por tipo</mat-label>
|
||||
<mat-select [(value)]="selectedTreeFilter" (selectionChange)="filterTree(searchTerm, $event.value)">
|
||||
<mat-option [value]="">Todos</mat-option>
|
||||
<mat-option value="organizational-unit">Unidades Organizativas</mat-option>
|
||||
<mat-option value="classroom">Aulas</mat-option>
|
||||
<mat-option value="client">Clientes</mat-option>
|
||||
<mat-option value="group">Grupos</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Buscar cliente</mat-label>
|
||||
<input matInput (input)="onClientFilterInput($event)" placeholder="Buscar nombre, IP, estado o MAC">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
|
||||
|
||||
|
||||
<!-- LAS CARDS DE LAS FACULTADES -->
|
||||
|
||||
<div *ngIf="!selectedUnidad; else detailsTemplate" class="card-container">
|
||||
<mat-card *ngFor="let unidad of organizationalUnits"
|
||||
[ngClass]="{'selected-item': unidad === selectedUnidad, 'clickable-item': true}"
|
||||
(click)="onSelectUnidad(unidad)" class="unidad-card small-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>
|
||||
<mat-icon>apartment</mat-icon> {{ unidad.name }}
|
||||
</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-actions>
|
||||
<div class="button-container">
|
||||
<button mat-raised-button color="primary" [matMenuTriggerFor]="menu" (click)="$event.stopPropagation()">
|
||||
<mat-icon>menu</mat-icon>
|
||||
{{ 'Menu' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
<mat-menu #menu="matMenu">
|
||||
|
||||
<button mat-menu-item (click)="onEditClick($event, unidad.type, unidad.uuid)">
|
||||
<mat-icon matTooltip="{{ 'editUnitTooltip' | translate }}" matTooltipHideDelay="0">edit</mat-icon>
|
||||
<span>{{ 'editUnitMenu' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onShowDetailsClick($event, unidad)">
|
||||
<mat-icon matTooltip="{{ 'viewUnitTooltip' | translate }}" matTooltipHideDelay="0">visibility</mat-icon>
|
||||
<span>{{ 'viewUnitMenu' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="addOU($event, unidad)">
|
||||
<mat-icon matTooltip="{{ 'addInternalUnitTooltip' | translate }}"
|
||||
matTooltipHideDelay="0">add_home_work</mat-icon>
|
||||
<span>{{ 'addInternalUnitMenu' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="addClient($event, unidad)">
|
||||
<mat-icon matTooltip="{{ 'addClientTooltip' | translate }}" matTooltipHideDelay="0">devices</mat-icon>
|
||||
<span>{{ 'addClientMenu' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onTreeClick($event, unidad)">
|
||||
<mat-icon matTooltip="{{ 'viewTreeTooltip' | translate }}" matTooltipHideDelay="0">account_tree</mat-icon>
|
||||
<span>{{ 'viewTreeMenu' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onDeleteClick($event, unidad)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span>Delete</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
</div>
|
||||
|
||||
<!-- TEMPLATE QUE SALE DDESPUES DE LAS CARDs CON EL ARBOL Y PCS -->
|
||||
|
||||
<ng-template #detailsTemplate>
|
||||
<div class="header-actions-container">
|
||||
<!-- Botón de Back -->
|
||||
<button mat-raised-button color="primary" (click)="clearSelection()" class="back-button">
|
||||
<mat-icon>arrow_back</mat-icon>
|
||||
{{ 'Back' | translate }}
|
||||
</button>
|
||||
|
||||
<!-- Botones de alternancia -->
|
||||
<div class="view-toggle-container" *ngIf="selectedDetail">
|
||||
<button mat-button color="primary" (click)="toggleView('card')" [disabled]="currentView === 'card'">
|
||||
<mat-icon>grid_view</mat-icon> {{ 'Vista Tarjeta' | translate }}
|
||||
</div>
|
||||
<div class="main-container">
|
||||
<div class="tree-container">
|
||||
<h2>{{ selectedUnidad?.name }}</h2>
|
||||
<mat-tree [dataSource]="treeDataSource" [treeControl]="treeControl">
|
||||
<mat-tree-node [ngClass]="{'selected-node': node === selectedNode}" *matTreeNodeDef="let node; when: hasChild" matTreeNodePadding (click)="onNodeClick(node)">
|
||||
<button mat-icon-button matTreeNodeToggle [disabled]="!node.expandable" [ngClass]="{'disabled-toggle': !node.expandable}">
|
||||
<mat-icon>{{ treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right' }}</mat-icon>
|
||||
</button>
|
||||
<button mat-button color="primary" (click)="toggleView('list')" [disabled]="currentView === 'list'">
|
||||
<mat-icon>list</mat-icon> {{ 'Vista Lista' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="main-container">
|
||||
<!-- Contenedor del árbol -->
|
||||
|
||||
<div class="tree-container">
|
||||
|
||||
<h2>{{ selectedUnidad?.name }}</h2>
|
||||
<mat-tree [dataSource]="treeDataSource" [treeControl]="treeControl">
|
||||
<mat-tree-node *matTreeNodeDef="let node; when: hasChild" matTreeNodePadding (click)="onNodeClick(node)">
|
||||
<button mat-icon-button matTreeNodeToggle [disabled]="!node.expandable"
|
||||
[ngClass]="{'disabled-toggle': !node.expandable}">
|
||||
<mat-icon>
|
||||
{{ treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right' }}
|
||||
</mat-icon>
|
||||
</button>
|
||||
<mat-icon class="node-icon {{ node.type }}">
|
||||
{{
|
||||
node.type === 'organizational-unit' ? 'apartment'
|
||||
: node.type === 'classrooms-group' ? 'meeting_room'
|
||||
: node.type === 'classroom' ? 'school'
|
||||
: node.type === 'clients-group' ? 'lan'
|
||||
: node.type === 'client' ? 'computer'
|
||||
: 'group'
|
||||
}}
|
||||
</mat-icon>
|
||||
<span>{{ node.name }}</span>
|
||||
<button mat-icon-button [matMenuTriggerFor]="menu" (click)="setSelectedNode(node)">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
</mat-tree-node>
|
||||
|
||||
<mat-tree-node *matTreeNodeDef="let node; when: isLeafNode" matTreeNodePadding (click)="onNodeClick(node)">
|
||||
<button mat-icon-button matTreeNodeToggle [disabled]="true" class="disabled-toggle">
|
||||
|
||||
</button>
|
||||
<mat-icon [ngClass]="{
|
||||
'pc-og-live': node.type === 'client' && node.status === 'og-live',
|
||||
'pc-busy': node.type === 'client' && node.status === 'busy',
|
||||
'pc-windows': node.type === 'client' && (node.status === 'windows' || node.status === 'windows-session'),
|
||||
'pc-linux': node.type === 'client' && (node.status === 'linux' || node.status === 'linux-session'),
|
||||
'pc-macos': node.type === 'client' && node.status === 'macos',
|
||||
'pc-off': node.type === 'client' && node.status === 'off'
|
||||
}">
|
||||
{{
|
||||
node.type === 'organizational-unit' ? 'apartment'
|
||||
: node.type === 'classrooms-group' ? 'meeting_room'
|
||||
: node.type === 'classroom' ? 'school'
|
||||
: node.type === 'clients-group' ? 'lan'
|
||||
: node.type === 'client' ? 'computer'
|
||||
: 'group'
|
||||
<mat-icon class="node-icon {{ node.type }}">
|
||||
{{
|
||||
node.type === 'organizational-unit' ? 'apartment'
|
||||
: node.type === 'classrooms-group' ? 'meeting_room'
|
||||
: node.type === 'classroom' ? 'school'
|
||||
: node.type === 'clients-group' ? 'lan'
|
||||
: node.type === 'client' ? 'computer'
|
||||
: 'group'
|
||||
}}
|
||||
|
||||
</mat-icon>
|
||||
<span>{{ node.name }}</span>
|
||||
<ng-container *ngIf="node.type === 'client'">
|
||||
<span> - IP: {{ node.ip }}</span>
|
||||
</ng-container>
|
||||
<button mat-icon-button [matMenuTriggerFor]="menu" (click)="setSelectedNode(node)">
|
||||
</mat-icon>
|
||||
<span>{{ node.name }}</span>
|
||||
<button mat-icon-button [matMenuTriggerFor]="menu" (click)="setSelectedNode(node); $event.stopPropagation()">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
</mat-tree-node>
|
||||
<mat-tree-node [ngClass]="{'selected-node': node === selectedNode}" *matTreeNodeDef="let node; when: isLeafNode" matTreeNodePadding (click)="onNodeClick(node)">
|
||||
<button mat-icon-button matTreeNodeToggle [disabled]="true" class="disabled-toggle"></button>
|
||||
<mat-icon style="color: green;">
|
||||
{{
|
||||
node.type === 'organizational-unit' ? 'apartment'
|
||||
: node.type === 'classrooms-group' ? 'meeting_room'
|
||||
: node.type === 'classroom' ? 'school'
|
||||
: node.type === 'clients-group' ? 'lan'
|
||||
: node.type === 'client' ? 'computer'
|
||||
: 'group'
|
||||
}}
|
||||
</mat-icon>
|
||||
<span>{{ node.name }}</span>
|
||||
<ng-container *ngIf="node.type === 'client'">
|
||||
<span> - IP: {{ node.ip }}</span>
|
||||
</ng-container>
|
||||
<button mat-icon-button [matMenuTriggerFor]="menu" (click)="setSelectedNode(node)">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
</mat-tree-node>
|
||||
</mat-tree>
|
||||
</div>
|
||||
<mat-menu restoreFocus=false #commandMenu="matMenu">
|
||||
<button mat-menu-item *ngFor="let command of commands" (click)="executeCommand(command, selectedNode)">
|
||||
<span>{{ command.name }}</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
<mat-menu #menu="matMenu">
|
||||
<button *ngIf="selectedNode?.type === 'classroom'" mat-menu-item [matMenuTriggerFor]="commandMenu" (click)="fetchCommands()">
|
||||
<mat-icon>play_arrow</mat-icon>
|
||||
<span>Ejecutar Comando</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onShowDetailsClick($event, selectedNode)">
|
||||
<mat-icon matTooltip="{{ 'viewUnitTooltip' | translate }}" matTooltipHideDelay="0">visibility</mat-icon>
|
||||
<span>{{ 'viewUnitMenu' | translate }}</span>
|
||||
</button>
|
||||
<button *ngIf="selectedNode?.type === 'classroom'" mat-menu-item (click)="onRoomMap(selectedNode)">
|
||||
<mat-icon>map</mat-icon>
|
||||
<span>Plano aula</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="addClient($event, selectedNode)">
|
||||
<mat-icon>add</mat-icon>
|
||||
<span>Añadir clientes</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="addOU($event, selectedNode)">
|
||||
<mat-icon>playlist_add</mat-icon>
|
||||
<span>Añadir unidad organizativa</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onEditNode($event, selectedNode)">
|
||||
<mat-icon>edit</mat-icon>
|
||||
<span>Edit</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onDeleteClick($event, selectedNode)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span>Delete</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
<div class="clients-container" *ngIf="selectedClients.length > 0">
|
||||
<h3>Clientes {{ selectedNode?.name ? 'del ' + selectedNode?.name : '' }}</h3>
|
||||
<div class="clients-grid" *ngIf="currentView === 'card'">
|
||||
<div *ngFor="let client of selectedClients" class="client-item">
|
||||
<div class="client-card">
|
||||
<img src="assets/images/client.png" alt="Client Icon" class="client-image" />
|
||||
<div class="client-details">
|
||||
<span class="client-name">{{ client.name }}</span>
|
||||
<span class="client-ip">{{ client.ip }}</span>
|
||||
<mat-chip [ngClass]="{
|
||||
'chip-og-live': client.status === 'og-live',
|
||||
'chip-busy': client.status === 'busy',
|
||||
'chip-windows': client.status === 'windows' || client.status === 'windows-session',
|
||||
'chip-linux': client.status === 'linux' || client.status === 'linux-session',
|
||||
'chip-macos': client.status === 'macos',
|
||||
'chip-off': client.status === 'off'
|
||||
}">
|
||||
{{ client.status || 'off' }}
|
||||
</mat-chip>
|
||||
<button mat-raised-button color="primary" [matMenuTriggerFor]="clientMenu">Acciones</button>
|
||||
<mat-menu #clientMenu="matMenu">
|
||||
<button mat-menu-item (click)="onEditClick($event, client.type, client.uuid)">
|
||||
<mat-icon>edit</mat-icon>
|
||||
<span>Edit</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onShowClientDetail($event, client)">
|
||||
<mat-icon>visibility</mat-icon>
|
||||
<span>Ver detalles</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onDeleteClick($event, client, selectedNode)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span>Delete</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<mat-paginator [pageSize]="10" [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons></mat-paginator>
|
||||
</div>
|
||||
<div class="clients-table" *ngIf="currentView === 'list'">
|
||||
<table mat-table [dataSource]="selectedClients" class="mat-elevation-z8">
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef> Nombre </th>
|
||||
<td mat-cell *matCellDef="let client"> {{ client.name }} </td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="ip">
|
||||
<th mat-header-cell *matHeaderCellDef> IP </th>
|
||||
<td mat-cell *matCellDef="let client"> {{ client.ip }} </td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="mac">
|
||||
<th mat-header-cell *matHeaderCellDef> MAC </th>
|
||||
<td mat-cell *matCellDef="let client"> {{ client.mac }} </td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="oglive">
|
||||
<th mat-header-cell *matHeaderCellDef> OG Live </th>
|
||||
<td mat-cell *matCellDef="let client"> {{ client.oglive }} </td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="status">
|
||||
<th mat-header-cell *matHeaderCellDef> Estado </th>
|
||||
<td mat-cell *matCellDef="let client">
|
||||
<mat-chip [ngClass]="{
|
||||
'chip-og-live': client.status === 'og-live',
|
||||
'chip-busy': client.status === 'busy',
|
||||
'chip-windows': client.status === 'windows' || client.status === 'windows-session',
|
||||
'chip-linux': client.status === 'linux' || client.status === 'linux-session',
|
||||
'chip-macos': client.status === 'macos',
|
||||
'chip-off': client.status === 'off'
|
||||
}">
|
||||
{{ client.status || 'off' }}
|
||||
</mat-chip>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="mantenimiento">
|
||||
<th mat-header-cell *matHeaderCellDef> Mantenimiento </th>
|
||||
<td mat-cell *matCellDef="let client"> {{ client.mantenimiento }} </td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="subnet">
|
||||
<th mat-header-cell *matHeaderCellDef> Subred </th>
|
||||
<td mat-cell *matCellDef="let client"> {{ client.subnet }} </td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="pxeTemplate">
|
||||
<th mat-header-cell *matHeaderCellDef> Plantilla PXE </th>
|
||||
<td mat-cell *matCellDef="let client"> {{ client.pxeTemplate }} </td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef> Acciones </th>
|
||||
<td mat-cell *matCellDef="let client">
|
||||
<button mat-icon-button [matMenuTriggerFor]="clientMenu">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
</mat-tree-node>
|
||||
</mat-tree>
|
||||
</div>
|
||||
|
||||
<mat-menu restoreFocus=fasle #commandMenu="matMenu">
|
||||
<button mat-menu-item *ngFor="let command of commands" (click)="executeCommand(command, selectedNode)">
|
||||
<span>{{ command.name }}</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
<!-- Menú desplegable -->
|
||||
<mat-menu #menu="matMenu">
|
||||
|
||||
<button *ngIf="selectedNode?.type === 'classroom'" mat-menu-item [matMenuTriggerFor]="commandMenu"
|
||||
(click)="fetchCommands()">
|
||||
<mat-icon>play_arrow</mat-icon>
|
||||
<span>Ejecutar Comando</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onShowDetailsClick($event, selectedNode)">
|
||||
<mat-icon matTooltip="{{ 'viewUnitTooltip' | translate }}" matTooltipHideDelay="0">visibility</mat-icon>
|
||||
<span>{{ 'viewUnitMenu' | translate }}</span>
|
||||
</button>
|
||||
<button *ngIf="selectedNode?.type === 'classroom'" mat-menu-item (click)="onRoomMap(selectedNode)">
|
||||
<mat-icon>map</mat-icon>
|
||||
<span>Plano aula</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="addClient($event, selectedNode)">
|
||||
<mat-icon>add</mat-icon>
|
||||
<span>Añadir clientes</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onEditNode($event, selectedNode)">
|
||||
<mat-icon>edit</mat-icon>
|
||||
<span>Edit</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onDeleteClick($event, selectedNode)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span>Delete</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
|
||||
|
||||
|
||||
<!-- Contenedor de clientes -->
|
||||
<div class="clients-container" *ngIf="selectedClients.length > 0">
|
||||
<h3>Clientes del {{ selectedNode?.name }}</h3>
|
||||
|
||||
<!-- Vista Tarjeta -->
|
||||
<div class="clients-grid" *ngIf="currentView === 'card'">
|
||||
<div *ngFor="let client of selectedClients" class="client-item">
|
||||
<div class="client-card">
|
||||
<img src="assets/images/client.png" alt="Client Icon" class="client-image" />
|
||||
<div class="client-details">
|
||||
<span class="client-name">{{ client.name }}</span>
|
||||
<span class="client-ip">{{ client.ip }}</span>
|
||||
|
||||
<button mat-raised-button color="primary" [matMenuTriggerFor]="clientMenu">Acciones</button>
|
||||
<mat-menu #clientMenu="matMenu">
|
||||
<button mat-menu-item (click)="onEditClick($event, client.type, client.uuid)">
|
||||
<mat-icon>edit</mat-icon>
|
||||
<span>Edit</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onShowClientDetail($event, client)">
|
||||
<mat-icon>visibility</mat-icon>
|
||||
<span>Ver detalles</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onDeleteClick($event, client, selectedNode)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span>Delete</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Paginador -->
|
||||
<mat-paginator [pageSize]="10" [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons>
|
||||
</mat-paginator>
|
||||
</div>
|
||||
|
||||
<!-- Vista Tabla -->
|
||||
<div class="clients-table" *ngIf="currentView === 'list'">
|
||||
<table mat-table [dataSource]="selectedClients" class="mat-elevation-z8">
|
||||
|
||||
<!-- Columna: Nombre -->
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef> Nombre </th>
|
||||
<td mat-cell *matCellDef="let client"> {{ client.name }} </td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Columna: IP -->
|
||||
<ng-container matColumnDef="ip">
|
||||
<th mat-header-cell *matHeaderCellDef> IP </th>
|
||||
<td mat-cell *matCellDef="let client"> {{ client.ip }} </td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Columna: MAC -->
|
||||
<ng-container matColumnDef="mac">
|
||||
<th mat-header-cell *matHeaderCellDef> MAC </th>
|
||||
<td mat-cell *matCellDef="let client"> {{ client.mac }} </td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Columna: OG Live -->
|
||||
<ng-container matColumnDef="oglive">
|
||||
<th mat-header-cell *matHeaderCellDef> OG Live </th>
|
||||
<td mat-cell *matCellDef="let client"> {{ client.oglive }} </td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Columna: Estado -->
|
||||
<ng-container matColumnDef="status">
|
||||
<th mat-header-cell *matHeaderCellDef> Estado </th>
|
||||
<td mat-cell *matCellDef="let client">
|
||||
<mat-chip [ngClass]="{
|
||||
'chip-og-live': client.status === 'og-live',
|
||||
'chip-busy': client.status === 'busy',
|
||||
'chip-windows': client.status === 'windows' || client.status === 'windows-session',
|
||||
'chip-linux': client.status === 'linux' || client.status === 'linux-session',
|
||||
'chip-macos': client.status === 'macos',
|
||||
'chip-off': client.status === 'off'
|
||||
}">
|
||||
{{ client.status || 'off' }}
|
||||
</mat-chip>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Columna: Subred -->
|
||||
<ng-container matColumnDef="subnet">
|
||||
<th mat-header-cell *matHeaderCellDef> Subred </th>
|
||||
<td mat-cell *matCellDef="let client"> {{ client.subnet }} </td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Columna: Plantilla PXE -->
|
||||
<ng-container matColumnDef="pxeTemplate">
|
||||
<th mat-header-cell *matHeaderCellDef> Plantilla PXE </th>
|
||||
<td mat-cell *matCellDef="let client"> {{ client.pxeTemplate }} </td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Columna: Acciones -->
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef> Acciones </th>
|
||||
<td mat-cell *matCellDef="let client">
|
||||
<button mat-icon-button [matMenuTriggerFor]="clientMenu">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
<mat-menu #clientMenu="matMenu">
|
||||
<button mat-menu-item (click)="onEditClick($event, client.type, client.uuid)">
|
||||
<mat-icon>edit</mat-icon>
|
||||
<span>Edit</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onShowClientDetail($event, client)">
|
||||
<mat-icon>visibility</mat-icon>
|
||||
<span>Ver detalles</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onDeleteClick($event, client, selectedNode)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span>Delete</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Fila Encabezado -->
|
||||
<tr mat-header-row
|
||||
*matHeaderRowDef="['name', 'ip', 'mac', 'oglive', 'status', 'subnet', 'pxeTemplate', 'actions']"></tr>
|
||||
<!-- Filas de Datos -->
|
||||
<tr mat-row
|
||||
*matRowDef="let row; columns: ['name', 'ip', 'mac', 'oglive', 'status', 'subnet', 'pxeTemplate', 'actions'];">
|
||||
</tr>
|
||||
</table>
|
||||
<!-- Paginador -->
|
||||
<mat-paginator [pageSize]="10" [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons>
|
||||
</mat-paginator>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<mat-menu #clientMenu="matMenu">
|
||||
<button mat-menu-item (click)="onEditClick($event, client.type, client.uuid)">
|
||||
<mat-icon>edit</mat-icon>
|
||||
<span>Edit</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onShowClientDetail($event, client)">
|
||||
<mat-icon>visibility</mat-icon>
|
||||
<span>Ver detalles</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onDeleteClick($event, client, selectedNode)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span>Delete</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</td>
|
||||
</ng-container>
|
||||
<tr mat-header-row *matHeaderRowDef="['name', 'ip', 'mac', 'oglive', 'status', 'mantenimiento', 'subnet', 'pxeTemplate', 'actions']"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: ['name', 'ip', 'mac', 'oglive', 'status', 'mantenimiento', 'subnet', 'pxeTemplate', 'actions'];"></tr>
|
||||
</table>
|
||||
<mat-paginator [pageSize]="10" [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons></mat-paginator>
|
||||
</div>
|
||||
</ng-template>
|
||||
<!-- FIN DEL TAB -->
|
||||
<!-- </mat-tab>
|
||||
|
||||
<mat-tab label="{{ 'advancedSearchTabLabel' | translate }}">
|
||||
<app-advanced-search></app-advanced-search>
|
||||
</mat-tab>
|
||||
|
||||
<mat-tab label="{{ 'clientsTabLabel' | translate }}">
|
||||
<app-client-tab-view #clientTab></app-client-tab-view>
|
||||
</mat-tab>
|
||||
|
||||
<mat-tab label="{{ 'organizationalUnitsTabLabel' | translate }}">
|
||||
<app-organizational-unit-tab-view #organizationalUnitTab></app-organizational-unit-tab-view>
|
||||
</mat-tab>
|
||||
</mat-tab-group> -->
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
|
|
@ -4,12 +4,10 @@ import { Router } from '@angular/router';
|
|||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatBottomSheet } from '@angular/material/bottom-sheet';
|
||||
import { MatTabChangeEvent } from '@angular/material/tabs';
|
||||
import { MatMenuTrigger } from '@angular/material/menu';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { JoyrideService } from 'ngx-joyride';
|
||||
import { FlatTreeControl } from '@angular/cdk/tree';
|
||||
import { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree';
|
||||
|
||||
import { DataService } from './services/data.service';
|
||||
import { UnidadOrganizativa } from './model/model';
|
||||
import { CreateOrganizationalUnitComponent } from './shared/organizational-units/create-organizational-unit/create-organizational-unit.component';
|
||||
|
@ -25,6 +23,7 @@ import { DeleteModalComponent } from '../../shared/delete_modal/delete-modal/del
|
|||
import { ClassroomViewDialogComponent } from './shared/classroom-view/classroom-view-modal';
|
||||
|
||||
interface TreeNode {
|
||||
clients?: any[];
|
||||
name: string;
|
||||
type: string;
|
||||
children?: TreeNode[];
|
||||
|
@ -68,7 +67,7 @@ export class GroupsComponent implements OnInit {
|
|||
currentView: 'card' | 'list' = 'list';
|
||||
isTreeViewActive: boolean = false;
|
||||
savedFilterNames: any[] = [];
|
||||
|
||||
selectedTreeFilter: string = '';
|
||||
@ViewChild('clientTab') clientTabComponent!: ClientTabViewComponent;
|
||||
@ViewChild('organizationalUnitTab') organizationalUnitTabComponent!: OrganizationalUnitTabViewComponent;
|
||||
|
||||
|
@ -174,16 +173,32 @@ export class GroupsComponent implements OnInit {
|
|||
);
|
||||
}
|
||||
|
||||
onSelectUnidad(unidad: UnidadOrganizativa): void {
|
||||
onSelectUnidad(unidad: any): void {
|
||||
this.selectedUnidad = unidad;
|
||||
this.selectedDetail = unidad;
|
||||
|
||||
|
||||
this.selectedClients = this.collectAllClients(unidad);
|
||||
this.selectedClientsOriginal = [...this.selectedClients];
|
||||
|
||||
this.loadChildrenAndClients(unidad.id).then(fullData => {
|
||||
const treeData = this.convertToTreeData(fullData);
|
||||
this.treeDataSource.data = treeData[0]?.children || [];
|
||||
});
|
||||
|
||||
this.isTreeViewActive = true;
|
||||
}
|
||||
|
||||
|
||||
private collectAllClients(node: any): any[] {
|
||||
let clients = node.clients || [];
|
||||
if (node.children && node.children.length > 0) {
|
||||
node.children.forEach((child: any) => {
|
||||
clients = clients.concat(this.collectAllClients(child));
|
||||
});
|
||||
}
|
||||
return clients;
|
||||
}
|
||||
|
||||
|
||||
async loadChildrenAndClients(id: string): Promise<any> {
|
||||
try {
|
||||
|
@ -222,7 +237,8 @@ export class GroupsComponent implements OnInit {
|
|||
|
||||
onNodeClick(node: TreeNode): void {
|
||||
this.selectedNode = node;
|
||||
|
||||
this.selectedClients = node.clients || [];
|
||||
this.selectedClientsOriginal = [...this.selectedClients];
|
||||
if (node.hasClients) {
|
||||
const url = `${this.baseUrl}${node['@id']}`;
|
||||
this.http.get(url).subscribe(
|
||||
|
@ -259,6 +275,10 @@ export class GroupsComponent implements OnInit {
|
|||
this.dataService.getOrganizationalUnits().subscribe(
|
||||
data => {
|
||||
this.organizationalUnits = data;
|
||||
this.loadChildrenAndClients(this.selectedUnidad?.id || '').then(updatedData => {
|
||||
const treeData = this.convertToTreeData(updatedData);
|
||||
this.treeDataSource.data = treeData[0]?.children || [];
|
||||
});
|
||||
},
|
||||
error => console.error('Error fetching unidades organizativas', error)
|
||||
);
|
||||
|
@ -272,8 +292,13 @@ export class GroupsComponent implements OnInit {
|
|||
this.dataService.getOrganizationalUnits().subscribe(
|
||||
data => {
|
||||
this.organizationalUnits = data;
|
||||
this.loadChildrenAndClients(this.selectedUnidad?.id || '').then(updatedData => {
|
||||
const treeData = this.convertToTreeData(updatedData);
|
||||
this.treeDataSource.data = treeData[0]?.children || [];
|
||||
});
|
||||
if (organizationalUnit && organizationalUnit.id) {
|
||||
this.loadChildrenAndClients(organizationalUnit.id);
|
||||
this.refreshClients(organizationalUnit);
|
||||
}
|
||||
},
|
||||
error => console.error('Error fetching unidades organizativas', error)
|
||||
|
@ -393,7 +418,7 @@ export class GroupsComponent implements OnInit {
|
|||
}
|
||||
|
||||
onRoomMap(room: any): void {
|
||||
this.http.get('https://127.0.0.1:8443' + room['@id']).subscribe(
|
||||
this.http.get(`${this.baseUrl}`+ room['@id']).subscribe(
|
||||
(response: any) => {
|
||||
this.dialog.open(ClassroomViewDialogComponent, {
|
||||
width: '90vw',
|
||||
|
@ -408,7 +433,7 @@ export class GroupsComponent implements OnInit {
|
|||
|
||||
fetchCommands(): void {
|
||||
this.commandsLoading = true;
|
||||
this.http.get('https://127.0.0.1:8443/commands?page=1&itemsPerPage=30').subscribe(
|
||||
this.http.get(`${this.baseUrl}`+'/commands?page=1&itemsPerPage=30').subscribe(
|
||||
(response: any) => {
|
||||
this.commands = response['hydra:member'];
|
||||
this.commandsLoading = false;
|
||||
|
@ -465,8 +490,6 @@ export class GroupsComponent implements OnInit {
|
|||
hasChild = (_: number, node: FlatNode): boolean => node.expandable;
|
||||
isLeafNode = (_: number, node: FlatNode): boolean => !node.expandable;
|
||||
|
||||
/* filtros */
|
||||
selectedTreeFilter: string = '';
|
||||
filterTree(searchTerm: string, filterType: string): void {
|
||||
const filterNodes = (nodes: any[]): any[] => {
|
||||
return nodes
|
||||
|
@ -474,41 +497,36 @@ export class GroupsComponent implements OnInit {
|
|||
const matchesName = node.name.toLowerCase().includes(searchTerm.toLowerCase());
|
||||
const matchesType = filterType ? node.type.toLowerCase() === filterType.toLowerCase() : true;
|
||||
|
||||
// Filtrar hijos recursivamente
|
||||
const filteredChildren = node.children ? filterNodes(node.children) : [];
|
||||
|
||||
// Si el nodo o algún hijo coincide, incluirlo
|
||||
if (matchesName && matchesType || filteredChildren.length > 0) {
|
||||
return { ...node, children: filteredChildren };
|
||||
}
|
||||
return null; // Excluir nodos que no coinciden
|
||||
return null;
|
||||
})
|
||||
.filter(node => node !== null); // Eliminar nodos excluidos
|
||||
.filter(node => node !== null);
|
||||
};
|
||||
|
||||
// Aplicar filtro sobre el árbol completo
|
||||
const filteredData = filterNodes(this.treeDataSource.data);
|
||||
|
||||
// Actualizar el origen de datos del árbol
|
||||
this.treeDataSource.data = filteredData;
|
||||
}
|
||||
|
||||
onTreeFilterInput(event: Event): void {
|
||||
const input = event.target as HTMLInputElement;
|
||||
const searchTerm = input?.value || ''; // Maneja el caso de nulo o indefinido
|
||||
const searchTerm = input?.value || '';
|
||||
this.filterTree(searchTerm, this.selectedTreeFilter);
|
||||
}
|
||||
|
||||
onClientFilterInput(event: Event): void {
|
||||
const input = event.target as HTMLInputElement;
|
||||
const searchTerm = input?.value || ''; // Maneja valores nulos o indefinidos
|
||||
const searchTerm = input?.value || '';
|
||||
this.filterClients(searchTerm);
|
||||
}
|
||||
|
||||
|
||||
filterClients(searchTerm: string): void {
|
||||
if (!searchTerm) {
|
||||
// Restaurar los datos originales si no hay filtro
|
||||
this.selectedClients = [...this.selectedClientsOriginal];
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -31,18 +31,11 @@ mat-card {
|
|||
}
|
||||
|
||||
.client-info {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 5px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
color: black;
|
||||
text-align: center;
|
||||
padding: 15px;
|
||||
box-sizing: border-box;
|
||||
margin-top: 5px;
|
||||
font-size: medium;
|
||||
color: gray;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.client-name {
|
||||
|
|
|
@ -10,12 +10,9 @@
|
|||
<mat-card appearance="outlined">
|
||||
<div class="client-image-container">
|
||||
<img mat-card-image src="assets/images/client.png" alt="{{ 'clientAlt' | translate }}" class="client-image"/>
|
||||
<div class="client-info">
|
||||
<div class="client-name">{{ client.name }}</div>
|
||||
<div class="client-details">
|
||||
<span>{{ client.ip }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="client-info">
|
||||
<span>{{ client.name }}</span>
|
||||
</div>
|
||||
</mat-card>
|
||||
</div>
|
||||
|
|
|
@ -130,7 +130,7 @@
|
|||
<button mat-button (click)="toggleClientForm()">
|
||||
{{ isSingleClientForm ? 'Añadir múltiples clientes' : 'Añadir un único cliente' }}
|
||||
</button>
|
||||
<button mat-button (click)="onNoClick()">{{ 'cancelButton' | translate }}</button>
|
||||
<button mat-button (click)="onSubmit()">{{ 'addButton' | translate }}</button>
|
||||
<button mat-button color="warn" (click)="onNoClick()">{{ 'cancelButton' | translate }}</button>
|
||||
<button mat-button color="primary" (click)="onSubmit()">{{ 'addButton' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -19,4 +19,14 @@
|
|||
<mat-icon matListItemIcon>computer</mat-icon>
|
||||
<div matListItemTitle>{{ 'clientTitle' | translate }}</div>
|
||||
</mat-list-item>
|
||||
|
||||
<mat-list-item>
|
||||
<mat-icon matListItemIcon style="color: green;">school</mat-icon>
|
||||
<div matListItemTitle>Disponible acceso remoto</div>
|
||||
</mat-list-item>
|
||||
<mat-list-item>
|
||||
<mat-icon matListItemIcon style="color: rgb(209, 5, 5);">school</mat-icon>
|
||||
<div matListItemTitle>No disponible acceso remoto</div>
|
||||
</mat-list-item>
|
||||
|
||||
</mat-list>
|
||||
|
|
Loading…
Reference in New Issue