Compare commits

...

20 Commits

Author SHA1 Message Date
Developer 02
5b30ae789a Bearbeitung von Zellen durch isEditable steuern
- Bedingung hinzugefügt, um zu überprüfen, ob die Bearbeitung basierend auf der `updateService.isEditable`-Eigenschaft erlaubt ist.
- `cellEdit`-Methoden in GroupComponent und UserComponent aktualisiert, um die Einstellung `isEditable` zu berücksichtigen.
2024-08-06 18:09:03 +02:00
Developer 02
c1f603551f feat: Add editability feature to UpdateService and integrate with NavMenuComponent
- Added `isEditable` property to `UpdateService` for managing editability state.
- Integrated `isEditable` with a `mat-slide-toggle` in `NavMenuComponent` to toggle edit mode.
- Updated `UpdateService` to persist `isEditable` state in localStorage.
2024-08-06 18:04:28 +02:00
Developer 02
0b4a7b7ccd feat: GroupComponent mit asynchroner Zellbearbeitung und verbessertem Template für die tabellarische Ansicht von Gruppen- und Benutzertabellen aktualisieren. 2024-08-06 17:43:40 +02:00
Developer 02
39da8bd664 refactor: cellEdit-Methode vereinfacht, indem die rowEdit-Funktion entfernt wurde. 2024-08-06 17:28:57 +02:00
Developer 02
cef2690aa8 fix: integrate UpdateService with RefreshService. Ensured UpdateService actions are cleared when executing all actions in RefreshService. 2024-08-06 17:17:52 +02:00
Developer 02
607761c678 fix: Zellbearbeitung mit asynchronem Update verbessern und User-Modell einbinden
- cellEdit-Methode aktualisiert, um asynchrones Update mit `updateService` und `firstValueFrom` zu verwenden.
- Import für User-Modell hinzugefügt und Methodensignatur auf `User`-Typ aktualisiert.
- Kleine Code- und Importbereinigungen vorgenommen.
2024-08-06 17:04:52 +02:00
Developer 02
ac16d0d48d feat: UpdateService in BasePageComponent integrieren
- `UpdateService` in `BasePageComponent` integriert.
- Der Konstruktor wurde aktualisiert, um `UpdateService` zu integrieren. Wenn im `UpdateService` eine Aktion vorhanden ist, wird `executeAll` aufgerufen.
2024-08-06 16:29:52 +02:00
Developer 02
2175fdc15f refactor: UpdateService mit Zähler-Änderungs-Listener erweitern
- `UpdateEvent`-Enum für Ereignistypen hinzugefügt.
- `countChangeListeners` eingeführt, um zählerbezogene Änderungen zu verwalten.
- Methoden aktualisiert, um `countChangeListeners` auszulösen und Statusänderungen effizienter zu handhaben.
- Methodennamen auf `executeCountChangeListeners` geändert.
2024-08-06 16:23:39 +02:00
Developer 02
6bf606b738 refactor: UpdateService auf schlüsselbasierte Aktionen umstellen
- Arrays durch schlüsselbasierte Objekte für asynchrone und synchrone Aktionen ersetzt.
- Methoden aktualisiert, um Schlüssel zur Verwaltung von Aktionen zu verwenden und Änderungs-Listener auszulösen.
- `executeAll` angepasst, um Aktionen aus Objekten zu verarbeiten.
2024-08-06 16:09:01 +02:00
Developer 02
e00c113bee feat: enhance NavMenuComponent with updateService integration
- Added MatBadgeModule for update count display.
- Integrated `updateService` to show update count in the save button.
- Added change listener to update button count dynamically.
- Improved HTML structure with updated menu and button functionalities.
2024-08-06 15:32:51 +02:00
Developer 02
0fe9cb7126 feat: UpdateService mit Änderungs-Listenern und zusätzlichen Funktionen erweitern
- Getter `any` hinzugefügt, um zu überprüfen, ob Aktionen vorhanden sind.
- Methoden `addAsync` und `add` geändert, um Änderungs-Listener nach dem Hinzufügen von Aktionen zu benachrichtigen.
- `changeListeners`-Array implementiert mit Methoden zum Hinzufügen und Entfernen von Listenern.
- `executeAllChangeListeners` hinzugefügt, um alle registrierten Änderungs-Listener auszulösen.
- Methode `removeAll` aktualisiert, um Änderungs-Listener nach dem Leeren der Aktionen zu benachrichtigen.
2024-08-06 15:02:33 +02:00
Developer 02
2eb107cc0a feat: Getter asyncCount, syncCount und totalCount zu UpdateService hinzugefügt. 2024-08-06 13:35:46 +02:00
Developer 02
8d45b60aca feat: UpdateService hinzufügen und in Navbar integrieren
- UpdateService erstellt, um asynchrone und synchrone Aktionen zu verwalten und auszuführen.
- Einen Speichern-Button in der Navbar hinzugefügt, der die Ausführung aller Aktionen im UpdateService auslöst.
- UpdateService in die Anwendung integriert, um die Aktualisierungslogik zu zentralisieren.
2024-08-06 13:29:54 +02:00
Developer 02
86fae90d49 feat: create base page component and refactor page inheritance
- Created a base page component to centralize common functionality.
- Injected refreshService and creationService into the base page.
- Added reset methods for refreshService and creationService in the constructor.
- Refactored all other page components to inherit from the base page component.
2024-08-06 12:07:26 +02:00
Developer 02
efa79141cf refactor: nav-menu- und login-Komponenten in den Komponenten-Ordner verschieben 2024-08-06 11:43:32 +02:00
Developer 02
3d3ad0e09a refactor: Projektstruktur organisiert, indem alle Seitenkomponenten in einen eigenen Ordner verschoben wurden. 2024-08-06 11:39:45 +02:00
Developer 02
b6065ddd5c fix: Updated localStorage access to check for window object existence to avoid SSR issues. 2024-08-06 11:31:37 +02:00
Developer 02
3a72c4c9fa Revert "Reapply "fix: Vorübergehend nur Dark Mode erlaubt wegen localStorage Problem""
This reverts commit c604e5c5ef.
2024-08-06 11:09:38 +02:00
Developer 02
6cc3430592 feat: Logik hinzugefügt, um Add- und Update-Buttons auszublenden, wenn der Benutzer nicht angemeldet ist. 2024-08-06 10:53:30 +02:00
Developer 02
64a1ec7937 refactor: Separate Import-Buttons für Benutzer und Gruppen wurden entfernt, um die Benutzeroberfläche zu vereinfachen. 2024-08-01 13:41:59 +02:00
44 changed files with 268 additions and 112 deletions

