[oggui] Pantallas de roles y usuarios #3
|
@ -35,6 +35,7 @@
|
||||||
"src/assets"
|
"src/assets"
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
|
"src/custom-theme.scss",
|
||||||
"src/styles.css"
|
"src/styles.css"
|
||||||
],
|
],
|
||||||
"scripts": []
|
"scripts": []
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -10,22 +10,25 @@
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^17.0.0",
|
"@angular/animations": "^18.0.0",
|
||||||
"@angular/common": "^17.0.0",
|
"@angular/cdk": "~18.0.0",
|
||||||
"@angular/compiler": "^17.0.0",
|
"@angular/common": "^18.0.0",
|
||||||
"@angular/core": "^17.0.0",
|
"@angular/compiler": "^18.0.0",
|
||||||
"@angular/forms": "^17.0.0",
|
"@angular/core": "^18.0.0",
|
||||||
"@angular/platform-browser": "^17.0.0",
|
"@angular/forms": "^18.0.0",
|
||||||
"@angular/platform-browser-dynamic": "^17.0.0",
|
"@angular/material": "~18.0.0",
|
||||||
"@angular/router": "^17.0.0",
|
"@angular/platform-browser": "^18.0.0",
|
||||||
|
"@angular/platform-browser-dynamic": "^18.0.0",
|
||||||
|
"@angular/router": "^18.0.0",
|
||||||
|
"jwt-decode": "^4.0.0",
|
||||||
"rxjs": "~7.8.0",
|
"rxjs": "~7.8.0",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"zone.js": "~0.14.2"
|
"zone.js": "^0.14.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-devkit/build-angular": "^17.0.7",
|
"@angular-devkit/build-angular": "^18.0.1",
|
||||||
"@angular/cli": "^17.0.7",
|
"@angular/cli": "^18.0.1",
|
||||||
"@angular/compiler-cli": "^17.0.0",
|
"@angular/compiler-cli": "^18.0.0",
|
||||||
"@types/jasmine": "~5.1.0",
|
"@types/jasmine": "~5.1.0",
|
||||||
"jasmine-core": "~5.1.0",
|
"jasmine-core": "~5.1.0",
|
||||||
"karma": "~6.4.0",
|
"karma": "~6.4.0",
|
||||||
|
@ -33,6 +36,6 @@
|
||||||
"karma-coverage": "~2.2.0",
|
"karma-coverage": "~2.2.0",
|
||||||
"karma-jasmine": "~5.1.0",
|
"karma-jasmine": "~5.1.0",
|
||||||
"karma-jasmine-html-reporter": "~2.1.0",
|
"karma-jasmine-html-reporter": "~2.1.0",
|
||||||
"typescript": "~5.2.2"
|
"typescript": "~5.4.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,9 @@ import { AuthLayoutComponent } from './components/layout/auth-layout/auth-layout
|
||||||
import { LoginComponent } from './components/login/login.component';
|
import { LoginComponent } from './components/login/login.component';
|
||||||
import { DashboardComponent } from './components/dashboard/dashboard.component';
|
import { DashboardComponent } from './components/dashboard/dashboard.component';
|
||||||
import { PageNotFoundComponent } from './components/page-not-found/page-not-found.component';
|
import { PageNotFoundComponent } from './components/page-not-found/page-not-found.component';
|
||||||
|
import { AdminComponent } from './components/pages/admin/admin.component';
|
||||||
|
import { UsersComponent } from './components/pages/admin/users/users/users.component';
|
||||||
|
import { RolesComponent } from './components/pages/admin/roles/roles/roles.component';
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{ path: '', redirectTo: 'auth/login', pathMatch: 'full' },
|
{ path: '', redirectTo: 'auth/login', pathMatch: 'full' },
|
||||||
{
|
{
|
||||||
|
@ -13,7 +15,9 @@ const routes: Routes = [
|
||||||
component: MainLayoutComponent,
|
component: MainLayoutComponent,
|
||||||
children: [
|
children: [
|
||||||
{ path: 'dashboard', component: DashboardComponent },
|
{ path: 'dashboard', component: DashboardComponent },
|
||||||
// otras rutas que usan el MainLayoutComponent
|
{ path: 'admin', component: AdminComponent },
|
||||||
|
{ path: 'users', component: UsersComponent },
|
||||||
|
{ path: 'user-groups', component: RolesComponent },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -21,7 +25,6 @@ const routes: Routes = [
|
||||||
component: AuthLayoutComponent,
|
component: AuthLayoutComponent,
|
||||||
children: [
|
children: [
|
||||||
{ path: 'login', component: LoginComponent },
|
{ path: 'login', component: LoginComponent },
|
||||||
// otras rutas de autenticación
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{ path: '**', component: PageNotFoundComponent },
|
{ path: '**', component: PageNotFoundComponent },
|
||||||
|
|
|
@ -7,33 +7,77 @@ import { MainLayoutComponent } from './components/layout/main-layout/main-layout
|
||||||
import { HeaderComponent } from './components/layout/header/header.component';
|
import { HeaderComponent } from './components/layout/header/header.component';
|
||||||
import { SidebarComponent } from './components/layout/sidebar/sidebar.component';
|
import { SidebarComponent } from './components/layout/sidebar/sidebar.component';
|
||||||
import { LoginComponent } from './components/login/login.component';
|
import { LoginComponent } from './components/login/login.component';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
|
import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
|
||||||
import { CustomInterceptor } from './services/custom.interceptor';
|
import { CustomInterceptor } from './services/custom.interceptor';
|
||||||
|
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
|
||||||
|
import {MatToolbarModule} from '@angular/material/toolbar';
|
||||||
|
import {MatIconModule} from '@angular/material/icon';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatSidenavModule } from '@angular/material/sidenav';
|
||||||
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { AdminComponent } from './components/pages/admin/admin.component';
|
||||||
|
import { MatCardModule } from '@angular/material/card';
|
||||||
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
|
import { MatInputModule } from '@angular/material/input';
|
||||||
|
import { MatListModule } from '@angular/material/list';
|
||||||
|
import { UsersComponent } from './components/pages/admin/users/users/users.component';
|
||||||
|
import { RolesComponent } from './components/pages/admin/roles/roles/roles.component';
|
||||||
|
import {MatTableModule} from '@angular/material/table';
|
||||||
|
import {MatDialogModule} from '@angular/material/dialog';
|
||||||
|
import { DeleteUserModalComponent } from './components/pages/admin/users/users/delete-user-modal/delete-user-modal.component';
|
||||||
|
import { AddUserModalComponent } from './components/pages/admin/users/users/add-user-modal/add-user-modal.component';
|
||||||
|
import {MatSelectModule} from '@angular/material/select';
|
||||||
|
import { EditUserModalComponent } from './components/pages/admin/users/users/edit-user-modal/edit-user-modal.component';
|
||||||
|
import { AddRoleModalComponent } from './components/pages/admin/roles/roles/add-role-modal/add-role-modal.component';
|
||||||
|
import { DeleteRoleModalComponent } from './components/pages/admin/roles/roles/delete-role-modal/delete-role-modal.component';
|
||||||
|
import { ChangePasswordModalComponent } from './components/pages/admin/users/users/change-password-modal/change-password-modal.component';
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
declarations: [
|
@NgModule({ declarations: [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
AuthLayoutComponent,
|
AuthLayoutComponent,
|
||||||
MainLayoutComponent,
|
MainLayoutComponent,
|
||||||
HeaderComponent,
|
HeaderComponent,
|
||||||
SidebarComponent,
|
SidebarComponent,
|
||||||
LoginComponent,
|
LoginComponent,
|
||||||
MainLayoutComponent
|
AdminComponent,
|
||||||
],
|
MainLayoutComponent,
|
||||||
imports: [
|
UsersComponent,
|
||||||
BrowserModule,
|
RolesComponent,
|
||||||
AppRoutingModule,
|
DeleteUserModalComponent,
|
||||||
FormsModule,
|
AddUserModalComponent,
|
||||||
HttpClientModule
|
EditUserModalComponent,
|
||||||
],
|
AddRoleModalComponent,
|
||||||
providers: [
|
DeleteRoleModalComponent,
|
||||||
{
|
ChangePasswordModalComponent
|
||||||
provide: HTTP_INTERCEPTORS,
|
],
|
||||||
useClass: CustomInterceptor,
|
bootstrap: [AppComponent],
|
||||||
multi:true
|
imports: [BrowserModule,
|
||||||
}
|
AppRoutingModule,
|
||||||
],
|
FormsModule,
|
||||||
bootstrap: [AppComponent]
|
ReactiveFormsModule,
|
||||||
})
|
MatToolbarModule,
|
||||||
|
MatIconModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatSidenavModule,
|
||||||
|
BrowserAnimationsModule,
|
||||||
|
MatCardModule,
|
||||||
|
MatCheckboxModule,
|
||||||
|
MatFormFieldModule,
|
||||||
|
MatInputModule,
|
||||||
|
MatListModule,
|
||||||
|
MatTableModule,
|
||||||
|
MatDialogModule,
|
||||||
|
MatSelectModule],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: HTTP_INTERCEPTORS,
|
||||||
|
useClass: CustomInterceptor,
|
||||||
|
multi: true
|
||||||
|
},
|
||||||
|
provideAnimationsAsync(),
|
||||||
|
provideHttpClient(withInterceptorsFromDi())
|
||||||
|
] })
|
||||||
export class AppModule { }
|
export class AppModule { }
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import {} from '@angular/common/http';
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { RouterOutlet } from '@angular/router';
|
import { RouterOutlet } from '@angular/router';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
|
|
|
@ -1,5 +1,23 @@
|
||||||
:host{
|
|
||||||
display: block;
|
mat-toolbar {
|
||||||
background-color: rgb(126, 126, 126);
|
display: flex;
|
||||||
grid-area: header;
|
justify-content: space-between;
|
||||||
|
padding: 10px;
|
||||||
|
height: 50px;
|
||||||
|
box-shadow: 10px 0 10px -5px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-button-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
button[mat-flat-button] {
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-tittle{
|
||||||
|
padding-left: 20px;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
|
@ -1 +1,19 @@
|
||||||
<p>header works!</p>
|
<mat-toolbar>
|
||||||
|
<button mat-mini-fab color="primary" aria-label="menu" (click)="onToggleSidebar()">
|
||||||
|
<mat-icon>person</mat-icon>
|
||||||
|
</button>
|
||||||
|
<span class="navbar-tittle" routerLink="/dashboard">Opengnsys webconsole</span>
|
||||||
|
<div class="navbar-button-row">
|
||||||
|
<button mat-flat-button color="primary">Aulas</button>
|
||||||
|
<button mat-flat-button color="primary">Acciones</button>
|
||||||
|
<button mat-flat-button color="primary">Imágenes</button>
|
||||||
|
<button mat-flat-button color="primary">Componentes</button>
|
||||||
|
<button mat-flat-button color="primary">Repositiorios</button>
|
||||||
|
<button mat-flat-button color="primary">Menús</button>
|
||||||
|
<button mat-flat-button color="primary">Buscar</button>
|
||||||
|
<button mat-flat-button color="primary">Calendario</button>
|
||||||
|
<button mat-flat-button color="primary">Ayuda</button>
|
||||||
|
<button mat-flat-button color="warn" routerLink="/auth/login">Salir</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</mat-toolbar>
|
|
@ -1,9 +1,20 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
|
||||||
|
import {jwtDecode} from 'jwt-decode';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-header',
|
selector: 'app-header',
|
||||||
templateUrl: './header.component.html',
|
templateUrl: './header.component.html',
|
||||||
styleUrl: './header.component.css',
|
styleUrls: ['./header.component.css'],
|
||||||
})
|
})
|
||||||
export class HeaderComponent {
|
export class HeaderComponent implements OnInit {
|
||||||
|
@Output() toggleSidebar = new EventEmitter<void>();
|
||||||
|
|
||||||
|
onToggleSidebar() {
|
||||||
|
this.toggleSidebar.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
:host{
|
|
||||||
width: 100%;
|
|
||||||
display: grid;
|
|
||||||
grid-template-areas:
|
|
||||||
"sidebar header"
|
|
||||||
"sidebar content"
|
|
||||||
"sidebar footer";
|
|
||||||
grid-template-columns: 120px 1fr;
|
|
||||||
}
|
|
||||||
.content-wrapper{
|
.content-wrapper{
|
||||||
display: block;
|
display: block;
|
||||||
background-color: gold;
|
|
||||||
grid-area: content;
|
grid-area: content;
|
||||||
|
margin: 20px;
|
||||||
}
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
<app-sidebar></app-sidebar>
|
<app-header (toggleSidebar)="toggleSidebar()"></app-header>
|
||||||
<app-header>
|
|
||||||
</app-header>
|
|
||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
|
<app-sidebar [isVisible]="isSidebarVisible"></app-sidebar>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<router-outlet />
|
<router-outlet />
|
||||||
</div>
|
</div>
|
|
@ -1,10 +1,13 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-main-layout',
|
selector: 'app-main-layout',
|
||||||
templateUrl: './main-layout.component.html',
|
templateUrl: './main-layout.component.html',
|
||||||
styleUrl: './main-layout.component.css'
|
styleUrl: './main-layout.component.css'
|
||||||
})
|
})
|
||||||
export class MainLayoutComponent {
|
export class MainLayoutComponent {
|
||||||
|
isSidebarVisible: boolean = false;
|
||||||
|
|
||||||
|
toggleSidebar() {
|
||||||
|
this.isSidebarVisible = !this.isSidebarVisible;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,24 @@
|
||||||
:host{
|
.sidebar {
|
||||||
display: block;
|
width: 250px;
|
||||||
background-color: rgb(85, 85, 85);
|
position: fixed;
|
||||||
grid-area: sidebar;
|
top: 50px;
|
||||||
}
|
left: -260px;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgb(245, 245, 245);
|
||||||
|
transition: left 0.3s ease-in-out;
|
||||||
|
box-shadow: 10px 0 10px -5px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar.visible {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-content{
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1 +1,8 @@
|
||||||
<p>sidebar works!</p>
|
<div class="sidebar" [class.visible]="isVisible">
|
||||||
|
<div class="sidebar-content">
|
||||||
|
<h4>Bienvenido {{username}}</h4>
|
||||||
|
<button mat-flat-button color="primary" (click)="editUser('username')">Editar usuario</button>
|
||||||
|
<button mat-flat-button color="accent" routerLink="/admin" *ngIf="isSuperAdmin">Admin</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
|
import { jwtDecode } from 'jwt-decode';
|
||||||
|
import { EditUserModalComponent } from '../../pages/admin/users/users/edit-user-modal/edit-user-modal.component';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { ChangePasswordModalComponent } from '../../pages/admin/users/users/change-password-modal/change-password-modal.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-sidebar',
|
selector: 'app-sidebar',
|
||||||
|
@ -6,6 +10,33 @@ import { Component } from '@angular/core';
|
||||||
styleUrl: './sidebar.component.css'
|
styleUrl: './sidebar.component.css'
|
||||||
})
|
})
|
||||||
export class SidebarComponent {
|
export class SidebarComponent {
|
||||||
hovered = false;
|
@Input() isVisible: boolean = false;
|
||||||
}
|
isSuperAdmin: boolean = false;
|
||||||
//https://medium.com/@yevhen.chmykhun.01/angular-blueprint-application-layout-b1680ca888e0
|
username: string = "";
|
||||||
|
decodedToken: any = "";
|
||||||
|
constructor(public dialog: MatDialog) {}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
const token = localStorage.getItem('loginToken');
|
||||||
|
if (token) {
|
||||||
|
try {
|
||||||
|
this.decodedToken = jwtDecode(token);
|
||||||
|
console.log('Decoded token:', this.decodedToken);
|
||||||
|
this.isSuperAdmin = this.decodedToken.roles.includes('ROLE_SUPER_ADMIN');
|
||||||
|
this.username = this.decodedToken.username;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error decoding JWT:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
editUser(user: any) {
|
||||||
|
// Implementar la lógica de edición
|
||||||
|
const dialogRef = this.dialog.open(ChangePasswordModalComponent, {
|
||||||
|
data: { user: this.decodedToken.username, uuid: this.decodedToken.uuid },
|
||||||
|
});
|
||||||
|
/* dialogRef.componentInstance.userEdited.subscribe(() => {
|
||||||
|
console.log("User edited successfully!")
|
||||||
|
}); */
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { LoginComponent } from './login.component';
|
import { LoginComponent } from './login.component';
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
|
|
||||||
describe('LoginComponent', () => {
|
describe('LoginComponent', () => {
|
||||||
|
@ -10,9 +10,10 @@ describe('LoginComponent', () => {
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [HttpClientModule, FormsModule],
|
declarations: [LoginComponent],
|
||||||
declarations: [LoginComponent]
|
imports: [FormsModule],
|
||||||
})
|
providers: [provideHttpClient(withInterceptorsFromDi())]
|
||||||
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(LoginComponent);
|
fixture = TestBed.createComponent(LoginComponent);
|
||||||
|
|
|
@ -37,6 +37,7 @@ export class LoginComponent {
|
||||||
if (res.token) {
|
if (res.token) {
|
||||||
localStorage.setItem('loginToken', res.token);
|
localStorage.setItem('loginToken', res.token);
|
||||||
localStorage.setItem('refreshToken', res.refreshToken);
|
localStorage.setItem('refreshToken', res.refreshToken);
|
||||||
|
localStorage.setItem('username', this.loginObj.username);
|
||||||
this.router.navigateByUrl('/dashboard');
|
this.router.navigateByUrl('/dashboard');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -45,6 +46,9 @@ export class LoginComponent {
|
||||||
this.errorMessage = 'Usuario o contraseña incorrectos';
|
this.errorMessage = 'Usuario o contraseña incorrectos';
|
||||||
} else {
|
} else {
|
||||||
this.errorMessage = 'Ha ocurrido un error. Por favor, inténtelo de nuevo.';
|
this.errorMessage = 'Ha ocurrido un error. Por favor, inténtelo de nuevo.';
|
||||||
|
|
||||||
|
//BYPASS TO DASHBOARD
|
||||||
|
/* this.router.navigateByUrl('/dashboard'); */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/* Estilos del contenedor para centrar los botones */
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Estilos del contenedor de cada botón y texto */
|
||||||
|
.button-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Estilos de los botones */
|
||||||
|
button {
|
||||||
|
height: 150px;
|
||||||
|
width: 150px;
|
||||||
|
margin: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Estilos del texto debajo de los botones */
|
||||||
|
span{
|
||||||
|
margin: 0;
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Media query para hacer los botones responsive */
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
button {
|
||||||
|
height: 120px;
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
button {
|
||||||
|
height: 90px;
|
||||||
|
width: 90px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 400px) {
|
||||||
|
button {
|
||||||
|
height: 70px;
|
||||||
|
width: 70px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span{
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
<div class="container">
|
||||||
|
<button mat-fab color="primary" class="fab-button" routerLink="/users">
|
||||||
|
<mat-icon>group</mat-icon>
|
||||||
|
<span>Usuarios</span>
|
||||||
|
</button>
|
||||||
|
<button mat-fab color="primary" class="fab-button" routerLink="/user-groups">
|
||||||
|
<mat-icon>admin_panel_settings</mat-icon>
|
||||||
|
<span>Roles</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { UsersComponent } from './admin.component';
|
||||||
|
|
||||||
|
describe('UsersComponent', () => {
|
||||||
|
let component: UsersComponent;
|
||||||
|
let fixture: ComponentFixture<UsersComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [UsersComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(UsersComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-admin',
|
||||||
|
templateUrl: './admin.component.html',
|
||||||
|
styleUrl: './admin.component.css'
|
||||||
|
})
|
||||||
|
export class AdminComponent {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
.role-form .form-field {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 10px; /* Puedes ajustar el valor para cambiar la separación */
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-group label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8px; /* Ajusta este valor según necesites */
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
<h1 mat-dialog-title>Añadir Rol (TBD)</h1>
|
||||||
|
<div mat-dialog-content>
|
||||||
|
<form class="role-form">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-label>Nombre</mat-label>
|
||||||
|
<input matInput formControlName="rolename" required>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<section class="example-section">
|
||||||
|
<h4>Permisos:</h4>
|
||||||
|
<p><mat-checkbox >Gestionar los usuarios</mat-checkbox></p>
|
||||||
|
<p><mat-checkbox >Configuración PXE</mat-checkbox></p>
|
||||||
|
<p><mat-checkbox >Imágenes de la consola web</mat-checkbox></p>
|
||||||
|
<p><mat-checkbox >Gestionar los distintos componentes</mat-checkbox></p>
|
||||||
|
<p><mat-checkbox >Crear imágenes</mat-checkbox></p>
|
||||||
|
<p><mat-checkbox >script de configuración del servidor</mat-checkbox></p>
|
||||||
|
<p><mat-checkbox >...</mat-checkbox></p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onNoClick()">Cancelar</button>
|
||||||
|
<button mat-button>Añadir</button>
|
||||||
|
</div>
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AddRoleModalComponent } from './add-role-modal.component';
|
||||||
|
|
||||||
|
describe('AddRoleModalComponent', () => {
|
||||||
|
let component: AddRoleModalComponent;
|
||||||
|
let fixture: ComponentFixture<AddRoleModalComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [AddRoleModalComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(AddRoleModalComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Component, Inject } from '@angular/core';
|
||||||
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-add-role-modal',
|
||||||
|
templateUrl: './add-role-modal.component.html',
|
||||||
|
styleUrl: './add-role-modal.component.css'
|
||||||
|
})
|
||||||
|
export class AddRoleModalComponent {
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<AddRoleModalComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||||
|
private http: HttpClient
|
||||||
|
) {}
|
||||||
|
onNoClick(): void {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
<h1 mat-dialog-title>Eliminar Rol</h1>
|
||||||
|
<div mat-dialog-content>
|
||||||
|
<p>¿Estás seguro que deseas eliminar el rol {{ data.name }}?</p>
|
||||||
|
</div>
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onNoClick()">Cancelar</button>
|
||||||
|
<button mat-button (click)="onYesClick()">Eliminar</button>
|
||||||
|
</div>
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { DeleteRoleModalComponent } from './delete-role-modal.component';
|
||||||
|
|
||||||
|
describe('DeleteRoleModalComponent', () => {
|
||||||
|
let component: DeleteRoleModalComponent;
|
||||||
|
let fixture: ComponentFixture<DeleteRoleModalComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [DeleteRoleModalComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(DeleteRoleModalComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||||
|
import { Component, EventEmitter, Inject, Output } from '@angular/core';
|
||||||
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-delete-role-modal',
|
||||||
|
templateUrl: './delete-role-modal.component.html',
|
||||||
|
styleUrl: './delete-role-modal.component.css'
|
||||||
|
})
|
||||||
|
export class DeleteRoleModalComponent {
|
||||||
|
@Output() roleDeleted = new EventEmitter<void>();
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<DeleteRoleModalComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||||
|
private http: HttpClient
|
||||||
|
) {}
|
||||||
|
|
||||||
|
onNoClick(): void {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
onYesClick(): void {
|
||||||
|
const apiUrl = `http://127.0.0.1:8080/user-groups/${this.data.uuid}`;
|
||||||
|
const headers = new HttpHeaders({
|
||||||
|
'Content-Type': 'application/ld+json'
|
||||||
|
});
|
||||||
|
|
||||||
|
this.http.delete(apiUrl, { headers: headers }).subscribe(
|
||||||
|
() => {
|
||||||
|
console.log('Role deleted successfully');
|
||||||
|
this.roleDeleted.emit();
|
||||||
|
this.dialogRef.close(true);
|
||||||
|
},
|
||||||
|
( error: any) => {
|
||||||
|
console.error('Error deleting role:', error);
|
||||||
|
// Agregar alguna lógica para manejar el error en la interfaz de usuario
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-container {
|
||||||
|
margin-top: 16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-container h1 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
<div class="header-container">
|
||||||
|
<h1>Gestión de roles</h1>
|
||||||
|
<button mat-flat-button color="primary" (click)="addUser()">+ Añadir</button>
|
||||||
|
</div>
|
||||||
|
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8 demo-table">
|
||||||
|
|
||||||
|
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||||
|
<td mat-cell *matCellDef="let role"> {{ column.cell(role) }} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Botones Column -->
|
||||||
|
<ng-container matColumnDef="actions">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Acciones </th>
|
||||||
|
<td mat-cell *matCellDef="let role">
|
||||||
|
<button mat-button color="warn" [disabled]="role.name=== 'Super Admin' " (click)="deleteRole(role)">Eliminar</button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Row definition -->
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
</table>
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { RolesComponent } from './roles.component';
|
||||||
|
|
||||||
|
describe('RolesComponent', () => {
|
||||||
|
let component: RolesComponent;
|
||||||
|
let fixture: ComponentFixture<RolesComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [RolesComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(RolesComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,67 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { RoleService } from './roles.service';
|
||||||
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { AddRoleModalComponent } from './add-role-modal/add-role-modal.component';
|
||||||
|
import { DeleteRoleModalComponent } from './delete-role-modal/delete-role-modal.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-roles',
|
||||||
|
templateUrl: './roles.component.html',
|
||||||
|
styleUrls: ['./roles.component.css']
|
||||||
|
})
|
||||||
|
export class RolesComponent implements OnInit {
|
||||||
|
dataSource = new MatTableDataSource<any>();
|
||||||
|
columns = [
|
||||||
|
{
|
||||||
|
columnDef: 'id',
|
||||||
|
header: 'ID',
|
||||||
|
cell: (role: any) => `${role.id}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
columnDef: 'name',
|
||||||
|
header: 'Nombre',
|
||||||
|
cell: (role: any) => `${role.name}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
columnDef: 'permissions',
|
||||||
|
header: 'Permisos',
|
||||||
|
cell: (role: any) => `${role.permissions.join(', ')}`
|
||||||
|
}
|
||||||
|
];
|
||||||
|
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
|
||||||
|
|
||||||
|
constructor(private roleService: RoleService, public dialog: MatDialog) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.loadRoles();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadRoles() {
|
||||||
|
this.roleService.getRoles().subscribe(response => {
|
||||||
|
console.log(response);
|
||||||
|
this.dataSource.data = response['hydra:member'];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addUser() {
|
||||||
|
const dialogRef = this.dialog.open(AddRoleModalComponent);
|
||||||
|
|
||||||
|
/* dialogRef.componentInstance.roleAdded.subscribe(() => {
|
||||||
|
this.loadRoles();
|
||||||
|
}); */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteRole(role: any) {
|
||||||
|
const dialogRef = this.dialog.open(DeleteRoleModalComponent, {
|
||||||
|
data: role
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe(result => {
|
||||||
|
if (result) {
|
||||||
|
this.loadRoles();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
interface Role {
|
||||||
|
'@id': string;
|
||||||
|
name: string;
|
||||||
|
permissions: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class RoleService {
|
||||||
|
private apiUrl = 'http://127.0.0.1:8080';
|
||||||
|
|
||||||
|
constructor(private http: HttpClient) {}
|
||||||
|
|
||||||
|
getRoles(): Observable<{ 'hydra:member': Role[] }> {
|
||||||
|
return this.http.get<{ 'hydra:member': Role[] }>(`${this.apiUrl}/user-groups?page=1&itemsPerPage=30`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
.user-form .form-field {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 10px; /* Puedes ajustar el valor para cambiar la separación */
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-group label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8px; /* Ajusta este valor según necesites */
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
<h1 mat-dialog-title>Añadir Usuario</h1>
|
||||||
|
<div mat-dialog-content>
|
||||||
|
<form [formGroup]="userForm" class="user-form">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-label>Nombre de usuario</mat-label>
|
||||||
|
<input matInput formControlName="username" required>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-label>Contraseña</mat-label>
|
||||||
|
<input matInput formControlName="password" type="password" required>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-label>Rol</mat-label>
|
||||||
|
<mat-select formControlName="role">
|
||||||
|
<mat-option *ngFor="let group of userGroups" [value]="group['@id']">
|
||||||
|
{{ group.name }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-label>Unidad organiativa</mat-label>
|
||||||
|
<mat-select multiple formControlName="organizationalUnit">
|
||||||
|
<mat-option *ngFor="let unit of organizationalUnits" [value]="unit['@id']">
|
||||||
|
{{unit.name}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onNoClick()">Cancelar</button>
|
||||||
|
<button mat-button [disabled]="!userForm.valid" (click)="onSubmit()">Añadir</button>
|
||||||
|
</div>
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AddUserModalComponent } from './add-user-modal.component';
|
||||||
|
|
||||||
|
describe('AddUserModalComponent', () => {
|
||||||
|
let component: AddUserModalComponent;
|
||||||
|
let fixture: ComponentFixture<AddUserModalComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [AddUserModalComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(AddUserModalComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,75 @@
|
||||||
|
import { Component, EventEmitter, Inject, OnInit, Output } from '@angular/core';
|
||||||
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
|
import { UserService } from '../users.service';
|
||||||
|
|
||||||
|
interface UserGroup {
|
||||||
|
'@id': string;
|
||||||
|
name: string;
|
||||||
|
role: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-add-user-modal',
|
||||||
|
templateUrl: './add-user-modal.component.html',
|
||||||
|
styleUrls: ['./add-user-modal.component.css']
|
||||||
|
})
|
||||||
|
export class AddUserModalComponent implements OnInit {
|
||||||
|
@Output() userAdded = new EventEmitter<void>();
|
||||||
|
userForm: FormGroup;
|
||||||
|
userGroups: UserGroup[] = [];
|
||||||
|
organizationalUnits: any[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<AddUserModalComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||||
|
private fb: FormBuilder,
|
||||||
|
private userService: UserService // Inyecta el servicio
|
||||||
|
) {
|
||||||
|
this.userForm = this.fb.group({
|
||||||
|
username: ['', Validators.required],
|
||||||
|
password: ['', Validators.required],
|
||||||
|
role: ['', Validators.required],
|
||||||
|
organizationalUnit: [[], Validators.required]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.userService.getUserGroups().subscribe((data) => {
|
||||||
|
this.userGroups = data['hydra:member'];
|
||||||
|
});
|
||||||
|
this.userService.getOrganizationalUnits().subscribe((data) => {
|
||||||
|
this.organizationalUnits = data['hydra:member'];
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onNoClick(): void {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(): void {
|
||||||
|
if (this.userForm.valid) {
|
||||||
|
const userPayload = {
|
||||||
|
username: this.userForm.value.username,
|
||||||
|
allowedOrganizationalUnits: this.userForm.value.organizationalUnit,
|
||||||
|
password: this.userForm.value.password,
|
||||||
|
enabled: true,
|
||||||
|
userGroups: [this.userForm.value.role ]
|
||||||
|
};
|
||||||
|
|
||||||
|
this.userService.addUser(userPayload).subscribe(
|
||||||
|
response => {
|
||||||
|
console.log('User playload:', userPayload);
|
||||||
|
console.log('User added successfully:', response);
|
||||||
|
this.userAdded.emit();
|
||||||
|
this.dialogRef.close(this.userForm.value);
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.error('Error adding user:', error);
|
||||||
|
// Agregar alguna lógica para manejar el error en la interfaz de usuario
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
.user-form .form-field {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-group label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
color: red;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
<h1 mat-dialog-title>Editar Usuario</h1>
|
||||||
|
<div mat-dialog-content>
|
||||||
|
<form [formGroup]="userForm" class="user-form">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-label>Nombre de usuario</mat-label>
|
||||||
|
<input matInput formControlName="username">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-label>Nueva contraseña</mat-label>
|
||||||
|
<input matInput formControlName="password" type="password">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-label>Repite la contraseña</mat-label>
|
||||||
|
<input matInput formControlName="confirmPassword" type="password">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
@if (passwordMismatch) {
|
||||||
|
<div class="error-message">Las contraseñas no coinciden</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (updateError) {
|
||||||
|
<div class="error-message">Error, inténtelo de nuevo</div>
|
||||||
|
}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onNoClick()">Cancelar</button>
|
||||||
|
<button mat-button (click)="onSubmit()">Editar</button>
|
||||||
|
</div>
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ChangePasswordModalComponent } from './change-password-modal.component';
|
||||||
|
|
||||||
|
describe('ChangePasswordModalComponent', () => {
|
||||||
|
let component: ChangePasswordModalComponent;
|
||||||
|
let fixture: ComponentFixture<ChangePasswordModalComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ChangePasswordModalComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ChangePasswordModalComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,73 @@
|
||||||
|
import { Component, EventEmitter, Inject, Output } from '@angular/core';
|
||||||
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||||
|
import { EditUserModalComponent } from '../edit-user-modal/edit-user-modal.component';
|
||||||
|
import { UserService } from '../users.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-change-password-modal',
|
||||||
|
templateUrl: './change-password-modal.component.html',
|
||||||
|
styleUrls: ['./change-password-modal.component.css']
|
||||||
|
})
|
||||||
|
export class ChangePasswordModalComponent {
|
||||||
|
@Output() userEdited = new EventEmitter<void>();
|
||||||
|
userForm: FormGroup;
|
||||||
|
passwordMismatch: boolean = false;
|
||||||
|
updateError: boolean = false;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<EditUserModalComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||||
|
private fb: FormBuilder,
|
||||||
|
private userService: UserService
|
||||||
|
) {
|
||||||
|
this.userForm = this.fb.group({
|
||||||
|
username: [this.data.user, Validators.required],
|
||||||
|
password: ['', Validators.required],
|
||||||
|
confirmPassword: ['', Validators.required]
|
||||||
|
}, { validators: this.passwordMatchValidator });
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
console.log('Data:', this.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
onNoClick(): void {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(): void {
|
||||||
|
if (this.userForm.valid) {
|
||||||
|
this.passwordMismatch = false;
|
||||||
|
this.updateError = false;
|
||||||
|
|
||||||
|
const userPayload = {
|
||||||
|
username: this.userForm.value.username,
|
||||||
|
allowedOrganizationalUnits: [],
|
||||||
|
password: this.userForm.value.password,
|
||||||
|
enabled: true,
|
||||||
|
userGroups: []
|
||||||
|
};
|
||||||
|
console.log("THIS IS THE USER PAYLOAD: ", userPayload);
|
||||||
|
this.userService.updateUser(this.data.uuid, userPayload).subscribe(
|
||||||
|
response => {
|
||||||
|
console.log('User updated successfully:', response);
|
||||||
|
this.userEdited.emit();
|
||||||
|
this.dialogRef.close(this.userForm.value);
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.error('Error updating user:', error);
|
||||||
|
this.updateError = true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.error('Form is invalid');
|
||||||
|
this.passwordMismatch = this.userForm.hasError('mismatch');
|
||||||
|
this.updateError = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private passwordMatchValidator(form: FormGroup): { [key: string]: boolean } | null {
|
||||||
|
return form.get('password')?.value === form.get('confirmPassword')?.value ? null : { mismatch: true };
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
<h1 mat-dialog-title>Eliminar Usuario</h1>
|
||||||
|
<div mat-dialog-content>
|
||||||
|
<p>¿Estás seguro que deseas eliminar a {{ data.username }}?</p>
|
||||||
|
</div>
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onNoClick()">Cancelar</button>
|
||||||
|
<button mat-button (click)="onYesClick()">Eliminar</button>
|
||||||
|
</div>
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { DeleteUserModalComponent } from './delete-user-modal.component';
|
||||||
|
|
||||||
|
describe('DeleteUserModalComponent', () => {
|
||||||
|
let component: DeleteUserModalComponent;
|
||||||
|
let fixture: ComponentFixture<DeleteUserModalComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [DeleteUserModalComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(DeleteUserModalComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||||
|
import { Component, EventEmitter, Inject, Output } from '@angular/core';
|
||||||
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-delete-user-modal',
|
||||||
|
templateUrl: './delete-user-modal.component.html',
|
||||||
|
styleUrl: './delete-user-modal.component.css'
|
||||||
|
})
|
||||||
|
export class DeleteUserModalComponent {
|
||||||
|
@Output() userDeleted = new EventEmitter<void>();
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<DeleteUserModalComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||||
|
private http: HttpClient
|
||||||
|
) {}
|
||||||
|
|
||||||
|
onNoClick(): void {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
onYesClick(): void {
|
||||||
|
const apiUrl = `http://127.0.0.1:8080/users/${this.data.uuid}`;
|
||||||
|
const headers = new HttpHeaders({
|
||||||
|
'Content-Type': 'application/ld+json'
|
||||||
|
});
|
||||||
|
|
||||||
|
this.http.delete(apiUrl, { headers: headers }).subscribe(
|
||||||
|
() => {
|
||||||
|
console.log('User deleted successfully');
|
||||||
|
this.userDeleted.emit();
|
||||||
|
this.dialogRef.close(true);
|
||||||
|
},
|
||||||
|
( error: any) => {
|
||||||
|
console.error('Error deleting user:', error);
|
||||||
|
// Agregar alguna lógica para manejar el error en la interfaz de usuario
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
.user-form .form-field {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 10px; /* Puedes ajustar el valor para cambiar la separación */
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-group label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8px; /* Ajusta este valor según necesites */
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
<h1 mat-dialog-title>Editar Usuario</h1>
|
||||||
|
<div mat-dialog-content>
|
||||||
|
<form [formGroup]="userForm" class="user-form">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-label>Nombre de usuario</mat-label>
|
||||||
|
<input matInput formControlName="username">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-label>Contraseña</mat-label>
|
||||||
|
<input matInput formControlName="password" type="password">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field appearance="fill">
|
||||||
|
<mat-label>Rol</mat-label>
|
||||||
|
<mat-select formControlName="role">
|
||||||
|
<mat-option *ngFor="let group of userGroups" [value]="group['@id']">
|
||||||
|
{{ group.name }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-label>Unidad organiativa</mat-label>
|
||||||
|
<mat-select multiple formControlName="organizationalUnit">
|
||||||
|
<mat-option *ngFor="let unit of organizationalUnits" [value]="unit['@id']">
|
||||||
|
{{unit.name}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onNoClick()">Cancelar</button>
|
||||||
|
<button mat-button (click)="onSubmit()">Editar</button>
|
||||||
|
</div>
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { EditUserModalComponent } from './edit-user-modal.component';
|
||||||
|
|
||||||
|
describe('EditUserModalComponent', () => {
|
||||||
|
let component: EditUserModalComponent;
|
||||||
|
let fixture: ComponentFixture<EditUserModalComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [EditUserModalComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(EditUserModalComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,71 @@
|
||||||
|
import { Component, EventEmitter, Inject, OnInit, Output } from '@angular/core';
|
||||||
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
|
import { UserService } from '../users.service';
|
||||||
|
|
||||||
|
interface UserGroup {
|
||||||
|
'@id': string;
|
||||||
|
name: string;
|
||||||
|
role: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-edit-user-modal',
|
||||||
|
templateUrl: './edit-user-modal.component.html',
|
||||||
|
styleUrls: ['./edit-user-modal.component.css']
|
||||||
|
})
|
||||||
|
export class EditUserModalComponent implements OnInit {@Output() userEdited = new EventEmitter<void>();
|
||||||
|
userForm: FormGroup;
|
||||||
|
userGroups: UserGroup[] = [];
|
||||||
|
organizationalUnits: any[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<EditUserModalComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||||
|
private fb: FormBuilder,
|
||||||
|
private userService: UserService // Inyecta el servicio
|
||||||
|
) {
|
||||||
|
this.userForm = this.fb.group({
|
||||||
|
username: [this.data],
|
||||||
|
password: [''],
|
||||||
|
role: this.data.user.allowedOrganizationalUnits,
|
||||||
|
organizationalUnit: [[this.data.user.allowedOrganizationalUnits], Validators.required]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.userService.getUserGroups().subscribe((data) => {
|
||||||
|
this.userGroups = data['hydra:member'];
|
||||||
|
});
|
||||||
|
this.userService.getOrganizationalUnits().subscribe((data) => {
|
||||||
|
this.organizationalUnits = data['hydra:member'];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onNoClick(): void {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(): void {
|
||||||
|
|
||||||
|
const userPayload = {
|
||||||
|
username: this.userForm.value.username,
|
||||||
|
allowedOrganizationalUnits: [],
|
||||||
|
password: this.userForm.value.password,
|
||||||
|
enabled: true,
|
||||||
|
userGroups: [this.userForm.value.role ]
|
||||||
|
};
|
||||||
|
|
||||||
|
this.userService.updateUser(this.data.user.uuid, userPayload).subscribe(
|
||||||
|
response => {
|
||||||
|
console.log('User added successfully:', response);
|
||||||
|
this.userEdited.emit();
|
||||||
|
this.dialogRef.close(this.userForm.value);
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.error('Error adding user:', error);
|
||||||
|
// Agregar alguna lógica para manejar el error en la interfaz de usuario
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-container {
|
||||||
|
margin-top: 16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-container h1 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<div class="header-container">
|
||||||
|
<h1>Gestión de usuarios</h1>
|
||||||
|
<button mat-flat-button color="primary" (click)="addUser()">+ Añadir</button>
|
||||||
|
</div>
|
||||||
|
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8 demo-table">
|
||||||
|
|
||||||
|
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||||
|
<td mat-cell *matCellDef="let user"> {{ column.cell(user) }} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Botones Column -->
|
||||||
|
<ng-container matColumnDef="actions">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Acciones </th>
|
||||||
|
<td mat-cell *matCellDef="let user">
|
||||||
|
<button mat-button color="primary" (click)="editUser(user)">Editar</button>
|
||||||
|
<button mat-button color="warn" (click)="deleteUser(user)">Eliminar</button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Row definition -->
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
</table>
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { UsersComponent } from './users.component';
|
||||||
|
|
||||||
|
describe('UsersComponent', () => {
|
||||||
|
let component: UsersComponent;
|
||||||
|
let fixture: ComponentFixture<UsersComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [UsersComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(UsersComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,83 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { UserService } from './users.service';
|
||||||
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
|
import { DeleteUserModalComponent } from './delete-user-modal/delete-user-modal.component';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { AddUserModalComponent } from './add-user-modal/add-user-modal.component';
|
||||||
|
import { EditUserModalComponent } from './edit-user-modal/edit-user-modal.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-users',
|
||||||
|
templateUrl: './users.component.html',
|
||||||
|
styleUrls: ['./users.component.css']
|
||||||
|
})
|
||||||
|
export class UsersComponent implements OnInit {
|
||||||
|
dataSource = new MatTableDataSource<any>();
|
||||||
|
columns = [
|
||||||
|
{
|
||||||
|
columnDef: 'id',
|
||||||
|
header: 'ID',
|
||||||
|
cell: (user: any) => `${user.id}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
columnDef: 'username',
|
||||||
|
header: 'Nombre de Usuario',
|
||||||
|
cell: (user: any) => `${user.username}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
columnDef: 'allowedOrganizationalUnits',
|
||||||
|
header: 'Unidades Organizacionales Permitidas',
|
||||||
|
cell: (user: any) => `${user.allowedOrganizationalUnits.map((unit: { name: any; }) => unit.name).join(', ')}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
columnDef: 'roles',
|
||||||
|
header: 'Roles',
|
||||||
|
cell: (user: any) => `${user.roles.join(', ')}`
|
||||||
|
}
|
||||||
|
];
|
||||||
|
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
|
||||||
|
|
||||||
|
constructor(private userService: UserService, public dialog: MatDialog) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.loadUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadUsers() {
|
||||||
|
this.userService.getUsers().subscribe(response => {
|
||||||
|
this.dataSource.data = response['hydra:member'];
|
||||||
|
console.log(this.dataSource.data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addUser() {
|
||||||
|
const dialogRef = this.dialog.open(AddUserModalComponent);
|
||||||
|
|
||||||
|
dialogRef.componentInstance.userAdded.subscribe(() => {
|
||||||
|
this.loadUsers();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
editUser(user: any) {
|
||||||
|
// Implementar la lógica de edición
|
||||||
|
const dialogRef = this.dialog.open(EditUserModalComponent, {
|
||||||
|
data: { user: user }
|
||||||
|
});
|
||||||
|
dialogRef.componentInstance.userEdited.subscribe(() => {
|
||||||
|
this.loadUsers();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteUser(user: any) {
|
||||||
|
const dialogRef = this.dialog.open(DeleteUserModalComponent, {
|
||||||
|
data: user
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe(result => {
|
||||||
|
if (result) {
|
||||||
|
this.loadUsers();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
interface UserPayload {
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
enabled: boolean;
|
||||||
|
userGroups: string[];
|
||||||
|
allowedOrganizationalUnits: any[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UserGroup {
|
||||||
|
'@id': string;
|
||||||
|
name: string;
|
||||||
|
role: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class UserService {
|
||||||
|
private apiUrl = 'http://127.0.0.1:8080';
|
||||||
|
|
||||||
|
constructor(private http: HttpClient) {}
|
||||||
|
|
||||||
|
addUser(userPayload: UserPayload): Observable<any> {
|
||||||
|
const headers = new HttpHeaders({
|
||||||
|
'Content-Type': 'application/ld+json',
|
||||||
|
});
|
||||||
|
return this.http.post(`${this.apiUrl}/users`, userPayload, { headers });
|
||||||
|
}
|
||||||
|
|
||||||
|
updateUser(userId: number, userPayload: UserPayload): Observable<any> {
|
||||||
|
const headers = new HttpHeaders({
|
||||||
|
'Content-Type': 'application/ld+json',
|
||||||
|
});
|
||||||
|
return this.http.put(`${this.apiUrl}/users/${userId}`, userPayload, { headers });
|
||||||
|
}
|
||||||
|
|
||||||
|
getUserGroups(): Observable<{ 'hydra:member': UserGroup[] }> {
|
||||||
|
return this.http.get<{ 'hydra:member': UserGroup[] }>(`${this.apiUrl}/user-groups`);
|
||||||
|
}
|
||||||
|
|
||||||
|
getUsers(): Observable<any> {
|
||||||
|
return this.http.get<any>(`${this.apiUrl}/users?page=1&itemsPerPage=30`);
|
||||||
|
}
|
||||||
|
|
||||||
|
getOrganizationalUnits(): Observable<any> {
|
||||||
|
return this.http.get<any>(`${this.apiUrl}/organizational-units?page=1&itemsPerPage=30`);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,18 +1,28 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HttpInterceptorFn, HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
|
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { Token } from '@angular/compiler';
|
|
||||||
|
|
||||||
export class CustomInterceptor implements HttpInterceptor{
|
@Injectable()
|
||||||
constructor(){}
|
export class CustomInterceptor implements HttpInterceptor {
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
|
|
||||||
const token = localStorage.getItem('loginToken');
|
const token = localStorage.getItem('loginToken');
|
||||||
const newCloneRequest = req.clone({
|
let newCloneRequest;
|
||||||
setHeaders:{
|
|
||||||
Authorization: `${token}`
|
if (req.url.includes('login')) {
|
||||||
}
|
newCloneRequest = req.clone({
|
||||||
})
|
setHeaders: {
|
||||||
|
Authorization: `${token}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
newCloneRequest = req.clone({
|
||||||
|
setHeaders: {
|
||||||
|
Authorization: `Bearer ${token}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return next.handle(newCloneRequest);
|
return next.handle(newCloneRequest);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
|
||||||
|
// Custom Theming for Angular Material
|
||||||
|
// For more information: https://material.angular.io/guide/theming
|
||||||
|
@use '@angular/material' as mat;
|
||||||
|
// Plus imports for other components in your app.
|
||||||
|
|
||||||
|
// Include the common styles for Angular Material. We include this here so that you only
|
||||||
|
// have to load a single css file for Angular Material in your app.
|
||||||
|
// Be sure that you only ever include this mixin once!
|
||||||
|
@include mat.core();
|
||||||
|
|
||||||
|
// Define the palettes for your theme using the Material Design palettes available in palette.scss
|
||||||
|
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
|
||||||
|
// hue. Available color palettes: https://material.io/design/color/
|
||||||
|
$ogWebconsole-primary: mat.m2-define-palette(mat.$m2-indigo-palette);
|
||||||
|
$ogWebconsole-accent: mat.m2-define-palette(mat.$m2-pink-palette, A200, A100, A400);
|
||||||
|
|
||||||
|
// The warn palette is optional (defaults to red).
|
||||||
|
$ogWebconsole-warn: mat.m2-define-palette(mat.$m2-red-palette);
|
||||||
|
|
||||||
|
// Create the theme object. A theme consists of configurations for individual
|
||||||
|
// theming systems such as "color" or "typography".
|
||||||
|
$ogWebconsole-theme: mat.m2-define-light-theme((
|
||||||
|
color: (
|
||||||
|
primary: $ogWebconsole-primary,
|
||||||
|
accent: $ogWebconsole-accent,
|
||||||
|
warn: $ogWebconsole-warn,
|
||||||
|
),
|
||||||
|
typography: mat.m2-define-typography-config(),
|
||||||
|
density: 0
|
||||||
|
));
|
||||||
|
|
||||||
|
// Include theme styles for core and each component used in your app.
|
||||||
|
// Alternatively, you can import and @include the theme mixins for each component
|
||||||
|
// that you are using.
|
||||||
|
@include mat.all-component-themes($ogWebconsole-theme);
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 3.4 KiB |
|
@ -6,8 +6,10 @@
|
||||||
<base href="/">
|
<base href="/">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body class="mat-typography">
|
||||||
<app-root></app-root>
|
<app-root></app-root>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1 +1,4 @@
|
||||||
/* You can add global styles to this file, and also import other style files */
|
/* You can add global styles to this file, and also import other style files */
|
||||||
|
|
||||||
|
html, body { height: 100%; }
|
||||||
|
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
|
||||||
|
|
Loading…
Reference in New Issue