refs #1619. In Progress. Refactor: update layout dimensions and styles for groups component
testing/ogGui-multibranch/pipeline/head This commit looks good Details

deb-pkg
Lucas Lara García 2025-02-27 10:35:20 +01:00
parent 1ae55c3254
commit bae2069661
5 changed files with 384 additions and 406 deletions

View File

@ -1,3 +1,10 @@
.groups-container {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
}
.header-container {
display: flex;
justify-content: space-between;
@ -6,6 +13,13 @@
border-bottom: 1px solid #ddd;
}
.main-container {
display: flex;
flex-direction: row;
width: 100%;
height: 100%;
}
.header-container-title {
flex-grow: 1;
text-align: left;
@ -15,6 +29,7 @@
.groups-button-row {
display: flex;
gap: 15px;
padding-right: 0.5rem;
}
.button-container {
@ -23,6 +38,23 @@
margin: 20px 0;
}
.clients-container {
flex-grow: 1;
box-sizing: border-box;
overflow-y: auto;
}
.clients-view-header {
display: flex;
flex-direction: row;
justify-content: space-between;
margin-bottom: 0.5rem;
margin-top: 0.5rem;
align-items: center;
padding-right: 1rem;
flex-grow: 1;
}
.actions mat-icon {
color: #757575;
cursor: pointer;
@ -59,25 +91,6 @@
border-radius: 8px;
}
.details-container {
display: flex;
flex-direction: column;
gap: 20px;
padding: 20px;
align-items: center;
text-align: center;
}
.details-wrapper {
width: 95%;
padding: 20px;
display: block;
}
.details-placeholder {
width: 100%;
}
@media (max-width: 1024px) {
.card-container {
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
@ -105,19 +118,6 @@
}
}
.details-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
padding: 30px;
background-color: #f9f9f9;
border-radius: 12px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
max-width: 1200px;
margin: 20px auto;
}
mat-tree {
background-color: #f9f9f9;
padding: 0px 10px 10px 10px;
@ -232,14 +232,9 @@ mat-tree mat-tree-node.disabled:hover {
.filters-container {
display: flex;
flex-direction: column;
justify-content: start;
gap: 1rem;
margin: 2rem 0px 0.7rem 10px;
}
.filters-container mat-form-field {
flex: 1 1 100%;
max-width: 250px;
padding: 1em;
}
.chip-busy {
@ -270,7 +265,6 @@ mat-tree mat-tree-node.disabled:hover {
color: white;
}
.clients-card-container {
display: flex;
flex-wrap: wrap;
@ -317,13 +311,7 @@ mat-tree mat-tree-node.disabled:hover {
margin: 0 4px;
}
.main-container {
display: flex;
flex-direction: row;
}
.tree-container {
width: 25%;
overflow-x: hidden;
overflow-y: auto;
}
@ -353,8 +341,8 @@ mat-tree mat-tree-node.disabled:hover {
}
.client-image {
max-width: 30px !important;
max-height: 30px !important;
max-width: 35px !important;
max-height: 35px !important;
height: auto;
}
@ -464,15 +452,6 @@ mat-tree mat-tree-node.disabled:hover {
margin-top: 4px;
}
.clients-view-header {
display: flex;
flex-direction: row;
justify-content: space-between;
margin-bottom: 1rem;
align-items: center;
padding-right: 1rem;
}
@media (max-width: 1560px) {
.clients-view-header {
display: flex;
@ -548,12 +527,6 @@ mat-button-toggle-group {
background-color: #c7c7c7;
}
.clients-container {
width: 75%;
box-sizing: border-box;
overflow-y: auto;
}
.cards-view {
display: flex;
width: 100%;

View File

@ -1,358 +1,372 @@
<!-- Header -->
<div class="header-container" joyrideStep="tabsStep" text="{{ 'tabsStepText' | translate }}">
<button mat-icon-button color="primary" (click)="iniciarTour()">
<mat-icon>help</mat-icon>
</button>
<div class="header-container-title">
<h2 joyrideStep="groupsTitleStepText" text="{{ 'groupsTitleStepText' | translate }}">
{{ 'adminGroupsTitle' | translate }}
</h2>
</div>
<div class="groups-button-row" joyrideStep="addStep" text="{{ 'groupsAddStepText' | translate }}">
<button class="action-button" (click)="addOU($event)" matTooltip="{{ 'newOrganizationalUnitTooltip' | translate }}"
matTooltipShowDelay="1000">
{{ 'newOrganizationalUnitButton' | translate }}
<div class="groups-container">
<!-- HEADER -->
<div class="header-container" joyrideStep="tabsStep" text="{{ 'tabsStepText' | translate }}">
<button mat-icon-button color="primary" (click)="iniciarTour()">
<mat-icon>help</mat-icon>
</button>
<button class="action-button" [matMenuTriggerFor]="menuClients">{{ 'newClientButton' | translate }}</button>
<mat-menu #menuClients="matMenu">
<button mat-menu-item (click)="addClient($event)">{{ 'newSingleClientButton' | translate }}</button>
<button mat-menu-item (click)="addMultipleClients($event)">{{ 'newMultipleClientButton' | translate }}</button>
</mat-menu>
<div class="header-container-title">
<h2 joyrideStep="groupsTitleStepText" text="{{ 'groupsTitleStepText' | translate }}">
{{ 'adminGroupsTitle' | translate }}
</h2>
</div>
<div class="groups-button-row" joyrideStep="addStep" text="{{ 'groupsAddStepText' | translate }}">
<button class="action-button" (click)="addOU($event)"
matTooltip="{{ 'newOrganizationalUnitTooltip' | translate }}" matTooltipShowDelay="1000">
{{ 'newOrganizationalUnitButton' | translate }}
</button>
<button class="action-button" [matMenuTriggerFor]="menuClients">{{ 'newClientButton' | translate }}</button>
<mat-menu #menuClients="matMenu">
<button mat-menu-item (click)="addClient($event)">{{ 'newSingleClientButton' | translate }}</button>
<button mat-menu-item (click)="addMultipleClients($event)">{{ 'newMultipleClientButton' | translate }}</button>
</mat-menu>
<button class="ordinary-button" (click)="openBottomSheet()" joyrideStep="keyStep"
text="{{ 'keyStepText' | translate }}" matTooltipShowDelay="1000">
{{ 'legendButton' | translate }}
</button>
</div>
</div>
<div *ngIf="initialLoading; else contentTemplate">
<app-loading [isLoading]="initialLoading"></app-loading>
</div>
<ng-template #contentTemplate>
<!-- Filters Panel -->
<div class="filters-panel" joyrideStep="filtersPanelStep" text="{{ 'filtersPanelStepText' | translate }}">
<div class="filters-container">
<mat-form-field appearance="outline">
<mat-label>{{ 'searchTree' | translate }}</mat-label>
<input matInput #treeSearchInput (input)="onTreeFilterInput($event)" placeholder="Centro, aula, grupos ..." />
<button *ngIf="treeSearchInput.value" mat-icon-button matSuffix aria-label="Clear tree search"
(click)="clearTreeSearch(treeSearchInput)">
<mat-icon>close</mat-icon>
</button>
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>{{ 'searchClient' | translate }}</mat-label>
<input matInput #clientSearchInput (input)="onClientFilterInput($event)"
placeholder="Nombre, IP, estado o MAC" />
<button *ngIf="clientSearchInput.value" mat-icon-button matSuffix aria-label="Clear client search"
(click)="clearClientSearch(clientSearchInput)">
<mat-icon>close</mat-icon>
</button>
</mat-form-field>
<!-- Funcionalidad actualmente deshabilitada-->
<!-- <mat-form-field appearance="outline">
<mat-select (selectionChange)="loadSelectedFilter($event.value)" placeholder="Cargar filtro" disabled>
<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>{{ 'filterByType' | translate }}</mat-label>
<mat-select [(value)]="selectedTreeFilter" (selectionChange)="filterTree(searchTerm, $event.value)" disabled>
<mat-option [value]=""> {{ 'all' | translate }} </mat-option>
<mat-option value="classrooms-group">{{ 'classroomsGroup' | translate }}</mat-option>
<mat-option value="classroom">{{ 'classrooms' | translate }}</mat-option>
<mat-option value="group">{{ 'computerGroups' | translate }}</mat-option>
</mat-select>
</mat-form-field> -->
<button class="ordinary-button" (click)="openBottomSheet()" joyrideStep="keyStep"
text="{{ 'keyStepText' | translate }}" matTooltipShowDelay="1000">
{{ 'legendButton' | translate }}
</button>
</div>
</div>
<!-- Unit details view-->
<div class="main-container">
<!-- Tree view -->
<div class="tree-container">
<mat-tree [dataSource]="treeDataSource" [treeControl]="treeControl">
<mat-tree-node [ngClass]="{'selected-node': selectedNode?.id === node.id}"
*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]="menuNode" (click)="onNodeClick(node)">
<mat-icon>more_vert</mat-icon>
</button>
</mat-tree-node>
<mat-tree-node [ngClass]="{'selected-node': selectedNode?.id === node.id}"
*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]="menuNode" (click)="onNodeClick(node)">
<mat-icon>more_vert</mat-icon>
</button>
</mat-tree-node>
</mat-tree>
</div>
<div *ngIf="initialLoading; else contentTemplate">
<app-loading [isLoading]="initialLoading"></app-loading>
</div>
<mat-divider [vertical]="true"></mat-divider>
<!-- MAIN VIEW -->
<ng-template #contentTemplate>
<div class="main-container">
<!-- Tree node actions -->
<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 #menuNode="matMenu">
<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>{{ 'roomMap' | translate }}</span>
</button>
<button mat-menu-item (click)="addClient($event, selectedNode)">
<mat-icon>add</mat-icon>
<span>{{ 'newSingleClientButton' | translate }}</span>
</button>
<button mat-menu-item (click)="addMultipleClients($event, selectedNode)">
<mat-icon>playlist_add</mat-icon>
<span>{{ 'newMultipleClientButton' | translate }}</span>
</button>
<button mat-menu-item (click)="addOU($event, selectedNode)">
<mat-icon>account_tree</mat-icon>
<span>{{ 'addOrganizationalUnit' | translate }}</span>
</button>
<button mat-menu-item (click)="onEditNode($event, selectedNode)">
<mat-icon>edit</mat-icon>
<span>{{ 'edit' | translate }}</span>
</button>
<button mat-menu-item (click)="onDeleteClick($event, selectedNode)">
<mat-icon>delete</mat-icon>
<span>{{ 'delete' | translate }}</span>
</button>
</mat-menu>
<!-- FILTERS AND TREE VIEW -->
<div class="filters-and-tree-container">
<!-- Clients view -->
<div class="clients-container">
<div class="clients-view-header">
<div>
<span [ngStyle]="{ visibility: isLoadingClients ? 'hidden' : 'visible' }" class="clients-title-name">
{{ 'clients' | translate }}
<strong>{{ selectedNode?.name }}</strong>
</span>
<!-- Filters -->
<div class="filters-panel" joyrideStep="filtersPanelStep" text="{{ 'filtersPanelStepText' | translate }}">
<div class="filters-container">
<mat-form-field appearance="outline">
<mat-label>{{ 'searchTree' | translate }}</mat-label>
<input matInput #treeSearchInput (input)="onTreeFilterInput($event)"
placeholder="Centro, aula, grupos ..." />
<button *ngIf="treeSearchInput.value" mat-icon-button matSuffix aria-label="Clear tree search"
(click)="clearTreeSearch(treeSearchInput)">
<mat-icon>close</mat-icon>
</button>
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>{{ 'searchClient' | translate }}</mat-label>
<input matInput #clientSearchInput (input)="onClientFilterInput($event)"
placeholder="Nombre, IP, estado o MAC" />
<button *ngIf="clientSearchInput.value" mat-icon-button matSuffix aria-label="Clear client search"
(click)="clearClientSearch(clientSearchInput)">
<mat-icon>close</mat-icon>
</button>
</mat-form-field>
<!-- Funcionalidad actualmente deshabilitada-->
<!-- <mat-form-field appearance="outline">
<mat-select (selectionChange)="loadSelectedFilter($event.value)" placeholder="Cargar filtro" disabled>
<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>{{ 'filterByType' | translate }}</mat-label>
<mat-select [(value)]="selectedTreeFilter" (selectionChange)="filterTree(searchTerm, $event.value)" disabled>
<mat-option [value]=""> {{ 'all' | translate }} </mat-option>
<mat-option value="classrooms-group">{{ 'classroomsGroup' | translate }}</mat-option>
<mat-option value="classroom">{{ 'classrooms' | translate }}</mat-option>
<mat-option value="group">{{ 'computerGroups' | translate }}</mat-option>
</mat-select>
</mat-form-field> -->
</div>
</div>
<div class="view-type-container">
<app-execute-command [clientData]="selection.selected" [buttonType]="'text'"
[buttonText]="'Ejecutar comandos'" [disabled]="selection.selected.length === 0"></app-execute-command>
<mat-button-toggle-group name="viewType" aria-label="View Type" [hideSingleSelectionIndicator]="true"
(change)="toggleView($event.value)">
<mat-button-toggle value="list" [disabled]="currentView === 'list'">
<mat-icon>list</mat-icon> {{ 'Vista Lista' | translate }}
</mat-button-toggle>
<mat-button-toggle value="card" [disabled]="currentView === 'card'">
<mat-icon>grid_view</mat-icon> {{ 'Vista Tarjeta' | translate }}
</mat-button-toggle>
</mat-button-toggle-group>
<!-- Tree -->
<div class="tree-container">
<mat-tree [dataSource]="treeDataSource" [treeControl]="treeControl">
<mat-tree-node [ngClass]="{'selected-node': selectedNode?.id === node.id}"
*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]="menuNode" (click)="onNodeClick(node)">
<mat-icon>more_vert</mat-icon>
</button>
</mat-tree-node>
<mat-tree-node [ngClass]="{'selected-node': selectedNode?.id === node.id}"
*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]="menuNode" (click)="onNodeClick(node)">
<mat-icon>more_vert</mat-icon>
</button>
</mat-tree-node>
</mat-tree>
</div>
<!-- Tree node actions -->
<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 #menuNode="matMenu">
<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>{{ 'roomMap' | translate }}</span>
</button>
<button mat-menu-item (click)="addClient($event, selectedNode)">
<mat-icon>add</mat-icon>
<span>{{ 'newSingleClientButton' | translate }}</span>
</button>
<button mat-menu-item (click)="addMultipleClients($event, selectedNode)">
<mat-icon>playlist_add</mat-icon>
<span>{{ 'newMultipleClientButton' | translate }}</span>
</button>
<button mat-menu-item (click)="addOU($event, selectedNode)">
<mat-icon>account_tree</mat-icon>
<span>{{ 'addOrganizationalUnit' | translate }}</span>
</button>
<button mat-menu-item (click)="onEditNode($event, selectedNode)">
<mat-icon>edit</mat-icon>
<span>{{ 'edit' | translate }}</span>
</button>
<button mat-menu-item (click)="onDeleteClick($event, selectedNode)">
<mat-icon>delete</mat-icon>
<span>{{ 'delete' | translate }}</span>
</button>
</mat-menu>
</div>
<app-loading [isLoading]="isLoadingClients"></app-loading>
<mat-divider [vertical]="true"></mat-divider>
<div *ngIf="!isLoadingClients">
<div *ngIf="hasClients; else noClientsTemplate">
<!-- Cards view -->
<div *ngIf="currentView === 'card'" class="cards-view">
<mat-checkbox (change)="toggleAllCards()" [checked]="selection.hasValue() && isAllSelected()"
[indeterminate]="selection.hasValue() && !isAllSelected()" style="margin-left: 1em; margin-top: 0.5rem;">
</mat-checkbox>
<div class="clients-grid">
<div *ngFor="let client of arrayClients" class="client-item">
<div class="client-card">
<mat-checkbox (click)="$event.stopPropagation()" (change)="toggleRow(client)"
[checked]="selection.isSelected(client)" [disabled]="client.status === 'busy'">
</mat-checkbox>
<img [src]="'assets/images/ordenador_' + client.status + '.png'" alt="Client Icon"
class="client-image" />
<!-- CLIENTS -->
<div class="clients-container">
<div class="client-details">
<span class="client-name">{{ client.name }}</span>
<span class="client-ip">{{ client.ip }}</span>
<span class="client-ip">{{ client.mac }}</span>
<div class="action-icons">
<button *ngIf="(!syncStatus || syncingClientId !== client.uuid)" mat-icon-button color="primary"
(click)="getStatus(client, selectedNode)">
<mat-icon>sync</mat-icon>
</button>
<!-- CLIENTS HEADER -->
<div class="clients-view-header">
<div>
<span [ngStyle]="{ visibility: isLoadingClients ? 'hidden' : 'visible' }" class="clients-title-name">
{{ 'clients' | translate }}
<strong>{{ selectedNode?.name }}</strong>
</span>
</div>
<div class="view-type-container">
<app-execute-command [clientData]="selection.selected" [buttonType]="'text'"
[buttonText]="'Ejecutar comandos'" [disabled]="selection.selected.length === 0"></app-execute-command>
<mat-button-toggle-group name="viewType" aria-label="View Type" [hideSingleSelectionIndicator]="true"
(change)="toggleView($event.value)">
<mat-button-toggle value="list" [disabled]="currentView === 'list'">
<mat-icon>list</mat-icon> {{ 'Vista Lista' | translate }}
</mat-button-toggle>
<mat-button-toggle value="card" [disabled]="currentView === 'card'">
<mat-icon>grid_view</mat-icon> {{ 'Vista Tarjeta' | translate }}
</mat-button-toggle>
</mat-button-toggle-group>
</div>
</div>
<button *ngIf="syncStatus && syncingClientId === client.uuid" mat-icon-button color="primary">
<mat-spinner diameter="24"></mat-spinner>
</button>
<app-loading [isLoading]="isLoadingClients"></app-loading>
<app-execute-command [clientData]="[client]" [buttonType]="'icon'" [icon]="'terminal'"
[disabled]="selection.selected.length > 1 || (selection.selected.length === 1 && !selection.isSelected(client))"></app-execute-command>
<!-- CLIENTS VIEWS-->
<div *ngIf="!isLoadingClients">
<div *ngIf="hasClients; else noClientsTemplate">
<!-- Cards view -->
<div *ngIf="currentView === 'card'" class="cards-view">
<mat-checkbox (change)="toggleAllCards()" [checked]="selection.hasValue() && isAllSelected()"
[indeterminate]="selection.hasValue() && !isAllSelected()"
style="margin-left: 1em; margin-top: 0.5rem;">
</mat-checkbox>
<div class="clients-grid">
<div *ngFor="let client of arrayClients" class="client-item">
<div class="client-card">
<mat-checkbox (click)="$event.stopPropagation()" (change)="toggleRow(client)"
[checked]="selection.isSelected(client)" [disabled]="client.status === 'busy'">
</mat-checkbox>
<img [src]="'assets/images/ordenador_' + client.status + '.png'" alt="Client Icon"
class="client-image" />
<button
[disabled]="selection.selected.length > 1 || (selection.selected.length === 1 && !selection.isSelected(client))"
mat-icon-button [matMenuTriggerFor]="clientMenu" color="primary">
<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' | translate }}</span>
<div class="client-details">
<span class="client-name">{{ client.name }}</span>
<span class="client-ip">{{ client.ip }}</span>
<span class="client-ip">{{ client.mac }}</span>
<div class="action-icons">
<button *ngIf="(!syncStatus || syncingClientId !== client.uuid)" mat-icon-button color="primary"
(click)="getStatus(client, selectedNode)">
<mat-icon>sync</mat-icon>
</button>
<button mat-menu-item (click)="onShowClientDetail($event, client)">
<mat-icon>visibility</mat-icon>
<span>{{ 'viewDetails' | translate }}</span>
<button *ngIf="syncStatus && syncingClientId === client.uuid" mat-icon-button color="primary">
<mat-spinner diameter="24"></mat-spinner>
</button>
<button mat-menu-item (click)="onDeleteClick($event, client)">
<mat-icon>delete</mat-icon>
<span>{{ 'delete' | translate }}</span>
<app-execute-command [clientData]="[client]" [buttonType]="'icon'" [icon]="'terminal'"
[disabled]="selection.selected.length > 1 || (selection.selected.length === 1 && !selection.isSelected(client))"></app-execute-command>
<button
[disabled]="selection.selected.length > 1 || (selection.selected.length === 1 && !selection.isSelected(client))"
mat-icon-button [matMenuTriggerFor]="clientMenu" color="primary">
<mat-icon>more_vert</mat-icon>
</button>
</mat-menu>
<mat-menu #clientMenu="matMenu">
<button mat-menu-item (click)="onEditClick($event, client.type, client.uuid)">
<mat-icon>edit</mat-icon>
<span>{{ 'edit' | translate }}</span>
</button>
<button mat-menu-item (click)="onShowClientDetail($event, client)">
<mat-icon>visibility</mat-icon>
<span>{{ 'viewDetails' | translate }}</span>
</button>
<button mat-menu-item (click)="onDeleteClick($event, client)">
<mat-icon>delete</mat-icon>
<span>{{ 'delete' | translate }}</span>
</button>
</mat-menu>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- List view -->
<div class="clients-table" *ngIf="currentView === 'list'">
<table mat-table matSort [dataSource]="selectedClients" class="mat-elevation-z8">
<ng-container matColumnDef="select">
<th mat-header-cell *matHeaderCellDef>
<mat-checkbox (change)="$event ? toggleAllRows() : null"
[checked]="selection.hasValue() && isAllSelected()"
[indeterminate]="selection.hasValue() && !isAllSelected()">
</mat-checkbox>
</th>
<td mat-cell *matCellDef="let row">
<mat-checkbox (click)="$event.stopPropagation()" (change)="toggleRow(row)"
[checked]="selection.isSelected(row)" [disabled]="row.status === 'busy'">
</mat-checkbox>
</td>
</ng-container>
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'status' | translate }} </th>
<td mat-cell *matCellDef="let client" matTooltip="{{ getClientPath(client) }}"
matTooltipPosition="left" matTooltipShowDelay="500">
<img [src]="'assets/images/ordenador_' + client.status + '.png'" alt="Client Icon"
class="client-image" />
</td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'name' | translate }} </th>
<td mat-cell *matCellDef="let client" matTooltip="{{ getClientPath(client) }}"
matTooltipPosition="left" matTooltipShowDelay="500">
{{ client.name }}
</td>
</ng-container>
<ng-container matColumnDef="ip">
<th mat-header-cell *matHeaderCellDef mat-sort-header>IP </th>
<td mat-cell *matCellDef="let client" matTooltip="{{ getClientPath(client) }}"
matTooltipPosition="left" matTooltipShowDelay="500">
{{ client.ip }}
</td>
</ng-container>
<ng-container matColumnDef="oglive">
<th mat-header-cell *matHeaderCellDef mat-sort-header> OG Live </th>
<td mat-cell *matCellDef="let client"> {{ client.ogLive?.date | date }} </td>
</ng-container>
<ng-container matColumnDef="maintenace">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'maintenance' | translate }} </th>
<td mat-cell *matCellDef="let client"> {{ client.maintenance }} </td>
</ng-container>
<ng-container matColumnDef="subnet">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'subnet' | translate }} </th>
<td mat-cell *matCellDef="let client"> {{ client.subnet }} </td>
</ng-container>
<ng-container matColumnDef="pxeTemplate">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'pxeTemplate' | translate }} </th>
<td mat-cell *matCellDef="let client"> {{ client.template?.name }} </td>
</ng-container>
<ng-container matColumnDef="parentName">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'parent' | translate }} </th>
<td mat-cell *matCellDef="let client"> {{ client.parentName }} </td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'actions' | translate }} </th>
<td mat-cell *matCellDef="let client">
<button
[disabled]="selection.selected.length > 1 || (selection.selected.length === 1 && !selection.isSelected(client))"
mat-icon-button [matMenuTriggerFor]="clientMenu" color="primary">
<mat-icon>more_vert</mat-icon>
</button>
<app-execute-command [clientData]="[client]" [buttonType]="'icon'" [icon]="'terminal'"
[disabled]="selection.selected.length > 1 || (selection.selected.length === 1 && !selection.isSelected(client))"></app-execute-command>
<mat-menu #clientMenu="matMenu">
<button mat-menu-item (click)="onEditClick($event, client.type, client.uuid)">
<mat-icon>edit</mat-icon>
<span>{{ 'edit' | translate }}</span>
</button>
<button mat-menu-item (click)="onShowClientDetail($event, client)">
<mat-icon>visibility</mat-icon>
<span>{{ 'viewDetails' | translate }}</span>
</button>
<button mat-menu-item (click)="getStatus(client, selectedNode)">
<mat-icon>sync</mat-icon>
<span>{{ 'sync' | translate }}</span>
</button>
<button mat-menu-item (click)="onDeleteClick($event, client)">
<mat-icon>delete</mat-icon>
<span>{{ 'delete' | translate }}</span>
</button>
</mat-menu>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSize]="10" [pageSizeOptions]="[5, 10, 20, 50]" showFirstLastButtons></mat-paginator>
</div>
</div>
<!-- List view -->
<div class="clients-table" *ngIf="currentView === 'list'">
<table mat-table matSort [dataSource]="selectedClients" class="mat-elevation-z8">
<ng-container matColumnDef="select">
<th mat-header-cell *matHeaderCellDef>
<mat-checkbox (change)="$event ? toggleAllRows() : null"
[checked]="selection.hasValue() && isAllSelected()"
[indeterminate]="selection.hasValue() && !isAllSelected()">
</mat-checkbox>
</th>
<td mat-cell *matCellDef="let row">
<mat-checkbox (click)="$event.stopPropagation()" (change)="toggleRow(row)"
[checked]="selection.isSelected(row)" [disabled]="row.status === 'busy'">
</mat-checkbox>
</td>
</ng-container>
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'status' | translate }} </th>
<td mat-cell *matCellDef="let client" matTooltip="{{ getClientPath(client) }}" matTooltipPosition="left"
matTooltipShowDelay="500">
<img [src]="'assets/images/ordenador_' + client.status + '.png'" alt="Client Icon"
class="client-image" />
</td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'name' | translate }} </th>
<td mat-cell *matCellDef="let client" matTooltip="{{ getClientPath(client) }}" matTooltipPosition="left"
matTooltipShowDelay="500">
{{ client.name }}
</td>
</ng-container>
<ng-container matColumnDef="ip">
<th mat-header-cell *matHeaderCellDef mat-sort-header>IP </th>
<td mat-cell *matCellDef="let client" matTooltip="{{ getClientPath(client) }}" matTooltipPosition="left"
matTooltipShowDelay="500">
{{ client.ip }}
</td>
</ng-container>
<ng-container matColumnDef="oglive">
<th mat-header-cell *matHeaderCellDef mat-sort-header> OG Live </th>
<td mat-cell *matCellDef="let client"> {{ client.ogLive?.date | date }} </td>
</ng-container>
<ng-container matColumnDef="maintenace">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'maintenance' | translate }} </th>
<td mat-cell *matCellDef="let client"> {{ client.maintenance }} </td>
</ng-container>
<ng-container matColumnDef="subnet">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'subnet' | translate }} </th>
<td mat-cell *matCellDef="let client"> {{ client.subnet }} </td>
</ng-container>
<ng-container matColumnDef="pxeTemplate">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'pxeTemplate' | translate }} </th>
<td mat-cell *matCellDef="let client"> {{ client.template?.name }} </td>
</ng-container>
<ng-container matColumnDef="parentName">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'parent' | translate }} </th>
<td mat-cell *matCellDef="let client"> {{ client.parentName }} </td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'actions' | translate }} </th>
<td mat-cell *matCellDef="let client">
<button
[disabled]="selection.selected.length > 1 || (selection.selected.length === 1 && !selection.isSelected(client))"
mat-icon-button [matMenuTriggerFor]="clientMenu" color="primary">
<mat-icon>more_vert</mat-icon>
</button>
<app-execute-command [clientData]="[client]" [buttonType]="'icon'" [icon]="'terminal'"
[disabled]="selection.selected.length > 1 || (selection.selected.length === 1 && !selection.isSelected(client))"></app-execute-command>
<mat-menu #clientMenu="matMenu">
<button mat-menu-item (click)="onEditClick($event, client.type, client.uuid)">
<mat-icon>edit</mat-icon>
<span>{{ 'edit' | translate }}</span>
</button>
<button mat-menu-item (click)="onShowClientDetail($event, client)">
<mat-icon>visibility</mat-icon>
<span>{{ 'viewDetails' | translate }}</span>
</button>
<button mat-menu-item (click)="getStatus(client, selectedNode)">
<mat-icon>sync</mat-icon>
<span>{{ 'sync' | translate }}</span>
</button>
<button mat-menu-item (click)="onDeleteClick($event, client)">
<mat-icon>delete</mat-icon>
<span>{{ 'delete' | translate }}</span>
</button>
</mat-menu>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSize]="10" [pageSizeOptions]="[5, 10, 20, 50]" showFirstLastButtons></mat-paginator>
</div>
<!-- No clients view -->
<ng-template #noClientsTemplate>
<div *ngIf="!initialLoading" class="no-clients-info">
<span>{{ 'noClients' | translate }}</span>
<mat-icon>error_outline</mat-icon>
</div>
</ng-template>
</div>
<!-- No clients view -->
<ng-template #noClientsTemplate>
<div *ngIf="!initialLoading" class="no-clients-info">
<span>{{ 'noClients' | translate }}</span>
<mat-icon>error_outline</mat-icon>
</div>
</ng-template>
</div>
</div>
</div>
</ng-template>
</ng-template>
</div>

View File

@ -1,5 +1,5 @@
mat-toolbar {
height: 60px;
height: 7vh;
background-color: #3f51b5;
color: white;
}

View File

@ -1,19 +1,10 @@
.header {
height: 10vh;
}
.container {
width: 100vw;
height: calc(100vh - 10vh);
height: calc(100vh - 7vh);
}
.sidebar {
width: 250px;
width: 15vw;
min-width: 250px;
z-index: auto !important;
}
.content {
margin: 0px 10px 10px 10px;
padding: 0px 10px 10px 10px;
box-sizing: border-box;
}

View File

@ -1,4 +1,4 @@
<app-header class="header" (toggleSidebar)="toggleSidebar()"></app-header>
<app-header (toggleSidebar)="toggleSidebar()"></app-header>
<mat-drawer-container class="container" autosize>
<mat-drawer class="sidebar" mode="side" [opened]="isSidebarVisible">