View File

@@ -1,6 +1,6 @@
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import {NavMenuComponent} from './nav-menu/nav-menu.component'
import {NavMenuComponent} from './components/nav-menu/nav-menu.component'
@Component({
selector: 'app-root',

View File

@@ -1,11 +1,11 @@
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { HomeComponent } from './pages/home/home.component';
import { AuthGuard } from './auth/auth.guard';
import { UserComponent } from './components/user/user.component';
import { GroupComponent } from './components/group/group.component';
import { ModuleComponent } from './components/module/module.component';
import { UserAssignmentComponent } from './components/user-assignment/user-assignment.component';
import { UserRepresentationComponent } from './components/user-representation/user-representation.component';
import { UserComponent } from './pages/user/user.component';
import { GroupComponent } from './pages/group/group.component';
import { ModuleComponent } from './pages/module/module.component';
import { UserAssignmentComponent } from './pages/user-assignment/user-assignment.component';
import { UserRepresentationComponent } from './pages/user-representation/user-representation.component';
export const routes: Routes = [
{ path: '', component: HomeComponent },

View File

@@ -3,7 +3,7 @@ import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from
import { Observable, of } from 'rxjs';
import { AuthenticationService } from '../services/authentication.service'; // Adjust the path as necessary
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { LoginComponent } from '../login/login.component';
import { LoginComponent } from '../components/login/login.component';
@Injectable({
providedIn: 'root',

View File

@@ -1,5 +1,5 @@
import { Component, Inject, Input } from '@angular/core';
import { AuthenticationService } from '../services/authentication.service';
import { AuthenticationService } from '../../services/authentication.service';
import Swal from 'sweetalert2';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { CommonModule } from '@angular/common';

View File

@@ -30,10 +30,14 @@
<!-- Right menu -->
<div class="navbar-collapse justify-content-end me-5">
<a class="navbar-brand" [routerLink]="['/']">User Manager Portal</a>
<button class="btn">
<mat-slide-toggle [(ngModel)]="updateService.isEditable"></mat-slide-toggle>
<button *ngIf="isLogedIn()" class="btn">
<mat-icon class="scale-pulse" [matBadge]="updateActCount === 0 ? '' : updateActCount" (click)="updateService.executeAll()">save</mat-icon>
</button>
<button *ngIf="isLogedIn()" class="btn">
<mat-icon class="scale-pulse" (click)="creationService.openDialog()">add_to_photos</mat-icon>
</button>
<button class="btn" (click)="refreshService.executeAll()">
<button *ngIf="isLogedIn()" class="btn" (click)="refreshService.executeAll()">
<mat-icon class="turn-360">sync</mat-icon>
</button>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse"
@@ -41,26 +45,6 @@
<span class="navbar-toggler-icon"></span>
</button>
<app-color-mode-bttn></app-color-mode-bttn>
<div *ngIf="isLogedIn()" class="d-flex">
<button class="btn m-0 p-0" type="button" (click)="importUser()">
<img src="../../assets/img/user.svg">
</button>
<button class="btn m-0 p-0" type="button" (click)="importGroup()" style="stroke: #a9a8ad;">
<svg class="bi" width="3em" height="2.5em" viewBox="0 0 488.6 488.6" stroke="#a9a8ad">
<path opacity="0.5"
d="M480.9,333.2c-27.2-22.3-56.5-37.1-62.4-40c-0.7-0.3-1.1-1-1.1-1.8v-42.3c5.3-3.5,8.8-9.6,8.8-16.5v-43.9
c0-21.8-17.7-39.5-39.5-39.5H382h-4.7c-21.8,0-39.5,17.7-39.5,39.5v43.9c0,6.9,3.5,12.9,8.8,16.5v42.3c0,0.3-0.1,0.5-0.1,0.7
c8.3,5.7,17,12.1,25.5,19.1c9.9,8.2,15.6,20.2,15.6,33.2v35.3h101v-30.1C488.6,343.3,485.8,337.2,480.9,333.2z" />
<path opacity="0.5" d="M142,291.4v-42.3c5.3-3.5,8.8-9.6,8.8-16.5v-43.9c0-21.8-17.7-39.5-39.5-39.5h-4.7h-4.7c-21.8,0-39.5,17.7-39.5,39.5v43.9
c0,6.9,3.5,12.9,8.8,16.5v42.3c0,0.7-0.4,1.4-1.1,1.8c-6,2.9-35.3,17.7-62.4,40c-4.9,4-7.7,10.1-7.7,16.4v30.1h101v-35.3
c0-12.9,5.7-25,15.6-33.2c8.5-7,17.2-13.4,25.5-19.1C142.1,291.9,142,291.7,142,291.4z" />
<path opacity="0.5" d="M360.5,325.1c-31.9-26.2-66.3-43.6-73.4-47.1c-0.8-0.4-1.3-1.2-1.3-2.1v-49.7c6.2-4.2,10.4-11.3,10.4-19.3v-51.6
c0-25.6-20.8-46.4-46.4-46.4h-5.5h-5.5c-25.6,0-46.4,20.8-46.4,46.4v51.5c0,8.1,4.1,15.2,10.4,19.3v49.7c0,0.9-0.5,1.7-1.3,2.1
c-7,3.4-41.4,20.8-73.4,47.1c-5.8,4.7-9.1,11.8-9.1,19.3v35.3h108.9l10.8-49.3c-21.7-30.3,1.6-31.8,5.7-31.8l0,0l0,0
c4.1,0,27.4,1.5,5.7,31.8l10.8,49.3h108.9v-35.3C369.6,336.9,366.3,329.8,360.5,325.1z" />
</svg>
</button>
</div>
<button class="fs-5 btn d-flex align-items-center ms-2 me-0 pe-0" type="button" (click)="auth()">
<img fetchpriority="high" src="../../assets/img/login_logo.svg" alt="" style="stroke: #a9a8ad;">
{{isLogedIn() ? "Log out" : "Log in"}}

View File

@@ -1,19 +1,23 @@
import { Component } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { UserGroupDirImportComponent } from '../components/user-group-dir-import/user-group-dir-import.component';
import { GroupDirImportComponent } from '../components/group-dir-import/group-dir-import.component';
import { AuthenticationService, IsLogedIn } from '../services/authentication.service';
import { AuthenticationService, IsLogedIn } from '../../services/authentication.service';
import { LoginComponent } from '../login/login.component';
import { RouterModule } from '@angular/router';
import { CommonModule } from '@angular/common';
import { ColorModeBttnComponent } from '../components/common/color-mode-bttn/color-mode-bttn.component';
import { ColorModeBttnComponent } from '../common/color-mode-bttn/color-mode-bttn.component';
import { MatIconModule } from '@angular/material/icon';
import { RefreshService } from '../services/refresh.service';
import { CreationService } from '../services/creation.service';
import { RefreshService } from '../../services/refresh.service';
import { CreationService } from '../../services/creation.service';
import { UpdateService, UpdateEvent } from '../../services/update.service';
import { MatBadgeModule } from '@angular/material/badge';
import {
MatSlideToggleModule,
} from '@angular/material/slide-toggle';
import { FormsModule } from '@angular/forms';
@Component({
standalone: true,
imports: [RouterModule, CommonModule, ColorModeBttnComponent, MatIconModule],
imports: [RouterModule, CommonModule, ColorModeBttnComponent, MatIconModule, MatBadgeModule, MatSlideToggleModule, FormsModule],
selector: 'app-nav-menu',
templateUrl: './nav-menu.component.html',
styleUrls: ['./nav-menu.component.css']
@@ -24,12 +28,20 @@ export class NavMenuComponent {
}
isExpanded = false;
constructor(private dialog: MatDialog, private authService: AuthenticationService, public refreshService: RefreshService, public creationService : CreationService) {
updateActCount: number;
isChecked = true;
constructor(private dialog: MatDialog, private authService: AuthenticationService, public refreshService: RefreshService, public creationService: CreationService, public updateService: UpdateService) {
this.authService.isAuthenticated().then().catch()
this.updateActCount = this.updateService.totalCount;
this.updateService.addChangeListener(UpdateEvent.CountChange, () => {
this.updateActCount = updateService.totalCount;
})
}
get isDarkTheme(): boolean {
return true;
return (typeof window !== 'undefined') ? (localStorage.getItem('theme') === 'dark') : true;
}
collapse() {
@@ -40,17 +52,6 @@ export class NavMenuComponent {
this.isExpanded = !this.isExpanded;
}
importUser() {
const dialogRef = this.dialog.open(UserGroupDirImportComponent, {
width: "50vw"
});
}
importGroup() {
const dialogRef = this.dialog.open(GroupDirImportComponent, {
width: "50vw"
});
}
async auth() {
const isLoggedIn = await this.authService.isAuthenticated();
if (isLoggedIn)

View File

@@ -65,7 +65,7 @@ export class BaseTableComponent<TModel, TApiService extends ApiService<TModel>>
}
};
theme: GuiTheme = GuiTheme.DARK;
theme: GuiTheme = typeof window !== 'undefined' ? (localStorage.getItem('theme') === 'dark' ? GuiTheme.DARK : GuiTheme.FABRIC) : GuiTheme.DARK;
private themeSubscription: Subscription = new Subscription();

View File

@@ -1,23 +0,0 @@
import { Component, Inject, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { AuthenticationService } from '../services/authentication.service';
import { RefreshService } from '../services/refresh.service';
@Component({
standalone: true,
selector: 'app-home',
templateUrl: './home.component.html',
//styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
username: string = '';
password: string = '';
constructor(private authService: AuthenticationService, private router: Router, rService: RefreshService) {
rService.removeAll()
}
ngOnInit(): void {
}
}

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { BasePageComponent } from './base-page.component';
describe('BasePageComponent', () => {
let component: BasePageComponent;
let fixture: ComponentFixture<BasePageComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [BasePageComponent]
})
.compileComponents();
fixture = TestBed.createComponent(BasePageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,26 @@
import { Component, inject } from '@angular/core';
import { RefreshService } from '../../services/refresh.service';
import { CreationService } from '../../services/creation.service';
import { UpdateService } from '../../services/update.service';
@Component({
selector: 'app-base-page',
standalone: true,
imports: [],
templateUrl: './base-page.component.html',
styleUrl: './base-page.component.scss'
})
export class BasePageComponent {
protected refreshService: RefreshService = inject(RefreshService)
protected creationService: CreationService = inject(CreationService)
protected updateService: UpdateService = inject(UpdateService)
constructor() {
this.refreshService.removeAll()
this.creationService.disposeComponent();
if (this.updateService.any) {
this.updateService.executeAll().then()
}
}
}

View File

@@ -3,7 +3,7 @@
<div class="col-6">
<mat-tab-group>
<mat-tab label="Gruppen">
<app-group-table #groupTable [onSelectedRows]="groupsOnSelectedRows"></app-group-table>
<app-group-table #groupTable [onSelectedRows]="groupsOnSelectedRows" [cellEditing]="cellEditing"></app-group-table>
</mat-tab>
</mat-tab-group>
</div>

View File

@@ -1,11 +1,12 @@
import { AfterViewInit, Component, ViewChild } from '@angular/core';
import { GroupTableComponent } from '../../components/tables/group-table/group-table.component';
import { UserTableComponent } from '../../components/tables/user-table/user-table.component';
import { RefreshService } from '../../services/refresh.service';
import { MatTabsModule } from '@angular/material/tabs';
import { GuiSelectedRow } from '@generic-ui/ngx-grid';
import { CreationService } from '../../services/creation.service';
import { GroupFormComponent } from '../forms/group-form/group-form.component';
import { GuiCellEdit, GuiSelectedRow } from '@generic-ui/ngx-grid';
import { GroupFormComponent } from '../../components/forms/group-form/group-form.component';
import { BasePageComponent } from '../base-page/base-page.component';
import { Group } from '../../models/user-management.api.models';
import { firstValueFrom } from 'rxjs';
@Component({
standalone: true,
@@ -14,16 +15,29 @@ import { GroupFormComponent } from '../forms/group-form/group-form.component';
templateUrl: './group.component.html',
styleUrl: './group.component.css'
})
export class GroupComponent implements AfterViewInit {
export class GroupComponent extends BasePageComponent implements AfterViewInit {
initWithoutData = () => { }
cellEditing: GuiCellEdit = {
enabled: true,
cellEdit: (value: any, item: Group, index: number) => {
if (!this.updateService.isEditable)
return false;
this.updateService.setAsync("group_" + item.id!.toString(), async () => {
await firstValueFrom(this.groupTable.service.update(item))
})
return true;
}
}
private sGroupId = null;
constructor(private refreshService: RefreshService, private creationService: CreationService) { }
ngAfterViewInit(): void {
this.refreshService.removeAll()
this.refreshService.add(() => {
this.groupTable.fetchData();
if(this.sGroupId)
if (this.sGroupId)
this.userTable.fetchDataByGroupId(this.sGroupId);
});
this.creationService.component = GroupFormComponent
@@ -33,10 +47,10 @@ export class GroupComponent implements AfterViewInit {
@ViewChild("userTable") userTable!: UserTableComponent;
groupsOnSelectedRows = (rows: GuiSelectedRow[]) => {
if(rows.length > 0){
if (rows.length > 0) {
this.sGroupId = rows[0].source.id;
if(this.sGroupId)
if (this.sGroupId)
this.userTable.fetchDataByGroupId(this.sGroupId);
}
}
}
}

View File

@@ -0,0 +1,10 @@
import { Component } from '@angular/core';
import { BasePageComponent } from '../base-page/base-page.component';
@Component({
standalone: true,
selector: 'app-home',
templateUrl: './home.component.html'
})
export class HomeComponent extends BasePageComponent {
}

View File

@@ -2,8 +2,9 @@ import { AfterViewInit, Component, ViewChild } from '@angular/core';
import { ModuleTableComponent } from '../../components/tables/module-table/module-table.component';
import { RefreshService } from '../../services/refresh.service';
import { MatTabsModule } from '@angular/material/tabs';
import { UserTableComponent } from '../tables/user-table/user-table.component';
import { UserTableComponent } from '../../components/tables/user-table/user-table.component';
import { GuiSelectedRow } from '@generic-ui/ngx-grid';
import { BasePageComponent } from '../base-page/base-page.component';
@Component({
standalone: true,
@@ -12,11 +13,10 @@ import { GuiSelectedRow } from '@generic-ui/ngx-grid';
templateUrl: './module.component.html',
styleUrl: './module.component.css'
})
export class ModuleComponent implements AfterViewInit {
export class ModuleComponent extends BasePageComponent implements AfterViewInit {
private uModuleId = null;
constructor(private refreshService: RefreshService) { }
initWithoutData = () => { }
ngAfterViewInit(): void {
this.refreshService.removeAll()

View File

@@ -1,12 +1,12 @@
import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core';
import { TabItem } from '../common/tab-card/tab-card.component';
import { TabItem } from '../../components/common/tab-card/tab-card.component';
import { GuiRowSelection, GuiRowSelectionMode, GuiRowSelectionType, GuiSelectedRow } from '@generic-ui/ngx-grid';
import { UserTableComponent } from '../tables/user-table/user-table.component';
import { ModuleTableComponent } from '../tables/module-table/module-table.component';
import { GroupTableComponent } from '../tables/group-table/group-table.component';
import { UserTableComponent } from '../../components/tables/user-table/user-table.component';
import { ModuleTableComponent } from '../../components/tables/module-table/module-table.component';
import { GroupTableComponent } from '../../components/tables/group-table/group-table.component';
import { User } from '../../models/user-management.api.models';
import { MatTabsModule, MatTabGroup } from '@angular/material/tabs';
import { RefreshService } from '../../services/refresh.service';
import { BasePageComponent } from '../base-page/base-page.component';
@Component({
standalone: true,
@@ -15,7 +15,7 @@ import { RefreshService } from '../../services/refresh.service';
templateUrl: './user-assignment.component.html',
styleUrl: './user-assignment.component.scss'
})
export class UserAssignmentComponent implements OnInit, AfterViewInit {
export class UserAssignmentComponent extends BasePageComponent implements OnInit, AfterViewInit {
initWithoutData = () => { }
@@ -47,8 +47,6 @@ export class UserAssignmentComponent implements OnInit, AfterViewInit {
private anySelected: boolean = false;
constructor(private refreshService: RefreshService) { }
ngOnInit(): void { }
ngAfterViewInit(): void {

View File

@@ -1,13 +1,14 @@
import { AfterViewInit, Component, Inject, ViewChild } from '@angular/core';
import { GuiColumn, GuiSelectedRow } from '@generic-ui/ngx-grid/gui/grid/src/core/api/gui.grid.public-api';
import { UserTableComponent } from '../tables/user-table/user-table.component';
import { UserRepTableComponent } from '../tables/user-rep-table/user-rep-table.component';
import { GroupTableComponent } from '../tables/group-table/group-table.component';
import { UserTableComponent } from '../../components/tables/user-table/user-table.component';
import { UserRepTableComponent } from '../../components/tables/user-rep-table/user-rep-table.component';
import { GroupTableComponent } from '../../components/tables/group-table/group-table.component';
import { UserRepService } from '../../services/user-representation.service';
import Swal from 'sweetalert2';
import { MatTabsModule, MatTabGroup } from '@angular/material/tabs';
import { env } from '../../../environments/environment';
import { RefreshService } from '../../services/refresh.service';
import { BasePageComponent } from '../base-page/base-page.component';
@Component({
standalone: true,
@@ -16,7 +17,7 @@ import { RefreshService } from '../../services/refresh.service';
templateUrl: './user-representation.component.html',
styleUrl: './user-representation.component.css'
})
export class UserRepresentationComponent implements AfterViewInit {
export class UserRepresentationComponent extends BasePageComponent implements AfterViewInit {
useRepLabel: string = "";
groupRepCols: Array<GuiColumn>;
@@ -29,7 +30,8 @@ export class UserRepresentationComponent implements AfterViewInit {
initWithoutData = () => { }
constructor(private userRepService: UserRepService, private refreshService: RefreshService) {
constructor(private userRepService: UserRepService) {
super()
this.groupRepCols = env.columnNames.group.representative;
this.groupRightColumns = env.columnNames.group.right;
this.userRepService = userRepService;

View File

@@ -1,12 +1,15 @@
import { AfterViewInit, Component, ViewChild } from '@angular/core';
import { GuiCellEdit, GuiSelectedRow } from '@generic-ui/ngx-grid';
import { UserTableComponent } from '../tables/user-table/user-table.component';
import { UserTableComponent } from '../../components/tables/user-table/user-table.component';
import { RefreshService } from '../../services/refresh.service';
import { MatTabsModule } from '@angular/material/tabs';
import { GroupTableComponent } from '../../components/tables/group-table/group-table.component';
import { ModuleTableComponent } from '../../components/tables/module-table/module-table.component';
import { CreationService } from '../../services/creation.service';
import { UserFormComponent } from '../../components/forms/user-form/user-form.component';
import { BasePageComponent } from '../base-page/base-page.component';
import { User } from '../../models/user-management.api.models';
import { firstValueFrom } from 'rxjs';
@Component({
standalone: true,
@@ -15,23 +18,24 @@ import { UserFormComponent } from '../../components/forms/user-form/user-form.co
templateUrl: './user.component.html',
styleUrl: './user.component.css'
})
export class UserComponent implements AfterViewInit {
export class UserComponent extends BasePageComponent implements AfterViewInit {
initWithoutData = () => { }
cellEditing: GuiCellEdit = {
enabled: true,
rowEdit: (value: any, item: any, index: number) => {
return true;
},
cellEdit: (value: any, item: any, index: number) => {
cellEdit: (value: any, item: User, index: number) => {
if (!this.updateService.isEditable)
return false;
this.updateService.setAsync("user_" + item.id!.toString(), async () => {
await firstValueFrom(this.userTable.service.update(item))
})
return true;
}
}
private sUsername = null;
constructor(private refreshService: RefreshService, private creationService: CreationService) { }
ngAfterViewInit(): void {
this.refreshService.removeAll()
this.refreshService.add(() => {

View File

@@ -17,6 +17,8 @@ export class ColorModeService {
}
setTheme(theme: Theme) {
if (typeof window !== 'undefined')
localStorage.setItem('theme', theme)
this.updateTheme();
}
@@ -75,7 +77,7 @@ export const ParseTheme: (value: string) => Theme | undefined = (value: string)
}
export function GetLocalTheme(): Theme {
let sTheme: string | null = 'dark';
let sTheme: string | null = (typeof window !== 'undefined') ? (localStorage.getItem('theme')) : 'dark';
if (sTheme === null)
return Theme.Dark;

View File

@@ -20,4 +20,8 @@ export class CreationService {
})
: undefined;
}
disposeComponent(){
this.component = undefined;
}
}

View File

@@ -1,11 +1,12 @@
import { Injectable } from '@angular/core';
import { UpdateService } from './update.service';
@Injectable({
providedIn: 'root'
})
export class RefreshService {
constructor() { }
constructor(private updateService: UpdateService) { }
private actions: Array<() => void> = [];
@@ -19,5 +20,6 @@ export class RefreshService {
executeAll(): void {
this.actions.forEach(action => action());
this.updateService.removeAll()
}
}

View File

@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { UpdateService } from './update.service';
describe('UpdateService', () => {
let service: UpdateService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(UpdateService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@@ -0,0 +1,92 @@
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class UpdateService {
constructor() { }
private async_actions: { [key: string]: () => Promise<void> } = {};
private actions: { [key: string]: () => void } = {};
get asyncCount(): number {
return Object.keys(this.async_actions).length;
}
get syncCount(): number {
return Object.keys(this.actions).length;
}
get totalCount(): number {
return this.asyncCount + this.syncCount;
}
get any(): boolean {
return this.totalCount > 0;
}
//add - remove - executeA
setAsync(key: string, action: () => Promise<void>): void {
const keyWasPresent = this.async_actions.hasOwnProperty(key);
this.async_actions[key] = action;
if (!keyWasPresent)
this.executeCountChangeListeners();
}
set(key: string, action: () => void): void {
const keyWasPresent = this.actions.hasOwnProperty(key);
this.actions[key] = action;
if (!keyWasPresent)
this.executeCountChangeListeners();
}
removeAll(): void {
if (this.any) {
this.async_actions = {};
this.actions = {};
this.executeCountChangeListeners();
}
}
async executeAll(): Promise<void> {
await Promise.all(Object.values(this.async_actions).map(action => action()));
Object.values(this.actions).forEach(action => action());
this.removeAll();
}
//change listeners
//count
private countChangeListeners: Array<() => void> = new Array();
private executeCountChangeListeners() {
this.countChangeListeners.forEach(e => e());
}
addChangeListener(eventType: UpdateEvent, action: () => void) {
switch (eventType) {
case UpdateEvent.CountChange:
this.countChangeListeners.push(action)
break;
}
}
removeAllChangeListeners() {
this.countChangeListeners = []
}
//cell edit
private _isEditable: boolean = (typeof window !== 'undefined') ? (localStorage.getItem('editable') === "T") : true;
public get isEditable(): boolean {
return this._isEditable;
}
public set isEditable(value: boolean) {
if (typeof window !== 'undefined')
localStorage.setItem('editable', value ? "T" : "F")
this._isEditable = value;
}
}
export enum UpdateEvent {
CountChange
}