Handle redirects & First design steps

This commit is contained in:
Sven Heidemann 2024-12-14 18:43:51 +01:00
parent 7b8e818339
commit 99960572ea
120 changed files with 1948 additions and 1537 deletions

View File

@ -1,16 +1,27 @@
from flask import redirect
from flask import redirect, jsonify
from api.route import Route
from core.logger import Logger
from data.schemas.public.short_url import ShortUrl
from data.schemas.public.short_url_dao import shortUrlDao
BasePath = f"/"
logger = Logger(__name__)
@Route.get(f"{BasePath}/<path:path>")
@Route.get(f"/api/find/<path:path>")
async def find(path: str):
from_db = await shortUrlDao.find_single_by({ShortUrl.short_url: path})
if from_db is None:
return jsonify(None)
return jsonify(from_db.to_dto())
@Route.get(f"/api/redirect/<path:path>")
async def handle_short_url(path: str):
if path.startswith("api/"):
path = path.replace("api/", "")
from_db = await shortUrlDao.find_single_by({ShortUrl.short_url: path})
if from_db is None:
return {"error": "Short URL not found"}, 404

View File

@ -22,7 +22,7 @@ class FilterABC[T](ABC):
filter_type: Union[Type["FilterABC"], Type[Union[int, str, bool, datetime]]],
db_name=None,
):
if field not in self._obj:
if field not in self._obj and db_name not in self._obj:
return
if db_name is None:

View File

@ -8,6 +8,8 @@ type Group implements DbModel {
id: ID
name: String
shortUrls: [ShortUrl]
deleted: Boolean
editor: User
createdUtc: String

View File

@ -21,7 +21,6 @@ input ShortUrlSort {
id: SortOrder
name: SortOrder
description: SortOrder
group: GroupSort
deleted: SortOrder
editorId: SortOrder
@ -33,7 +32,6 @@ input ShortUrlFilter {
id: IntFilter
name: StringFilter
description: StringFilter
group: GroupFilter
deleted: BooleanFilter
editor: IntFilter

View File

@ -1,4 +1,7 @@
from api_graphql.abc.db_model_query_abc import DbModelQueryABC
from data.schemas.public.group import Group
from data.schemas.public.short_url import ShortUrl
from data.schemas.public.short_url_dao import shortUrlDao
class GroupQuery(DbModelQueryABC):
@ -6,3 +9,8 @@ class GroupQuery(DbModelQueryABC):
DbModelQueryABC.__init__(self, "Group")
self.set_field("name", lambda x, *_: x.name)
self.set_field("shortUrls", self._get_urls)
@staticmethod
async def _get_urls(group: Group, *_):
return await shortUrlDao.find_by({ShortUrl.group_id: group.id})

View File

@ -85,7 +85,13 @@ class Query(QueryABC):
.with_dao(groupDao)
.with_filter(GroupFilter)
.with_sort(Sort[Group])
.with_require_any_permission([Permissions.groups, Permissions.short_urls_create, Permissions.short_urls_update])
.with_require_any_permission(
[
Permissions.groups,
Permissions.short_urls_create,
Permissions.short_urls_update,
]
)
)
# partially public to load redirect if not resolved/redirected by api
self.field(

View File

@ -5,6 +5,7 @@ from async_property import async_property
from core.database.abc.db_model_abc import DbModelABC
from core.typing import SerialId
from data.schemas.public.group import Group
class ShortUrl(DbModelABC):
@ -59,7 +60,16 @@ class ShortUrl(DbModelABC):
self._group_id = value
@async_property
async def group(self):
async def group(self) -> Optional[Group]:
if self._group_id is None:
return None
from data.schemas.public.group_dao import groupDao
return await groupDao.get_by_id(self._group_id)
def to_dto(self) -> dict:
return {
"id": self.id,
"target_url": self.target_url,
}

View File

@ -1,34 +1,23 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { NotFoundComponent } from 'src/app/components/error/not-found/not-found.component';
import { AuthGuard } from 'src/app/core/guard/auth.guard';
import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";
import { NotFoundComponent } from "src/app/components/error/not-found/not-found.component";
import { AuthGuard } from "src/app/core/guard/auth.guard";
import { HomeComponent } from "src/app/components/home/home.component";
import { RedirectComponent } from "src/app/components/redirect/redirect.component";
const routes: Routes = [
{
path: '',
redirectTo: 'home',
pathMatch: 'full',
},
{
path: 'about',
redirectTo: 'home',
},
{
path: 'home',
path: "",
component: HomeComponent,
},
{
path: 'admin',
path: "admin",
loadChildren: () =>
import('./modules/admin/admin.module').then(m => m.AdminModule),
import("./modules/admin/admin.module").then((m) => m.AdminModule),
canActivate: [AuthGuard],
},
{ path: '404', component: NotFoundComponent },
{
path: '**',
redirectTo: '404',
},
{ path: "404", component: NotFoundComponent },
{ path: "**", component: RedirectComponent },
];
@NgModule({

View File

@ -1,4 +1,4 @@
<main>
<main *ngIf="isLoggedIn; else home">
<app-header></app-header>
<div class="app">
@ -30,3 +30,7 @@
</p-confirmDialog>
</main>
<app-spinner></app-spinner>
<ng-template #home>
<router-outlet></router-outlet>
</ng-template>

View File

@ -1,22 +1,22 @@
import { TestBed } from '@angular/core/testing';
import { ActivatedRoute } from '@angular/router';
import { AppComponent } from './app.component';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { TranslateModule } from '@ngx-translate/core';
import { AuthService } from 'src/app/service/auth.service';
import { KeycloakService } from 'keycloak-angular';
import { ErrorHandlingService } from 'src/app/service/error-handling.service';
import { ToastService } from 'src/app/service/toast.service';
import { ConfirmationService, MessageService } from 'primeng/api';
import { of } from 'rxjs';
import { HomeComponent } from 'src/app/components/home/home.component';
import { FooterComponent } from 'src/app/components/footer/footer.component';
import { HeaderComponent } from 'src/app/components/header/header.component';
import { NotFoundComponent } from 'src/app/components/error/not-found/not-found.component';
import { SpinnerComponent } from 'src/app/components/spinner/spinner.component';
import { SidebarComponent } from 'src/app/components/sidebar/sidebar.component';
import { TestBed } from "@angular/core/testing";
import { ActivatedRoute } from "@angular/router";
import { AppComponent } from "./app.component";
import { SharedModule } from "src/app/modules/shared/shared.module";
import { TranslateModule } from "@ngx-translate/core";
import { AuthService } from "src/app/service/auth.service";
import { KeycloakService } from "keycloak-angular";
import { ErrorHandlingService } from "src/app/service/error-handling.service";
import { ToastService } from "src/app/service/toast.service";
import { ConfirmationService, MessageService } from "primeng/api";
import { of } from "rxjs";
import { HomeComponent } from "src/app/components/home/home.component";
import { FooterComponent } from "src/app/components/footer/footer.component";
import { HeaderComponent } from "src/app/components/header/header.component";
import { NotFoundComponent } from "src/app/components/error/not-found/not-found.component";
import { SpinnerComponent } from "src/app/components/spinner/spinner.component";
import { SidebarComponent } from "src/app/components/sidebar/sidebar.component";
describe('AppComponent', () => {
describe("AppComponent", () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [
@ -46,7 +46,7 @@ describe('AppComponent', () => {
}).compileComponents();
});
it('should create the app', () => {
it("should create the app", () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();

View File

@ -1,27 +1,32 @@
import { Component, OnDestroy } from '@angular/core';
import { SidebarService } from 'src/app/service/sidebar.service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { AuthService } from 'src/app/service/auth.service';
import { Component, OnDestroy } from "@angular/core";
import { SidebarService } from "src/app/service/sidebar.service";
import { Subject } from "rxjs";
import { takeUntil } from "rxjs/operators";
import { AuthService } from "src/app/service/auth.service";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.scss',
selector: "app-root",
templateUrl: "./app.component.html",
styleUrl: "./app.component.scss",
})
export class AppComponent implements OnDestroy {
showSidebar = false;
isLoggedIn = false;
unsubscribe$ = new Subject<void>();
constructor(
private sidebar: SidebarService,
private auth: AuthService
private auth: AuthService,
) {
this.auth.loadUser();
this.auth.user$.pipe(takeUntil(this.unsubscribe$)).subscribe((user) => {
this.isLoggedIn = user !== null && user !== undefined;
});
this.sidebar.visible$
.pipe(takeUntil(this.unsubscribe$))
.subscribe(visible => {
.subscribe((visible) => {
this.showSidebar = visible;
});
}

View File

@ -1,26 +1,27 @@
import { APP_INITIALIZER, ErrorHandler, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { APP_INITIALIZER, ErrorHandler, NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { KeycloakService } from 'keycloak-angular';
import { HomeComponent } from './components/home/home.component';
import { initializeKeycloak } from './core/init-keycloak';
import { HttpClient } from '@angular/common/http';
import { environment } from '../environments/environment';
import { FooterComponent } from 'src/app/components/footer/footer.component';
import { HeaderComponent } from 'src/app/components/header/header.component';
import { NotFoundComponent } from 'src/app/components/error/not-found/not-found.component';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { Logger } from 'src/app/service/logger.service';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { SpinnerComponent } from 'src/app/components/spinner/spinner.component';
import { ConfirmationService, MessageService } from 'primeng/api';
import { DialogService } from 'primeng/dynamicdialog';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { SidebarComponent } from './components/sidebar/sidebar.component';
import { ErrorHandlingService } from 'src/app/service/error-handling.service';
import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
import { KeycloakService } from "keycloak-angular";
import { initializeKeycloak } from "./core/init-keycloak";
import { HttpClient } from "@angular/common/http";
import { environment } from "../environments/environment";
import { FooterComponent } from "src/app/components/footer/footer.component";
import { HeaderComponent } from "src/app/components/header/header.component";
import { NotFoundComponent } from "src/app/components/error/not-found/not-found.component";
import { TranslateLoader, TranslateModule } from "@ngx-translate/core";
import { TranslateHttpLoader } from "@ngx-translate/http-loader";
import { Logger } from "src/app/service/logger.service";
import { SharedModule } from "src/app/modules/shared/shared.module";
import { SpinnerComponent } from "src/app/components/spinner/spinner.component";
import { ConfirmationService, MessageService } from "primeng/api";
import { DialogService } from "primeng/dynamicdialog";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { SidebarComponent } from "./components/sidebar/sidebar.component";
import { ErrorHandlingService } from "src/app/service/error-handling.service";
import { HomeComponent } from "./components/home/home.component";
import { RedirectComponent } from "./components/redirect/redirect.component";
if (environment.production) {
Logger.enableProductionMode();
@ -35,12 +36,13 @@ export function HttpLoaderFactory(http: HttpClient) {
@NgModule({
declarations: [
AppComponent,
HomeComponent,
FooterComponent,
HeaderComponent,
NotFoundComponent,
SpinnerComponent,
SidebarComponent,
HomeComponent,
RedirectComponent,
],
imports: [
BrowserModule,
@ -48,7 +50,7 @@ export function HttpLoaderFactory(http: HttpClient) {
AppRoutingModule,
SharedModule,
TranslateModule.forRoot({
defaultLanguage: 'en',
defaultLanguage: "en",
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,

View File

@ -1,9 +1,9 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { NotFoundComponent } from 'src/app/components/error/not-found/not-found.component';
import { TranslateModule } from '@ngx-translate/core';
import { NotFoundComponent } from "src/app/components/error/not-found/not-found.component";
import { TranslateModule } from "@ngx-translate/core";
describe('NotFoundComponent', () => {
describe("NotFoundComponent", () => {
let component: NotFoundComponent;
let fixture: ComponentFixture<NotFoundComponent>;
@ -20,7 +20,7 @@ describe('NotFoundComponent', () => {
fixture.detectChanges();
});
it('should create', () => {
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,8 +1,8 @@
import { Component } from '@angular/core';
import { Component } from "@angular/core";
@Component({
selector: 'app-not-found',
templateUrl: './not-found.component.html',
styleUrls: ['./not-found.component.scss'],
selector: "app-not-found",
templateUrl: "./not-found.component.html",
styleUrls: ["./not-found.component.scss"],
})
export class NotFoundComponent {}

View File

@ -1,12 +1,12 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { FooterComponent } from 'src/app/components/footer/footer.component';
import { TranslateModule } from '@ngx-translate/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { FooterComponent } from "src/app/components/footer/footer.component";
import { TranslateModule } from "@ngx-translate/core";
import { BrowserModule } from "@angular/platform-browser";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { SharedModule } from "src/app/modules/shared/shared.module";
describe('FooterComponent', () => {
describe("FooterComponent", () => {
let component: FooterComponent;
let fixture: ComponentFixture<FooterComponent>;
@ -28,7 +28,7 @@ describe('FooterComponent', () => {
fixture.detectChanges();
});
it('should create', () => {
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,10 +1,10 @@
import { Component } from '@angular/core';
import { SettingsService } from 'src/app/service/settings.service';
import { Component } from "@angular/core";
import { SettingsService } from "src/app/service/settings.service";
@Component({
selector: 'app-footer',
templateUrl: './footer.component.html',
styleUrls: ['./footer.component.scss'],
selector: "app-footer",
templateUrl: "./footer.component.html",
styleUrls: ["./footer.component.scss"],
})
export class FooterComponent {
constructor(private settings: SettingsService) {}

View File

@ -1,6 +1,12 @@
<header>
<div class="header">
<div class="flex items-center justify-center">
<p-button
*ngIf="user"
icon="pi pi-bars"
class="btn icon-btn p-button-text"
(onClick)="toggleSidebar()"
></p-button>
</div>
<div class="logo">
<!-- <img src="/assets/images/logo.svg" alt="logo"/>-->

View File

@ -1,16 +1,16 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HeaderComponent } from 'src/app/components/header/header.component';
import { TranslateModule } from '@ngx-translate/core';
import { ConfirmationService, MessageService } from 'primeng/api';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { ErrorHandlingService } from 'src/app/service/error-handling.service';
import { ToastService } from 'src/app/service/toast.service';
import { AuthService } from 'src/app/service/auth.service';
import { KeycloakService } from 'keycloak-angular';
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { HeaderComponent } from "src/app/components/header/header.component";
import { TranslateModule } from "@ngx-translate/core";
import { ConfirmationService, MessageService } from "primeng/api";
import { ActivatedRoute } from "@angular/router";
import { of } from "rxjs";
import { SharedModule } from "src/app/modules/shared/shared.module";
import { ErrorHandlingService } from "src/app/service/error-handling.service";
import { ToastService } from "src/app/service/toast.service";
import { AuthService } from "src/app/service/auth.service";
import { KeycloakService } from "keycloak-angular";
describe('HeaderComponent', () => {
describe("HeaderComponent", () => {
let component: HeaderComponent;
let fixture: ComponentFixture<HeaderComponent>;
@ -41,7 +41,7 @@ describe('HeaderComponent', () => {
fixture.detectChanges();
});
it('should create', () => {
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,17 +1,18 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { MenuItem, PrimeNGConfig } from 'primeng/api';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { TranslateService } from '@ngx-translate/core';
import { GuiService } from 'src/app/service/gui.service';
import { User } from 'src/app/model/auth/user';
import { AuthService } from 'src/app/service/auth.service';
import { MenuElement } from 'src/app/model/view/menu-element';
import { Component, OnDestroy, OnInit } from "@angular/core";
import { MenuItem, PrimeNGConfig } from "primeng/api";
import { Subject } from "rxjs";
import { takeUntil } from "rxjs/operators";
import { TranslateService } from "@ngx-translate/core";
import { GuiService } from "src/app/service/gui.service";
import { User } from "src/app/model/auth/user";
import { AuthService } from "src/app/service/auth.service";
import { MenuElement } from "src/app/model/view/menu-element";
import { SidebarService } from "src/app/service/sidebar.service";
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss'],
selector: "app-header",
templateUrl: "./header.component.html",
styleUrls: ["./header.component.scss"],
})
export class HeaderComponent implements OnInit, OnDestroy {
langList: MenuItem[] = [];
@ -26,15 +27,21 @@ export class HeaderComponent implements OnInit, OnDestroy {
private translateService: TranslateService,
private config: PrimeNGConfig,
private guiService: GuiService,
private auth: AuthService
private auth: AuthService,
private sidebarService: SidebarService,
) {
this.guiService.isMobile$
.pipe(takeUntil(this.unsubscribe$))
.subscribe(isMobile => {
.subscribe((isMobile) => {
this.isMobile = isMobile;
if (isMobile) {
this.sidebarService.hide();
}
});
this.auth.user$.pipe(takeUntil(this.unsubscribe$)).subscribe(async user => {
this.auth.user$
.pipe(takeUntil(this.unsubscribe$))
.subscribe(async (user) => {
this.user = user;
await this.initMenuLists();
});
@ -55,49 +62,24 @@ export class HeaderComponent implements OnInit, OnDestroy {
}
async initMenuLists() {
await this.initMenuList();
await this.initLangMenuList();
await this.initUserMenuList();
}
async initMenuList() {
this.menu = [
{
label: 'common.news',
routerLink: ['/'],
icon: 'pi pi-home',
},
{
label: 'header.menu.about',
routerLink: ['/about'],
icon: 'pi pi-info',
},
];
if (this.auth.user$.value) {
this.menu.push({
label: 'header.menu.admin',
routerLink: ['/admin'],
icon: 'pi pi-cog',
visible: await this.auth.isAdmin(),
});
}
}
async initLangMenuList() {
this.langList = [
{
label: 'English',
label: "English",
command: () => {
this.translate('en');
this.setLang('en');
this.translate("en");
this.setLang("en");
},
},
{
label: 'Deutsch',
label: "Deutsch",
command: () => {
this.translate('de');
this.setLang('de');
this.translate("de");
this.setLang("de");
},
},
];
@ -114,13 +96,13 @@ export class HeaderComponent implements OnInit, OnDestroy {
separator: true,
},
{
label: this.translateService.instant('header.logout'),
label: this.translateService.instant("header.logout"),
command: () => {
this.auth.logout().then(() => {
console.log('logout');
console.log("logout");
});
},
icon: 'pi pi-sign-out',
icon: "pi pi-sign-out",
},
];
}
@ -128,18 +110,27 @@ export class HeaderComponent implements OnInit, OnDestroy {
translate(lang: string) {
this.translateService.use(lang);
this.translateService
.get('primeng')
.subscribe(res => this.config.setTranslation(res));
.get("primeng")
.subscribe((res) => this.config.setTranslation(res));
}
async loadLang() {
const lang = 'en';
const lang = "en";
this.setLang(lang);
this.translate(lang);
}
setLang(lang: string) {
// this.settings.setSetting(`lang`, lang);
console.log('setLang', lang);
console.log("setLang", lang);
}
toggleSidebar() {
if (this.sidebarService.visible$.value) {
this.sidebarService.hide();
return;
}
this.sidebarService.show();
}
}

View File

@ -1 +0,0 @@
<p>home works!</p>

View File

@ -1,8 +1,8 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { HomeComponent } from './home.component';
import { HomeComponent } from "./home.component";
describe('HomeComponent', () => {
describe("HomeComponent", () => {
let component: HomeComponent;
let fixture: ComponentFixture<HomeComponent>;
@ -16,7 +16,7 @@ describe('HomeComponent', () => {
fixture.detectChanges();
});
it('should create', () => {
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,8 +1,17 @@
import { Component } from '@angular/core';
import { Component } from "@angular/core";
import { AuthService } from "src/app/service/auth.service";
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrl: './home.component.scss',
selector: "app-home",
templateUrl: "./home.component.html",
styleUrl: "./home.component.scss",
})
export class HomeComponent {}
export class HomeComponent {
constructor(private auth: AuthService) {
if (this.auth.user$.value !== undefined) {
return;
}
this.auth.login().then(() => {});
}
}

View File

@ -0,0 +1 @@
<p>redirect works!</p>

View File

@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { RedirectComponent } from "./redirect.component";
describe("RedirectComponent", () => {
let component: RedirectComponent;
let fixture: ComponentFixture<RedirectComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [RedirectComponent],
}).compileComponents();
fixture = TestBed.createComponent(RedirectComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,47 @@
import { Component, OnInit } from "@angular/core";
import { SidebarService } from "src/app/service/sidebar.service";
import { Router } from "@angular/router";
import { HttpClient } from "@angular/common/http";
import { environment } from "src/environments/environment";
import { ShortUrlDto } from "src/app/model/entities/short-url";
@Component({
selector: "app-redirect",
templateUrl: "./redirect.component.html",
styleUrl: "./redirect.component.scss",
})
export class RedirectComponent implements OnInit {
constructor(
private sidebar: SidebarService,
private router: Router,
private http: HttpClient,
) {
this.sidebar.hide();
}
ngOnInit() {
this.handleUrl();
}
handleUrl() {
let shortUrl = this.router.url;
if (shortUrl === "/") {
return;
}
if (shortUrl.startsWith("/")) {
shortUrl = shortUrl.substring(1);
}
this.http
.get<ShortUrlDto | undefined>(`${environment.api.url}/find/${shortUrl}`)
.subscribe(async (response) => {
if (!response) {
await this.router.navigate(["/404"]);
return;
}
window.location.href = `${environment.api.url}/redirect/${shortUrl}`;
});
}
}

View File

@ -1,17 +1,17 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { SidebarComponent } from './sidebar.component';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { TranslateModule } from '@ngx-translate/core';
import { AuthService } from 'src/app/service/auth.service';
import { ErrorHandlingService } from 'src/app/service/error-handling.service';
import { ToastService } from 'src/app/service/toast.service';
import { ConfirmationService, MessageService } from 'primeng/api';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';
import { KeycloakService } from 'keycloak-angular';
import { SidebarComponent } from "./sidebar.component";
import { SharedModule } from "src/app/modules/shared/shared.module";
import { TranslateModule } from "@ngx-translate/core";
import { AuthService } from "src/app/service/auth.service";
import { ErrorHandlingService } from "src/app/service/error-handling.service";
import { ToastService } from "src/app/service/toast.service";
import { ConfirmationService, MessageService } from "primeng/api";
import { ActivatedRoute } from "@angular/router";
import { of } from "rxjs";
import { KeycloakService } from "keycloak-angular";
describe('SidebarComponent', () => {
describe("SidebarComponent", () => {
let component: SidebarComponent;
let fixture: ComponentFixture<SidebarComponent>;
@ -40,7 +40,7 @@ describe('SidebarComponent', () => {
fixture.detectChanges();
});
it('should create', () => {
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,13 +1,13 @@
import {Component, OnDestroy} from '@angular/core';
import {MenuElement} from 'src/app/model/view/menu-element';
import {Subject} from 'rxjs';
import {SidebarService} from 'src/app/service/sidebar.service';
import {takeUntil} from 'rxjs/operators';
import { Component, OnDestroy } from "@angular/core";
import { MenuElement } from "src/app/model/view/menu-element";
import { Subject } from "rxjs";
import { SidebarService } from "src/app/service/sidebar.service";
import { takeUntil } from "rxjs/operators";
@Component({
selector: 'app-sidebar',
templateUrl: './sidebar.component.html',
styleUrl: './sidebar.component.scss',
selector: "app-sidebar",
templateUrl: "./sidebar.component.html",
styleUrl: "./sidebar.component.scss",
})
export class SidebarComponent implements OnDestroy {
elements: MenuElement[] = [];
@ -17,7 +17,7 @@ export class SidebarComponent implements OnDestroy {
constructor(private sidebar: SidebarService) {
this.sidebar.elements$
.pipe(takeUntil(this.unsubscribe$))
.subscribe(elements => {
.subscribe((elements) => {
this.elements = elements;
});
}

View File

@ -1,8 +1,8 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { SpinnerComponent } from 'src/app/components/spinner/spinner.component';
import { SpinnerComponent } from "src/app/components/spinner/spinner.component";
describe('SpinnerComponent', () => {
describe("SpinnerComponent", () => {
let component: SpinnerComponent;
let fixture: ComponentFixture<SpinnerComponent>;
@ -18,7 +18,7 @@ describe('SpinnerComponent', () => {
fixture.detectChanges();
});
it('should create', () => {
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,16 +1,16 @@
import { Component } from '@angular/core';
import { SpinnerService } from 'src/app/service/spinner.service';
import { Component } from "@angular/core";
import { SpinnerService } from "src/app/service/spinner.service";
@Component({
selector: 'app-spinner',
templateUrl: './spinner.component.html',
styleUrls: ['./spinner.component.scss'],
selector: "app-spinner",
templateUrl: "./spinner.component.html",
styleUrls: ["./spinner.component.scss"],
})
export class SpinnerComponent {
showSpinnerState = false;
constructor(public spinnerService: SpinnerService) {
this.spinnerService.showSpinnerState$.subscribe(value => {
this.spinnerService.showSpinnerState$.subscribe((value) => {
this.showSpinnerState = value;
});
}

View File

@ -1,9 +1,9 @@
import { Directive, inject } from '@angular/core';
import { PageDataService } from 'src/app/core/base/page.data.service';
import { SpinnerService } from 'src/app/service/spinner.service';
import { FilterService } from 'src/app/service/filter.service';
import { FormGroup } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { Directive, inject } from "@angular/core";
import { PageDataService } from "src/app/core/base/page.data.service";
import { SpinnerService } from "src/app/service/spinner.service";
import { FilterService } from "src/app/service/filter.service";
import { FormGroup } from "@angular/forms";
import { ActivatedRoute, Router } from "@angular/router";
@Directive()
export abstract class FormPageBase<
@ -27,7 +27,7 @@ export abstract class FormPageBase<
protected dataService = inject(PageDataService) as S;
protected constructor() {
const id = this.route.snapshot.params['id'];
const id = this.route.snapshot.params["id"];
this.validateRoute(id);
this.buildForm();
@ -35,18 +35,18 @@ export abstract class FormPageBase<
validateRoute(id: string | undefined) {
const url = this.router.url;
if (url.endsWith('create') && id !== undefined) {
throw new Error('Route ends with create but id is defined');
if (url.endsWith("create") && id !== undefined) {
throw new Error("Route ends with create but id is defined");
}
if (url.endsWith('edit') && (id === undefined || isNaN(+id))) {
throw new Error('Route ends with edit but id is not a number');
if (url.endsWith("edit") && (id === undefined || isNaN(+id))) {
throw new Error("Route ends with edit but id is not a number");
}
this.nodeId = id ? +id : undefined;
}
close() {
const backRoute = this.nodeId ? '../..' : '..';
const backRoute = this.nodeId ? "../.." : "..";
this.router.navigate([backRoute], { relativeTo: this.route }).then(() => {
this.filterService.onLoad.emit();

View File

@ -1,21 +1,21 @@
import { Directive, inject, OnDestroy } from '@angular/core';
import { PageDataService } from 'src/app/core/base/page.data.service';
import { Subject } from 'rxjs';
import { Logger } from 'src/app/service/logger.service';
import { QueryResult } from 'src/app/model/entities/query-result';
import { SpinnerService } from 'src/app/service/spinner.service';
import { FilterService } from 'src/app/service/filter.service';
import { Filter } from 'src/app/model/graphql/filter/filter.model';
import { Sort } from 'src/app/model/graphql/filter/sort.model';
import { takeUntil } from 'rxjs/operators';
import { PaginatorState } from 'primeng/paginator';
import { PageColumns } from 'src/app/core/base/page.columns';
import { Directive, inject, OnDestroy } from "@angular/core";
import { PageDataService } from "src/app/core/base/page.data.service";
import { Subject } from "rxjs";
import { Logger } from "src/app/service/logger.service";
import { QueryResult } from "src/app/model/entities/query-result";
import { SpinnerService } from "src/app/service/spinner.service";
import { FilterService } from "src/app/service/filter.service";
import { Filter } from "src/app/model/graphql/filter/filter.model";
import { Sort } from "src/app/model/graphql/filter/sort.model";
import { takeUntil } from "rxjs/operators";
import { PaginatorState } from "primeng/paginator";
import { PageColumns } from "src/app/core/base/page.columns";
import {
TableColumn,
TableRequireAnyPermissions,
} from 'src/app/modules/shared/components/table/table.model';
} from "src/app/modules/shared/components/table/table.model";
const logger = new Logger('PageBase');
const logger = new Logger("PageBase");
@Directive()
export abstract class PageBase<
@ -96,13 +96,13 @@ export abstract class PageBase<
}
columns: TableColumn<T>[] =
'get' in this.columnsService ? this.columnsService.get() : [];
"get" in this.columnsService ? this.columnsService.get() : [];
protected unsubscribe$ = new Subject<void>();
protected constructor(
useQueryParams = false,
permissions?: TableRequireAnyPermissions
permissions?: TableRequireAnyPermissions,
) {
this.subscribeToFilterService();
this.filterService.reset({
@ -113,7 +113,7 @@ export abstract class PageBase<
}
ngOnDestroy(): void {
logger.trace('Destroy component');
logger.trace("Destroy component");
this.unsubscribe$.next();
this.unsubscribe$.complete();
}
@ -125,26 +125,26 @@ export abstract class PageBase<
this.filterService.filter$
.pipe(takeUntil(this.unsubscribe$))
.subscribe(filter => {
.subscribe((filter) => {
this._filter = filter;
});
this.filterService.sort$
.pipe(takeUntil(this.unsubscribe$))
.subscribe(sort => {
.subscribe((sort) => {
this._sort = sort;
});
this.filterService.skip$
.pipe(takeUntil(this.unsubscribe$))
.subscribe(skip => {
.subscribe((skip) => {
this._skip = skip;
});
this.filterService.take$
.pipe(takeUntil(this.unsubscribe$))
.subscribe(take => {
if (take && Object.prototype.hasOwnProperty.call(take, 'showAll')) {
.subscribe((take) => {
if (take && Object.prototype.hasOwnProperty.call(take, "showAll")) {
this._take = 0;
return;
}

View File

@ -1,67 +1,67 @@
import { Injectable } from '@angular/core';
import { TableColumn } from 'src/app/modules/shared/components/table/table.model';
import { DbModel } from 'src/app/model/entities/db-model';
import { Injectable } from "@angular/core";
import { TableColumn } from "src/app/modules/shared/components/table/table.model";
import { DbModel } from "src/app/model/entities/db-model";
@Injectable({
providedIn: 'root',
providedIn: "root",
})
export abstract class PageColumns<T> {
abstract get(): TableColumn<T>[];
}
export const ID_COLUMN = {
name: 'id',
label: 'common.id',
type: 'number',
name: "id",
label: "common.id",
type: "number",
filterable: true,
value: (row: { id?: number }) => row.id,
class: 'max-w-24',
class: "max-w-24",
};
export const NAME_COLUMN = {
name: 'name',
label: 'common.name',
type: 'text',
name: "name",
label: "common.name",
type: "text",
filterable: true,
value: (row: { name?: string }) => row.name,
};
export const DESCRIPTION_COLUMN = {
name: 'description',
label: 'common.description',
type: 'text',
name: "description",
label: "common.description",
type: "text",
filterable: true,
value: (row: { description?: string }) => row.description,
};
export const DELETED_COLUMN = {
name: 'deleted',
label: 'common.deleted',
type: 'bool',
name: "deleted",
label: "common.deleted",
type: "bool",
filterable: true,
value: (row: DbModel) => row.deleted,
};
export const EDITOR_COLUMN = {
name: 'editor',
label: 'common.editor',
name: "editor",
label: "common.editor",
value: (row: DbModel) => row.editor?.username,
};
export const CREATED_UTC_COLUMN = {
name: 'createdUtc',
label: 'common.created',
type: 'date',
name: "createdUtc",
label: "common.created",
type: "date",
value: (row: DbModel) => row.createdUtc,
class: 'max-w-32',
class: "max-w-32",
};
export const UPDATED_UTC_COLUMN = {
name: 'updatedUtc',
label: 'common.updated',
type: 'date',
name: "updatedUtc",
label: "common.updated",
type: "date",
value: (row: DbModel) => row.updatedUtc,
class: 'max-w-32',
class: "max-w-32",
};
export const DB_MODEL_COLUMNS = [

View File

@ -1,19 +1,19 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { MutationResult } from 'apollo-angular';
import { Filter } from 'src/app/model/graphql/filter/filter.model';
import { Sort } from 'src/app/model/graphql/filter/sort.model';
import { QueryResult } from 'src/app/model/entities/query-result';
import { Injectable } from "@angular/core";
import { Observable } from "rxjs";
import { MutationResult } from "apollo-angular";
import { Filter } from "src/app/model/graphql/filter/filter.model";
import { Sort } from "src/app/model/graphql/filter/sort.model";
import { QueryResult } from "src/app/model/entities/query-result";
@Injectable({
providedIn: 'root',
providedIn: "root",
})
export abstract class PageDataService<T> {
abstract load(
filter?: Filter[],
sort?: Sort[],
skip?: number,
take?: number
take?: number,
): Observable<QueryResult<T>>;
abstract loadById(id: number): Observable<T>;
@ -29,12 +29,12 @@ export interface Update<T, U> {
export interface Delete<T> {
delete(
object: T
object: T,
): Observable<T | undefined | boolean> | Observable<MutationResult>;
}
export interface Restore<T> {
restore(
object: T
object: T,
): Observable<T | undefined | boolean> | Observable<MutationResult>;
}

View File

@ -1,9 +1,9 @@
import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
import { KeycloakService } from 'keycloak-angular';
import { Injectable } from "@angular/core";
import { CanActivate } from "@angular/router";
import { KeycloakService } from "keycloak-angular";
@Injectable({
providedIn: 'root',
providedIn: "root",
})
export class AuthGuard implements CanActivate {
constructor(private keycloak: KeycloakService) {}

View File

@ -1,24 +1,24 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Router } from '@angular/router';
import { Logger } from 'src/app/service/logger.service';
import { ToastService } from 'src/app/service/toast.service';
import { AuthService } from 'src/app/service/auth.service';
import { PermissionsEnum } from 'src/app/model/auth/permissionsEnum';
import { Injectable } from "@angular/core";
import { ActivatedRouteSnapshot, Router } from "@angular/router";
import { Logger } from "src/app/service/logger.service";
import { ToastService } from "src/app/service/toast.service";
import { AuthService } from "src/app/service/auth.service";
import { PermissionsEnum } from "src/app/model/auth/permissionsEnum";
const log = new Logger('PermissionGuard');
const log = new Logger("PermissionGuard");
@Injectable({
providedIn: 'root',
providedIn: "root",
})
export class PermissionGuard {
constructor(
private router: Router,
private toast: ToastService,
private auth: AuthService
private auth: AuthService,
) {}
async canActivate(route: ActivatedRouteSnapshot): Promise<boolean> {
const permissions = route.data['permissions'] as PermissionsEnum[];
const permissions = route.data["permissions"] as PermissionsEnum[];
if (!permissions || permissions.length === 0) {
return true;
@ -26,11 +26,11 @@ export class PermissionGuard {
const validate = await this.auth.hasAnyPermissionLazy(permissions);
if (!validate) {
log.debug('Permission denied', permissions);
this.toast.warn('common.warning', 'error.permission_denied');
this.router.navigate(['/']).then();
log.debug("Permission denied", permissions);
this.toast.warn("common.warning", "error.permission_denied");
this.router.navigate(["/"]).then();
}
log.debug('Permission granted', permissions);
log.debug("Permission granted", permissions);
return validate;
}
}

View File

@ -1,5 +1,5 @@
import {KeycloakService} from 'keycloak-angular';
import {environment} from 'src/environments/environment';
import { KeycloakService } from "keycloak-angular";
import { environment } from "src/environments/environment";
export function initializeKeycloak(keycloak: KeycloakService) {
return () =>
@ -10,7 +10,7 @@ export function initializeKeycloak(keycloak: KeycloakService) {
clientId: environment.auth.clientId,
},
initOptions: {
onLoad: 'check-sso',
onLoad: "check-sso",
},
enableBearerInterceptor: false,
});

View File

@ -1,7 +1,7 @@
import { HttpInterceptorFn } from '@angular/common/http';
import { KeycloakService } from 'keycloak-angular';
import { inject } from '@angular/core';
import { from, switchMap } from 'rxjs';
import { HttpInterceptorFn } from "@angular/common/http";
import { KeycloakService } from "keycloak-angular";
import { inject } from "@angular/core";
import { from, switchMap } from "rxjs";
export const tokenInterceptor: HttpInterceptorFn = (req, next) => {
const keycloak = inject(KeycloakService);
@ -15,14 +15,14 @@ export const tokenInterceptor: HttpInterceptorFn = (req, next) => {
}
return from(keycloak.getToken()).pipe(
switchMap(token => {
switchMap((token) => {
const modifiedReq = token
? req.clone({
headers: req.headers.set('Authorization', `Bearer ${token}`),
headers: req.headers.set("Authorization", `Bearer ${token}`),
})
: req;
return next(modifiedReq);
})
}),
);
};

View File

@ -1,5 +1,5 @@
import { Role } from 'src/app/model/entities/role';
import { DbModel } from 'src/app/model/entities/db-model';
import { Role } from "src/app/model/entities/role";
import { DbModel } from "src/app/model/entities/db-model";
export interface NotExistingUser {
keycloakId: string;

View File

@ -1,4 +1,4 @@
import { Theme } from 'src/app/model/view/theme';
import { Theme } from "src/app/model/view/theme";
export interface AppSettings {
TermsUrl: string;

View File

@ -1,5 +1,5 @@
import { DbModel } from 'src/app/model/entities/db-model';
import { Permission } from 'src/app/model/entities/role';
import { DbModel } from "src/app/model/entities/db-model";
import { Permission } from "src/app/model/entities/role";
export interface ApiKey extends DbModel {
identifier?: string;

View File

@ -1,4 +1,4 @@
import { User } from 'src/app/model/auth/user';
import { User } from "src/app/model/auth/user";
export interface DbModel {
id?: number;

View File

@ -2,7 +2,7 @@ import { DbModel } from "src/app/model/entities/db-model";
import { Permission } from "src/app/model/entities/role";
export interface Group extends DbModel {
name?: string;
name: string;
}
export interface GroupCreateInput {

View File

@ -1,4 +1,4 @@
import { DbModel } from 'src/app/model/entities/db-model';
import { DbModel } from "src/app/model/entities/db-model";
export interface News extends DbModel {
title: string;

View File

@ -1,4 +1,4 @@
import { DbModel } from 'src/app/model/entities/db-model';
import { DbModel } from "src/app/model/entities/db-model";
export interface Role extends DbModel {
name?: string;

View File

@ -9,6 +9,11 @@ export interface ShortUrl extends DbModel {
group?: Group;
}
export interface ShortUrlDto {
id: number;
targetUrl: string;
}
export interface ShortUrlCreateInput {
shortUrl: string;
targetUrl: string;

View File

@ -1,5 +1,5 @@
import { gql } from 'apollo-angular';
import { EDITOR_FRAGMENT } from 'src/app/model/graphql/editor.query';
import { gql } from "apollo-angular";
import { EDITOR_FRAGMENT } from "src/app/model/graphql/editor.query";
export const DB_MODEL_FRAGMENT = gql`
fragment DB_MODEL on DbModel {

View File

@ -1,4 +1,4 @@
import { gql } from 'apollo-angular';
import { gql } from "apollo-angular";
export const EDITOR_FRAGMENT = gql`
fragment EDITOR on User {

View File

@ -2,6 +2,6 @@
export type Sort = { [key: string]: any };
export enum SortOrder {
ASC = 'ASC',
DESC = 'DESC',
ASC = "ASC",
DESC = "DESC",
}

View File

@ -1,3 +1,3 @@
export enum Themes {
Default = 'maxlan-dark-theme',
Default = "maxlan-dark-theme",
}

View File

@ -1,38 +1,38 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes } from '@angular/router';
import { PermissionGuard } from 'src/app/core/guard/permission.guard';
import { PermissionsEnum } from 'src/app/model/auth/permissionsEnum';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { RouterModule, Routes } from "@angular/router";
import { PermissionGuard } from "src/app/core/guard/permission.guard";
import { PermissionsEnum } from "src/app/model/auth/permissionsEnum";
import { SharedModule } from "src/app/modules/shared/shared.module";
const routes: Routes = [
{
path: 'users',
title: 'Users | Maxlan',
path: "users",
title: "Users | Maxlan",
loadChildren: () =>
import('src/app/modules/admin/administration/users/users.module').then(
m => m.UsersModule
import("src/app/modules/admin/administration/users/users.module").then(
(m) => m.UsersModule,
),
canActivate: [PermissionGuard],
data: { permissions: [PermissionsEnum.users] },
},
{
path: 'roles',
title: 'Roles | Maxlan',
path: "roles",
title: "Roles | Maxlan",
loadChildren: () =>
import('src/app/modules/admin/administration/roles/roles.module').then(
m => m.RolesModule
import("src/app/modules/admin/administration/roles/roles.module").then(
(m) => m.RolesModule,
),
canActivate: [PermissionGuard],
data: { permissions: [PermissionsEnum.roles] },
},
{
path: 'api-keys',
title: 'API Key | Maxlan',
path: "api-keys",
title: "API Key | Maxlan",
loadChildren: () =>
import(
'src/app/modules/admin/administration/api-keys/api-keys.module'
).then(m => m.ApiKeysModule),
"src/app/modules/admin/administration/api-keys/api-keys.module"
).then((m) => m.ApiKeysModule),
canActivate: [PermissionGuard],
data: { permissions: [PermissionsEnum.apiKeys] },
},

View File

@ -1,11 +1,11 @@
import { Injectable, Provider } from '@angular/core';
import { Injectable, Provider } from "@angular/core";
import {
DB_MODEL_COLUMNS,
ID_COLUMN,
PageColumns,
} from 'src/app/core/base/page.columns';
import { TableColumn } from 'src/app/modules/shared/components/table/table.model';
import { ApiKey } from 'src/app/model/entities/api-key';
} from "src/app/core/base/page.columns";
import { TableColumn } from "src/app/modules/shared/components/table/table.model";
import { ApiKey } from "src/app/model/entities/api-key";
@Injectable()
export class ApiKeysColumns extends PageColumns<ApiKey> {
@ -13,16 +13,16 @@ export class ApiKeysColumns extends PageColumns<ApiKey> {
return [
ID_COLUMN,
{
name: 'identifier',
label: 'common.identifier',
type: 'text',
name: "identifier",
label: "common.identifier",
type: "text",
filterable: true,
value: (row: ApiKey) => row.identifier,
},
{
name: 'key',
label: 'common.key',
type: 'password',
name: "key",
label: "common.key",
type: "password",
value: (row: ApiKey) => row.key,
},
...DB_MODEL_COLUMNS,

View File

@ -1,25 +1,25 @@
import { Injectable, Provider } from '@angular/core';
import { Observable } from 'rxjs';
import { Injectable, Provider } from "@angular/core";
import { Observable } from "rxjs";
import {
Create,
Delete,
PageDataService,
Restore,
Update,
} from 'src/app/core/base/page.data.service';
import { Permission } from 'src/app/model/entities/role';
import { Filter } from 'src/app/model/graphql/filter/filter.model';
import { Sort } from 'src/app/model/graphql/filter/sort.model';
import { Apollo, gql } from 'apollo-angular';
import { QueryResult } from 'src/app/model/entities/query-result';
import { DB_MODEL_FRAGMENT } from 'src/app/model/graphql/db-model.query';
import { catchError, map } from 'rxjs/operators';
import { SpinnerService } from 'src/app/service/spinner.service';
} from "src/app/core/base/page.data.service";
import { Permission } from "src/app/model/entities/role";
import { Filter } from "src/app/model/graphql/filter/filter.model";
import { Sort } from "src/app/model/graphql/filter/sort.model";
import { Apollo, gql } from "apollo-angular";
import { QueryResult } from "src/app/model/entities/query-result";
import { DB_MODEL_FRAGMENT } from "src/app/model/graphql/db-model.query";
import { catchError, map } from "rxjs/operators";
import { SpinnerService } from "src/app/service/spinner.service";
import {
ApiKey,
ApiKeyCreateInput,
ApiKeyUpdateInput,
} from 'src/app/model/entities/api-key';
} from "src/app/model/entities/api-key";
@Injectable()
export class ApiKeysDataService
@ -32,7 +32,7 @@ export class ApiKeysDataService
{
constructor(
private spinner: SpinnerService,
private apollo: Apollo
private apollo: Apollo,
) {
super();
}
@ -41,7 +41,7 @@ export class ApiKeysDataService
filter?: Filter[] | undefined,
sort?: Sort[] | undefined,
skip?: number | undefined,
take?: number | undefined
take?: number | undefined,
): Observable<QueryResult<ApiKey>> {
return this.apollo
.query<{ apiKeys: QueryResult<ApiKey> }>({
@ -78,12 +78,12 @@ export class ApiKeysDataService
},
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data.apiKeys));
.pipe(map((result) => result.data.apiKeys));
}
loadById(id: number): Observable<ApiKey> {
@ -109,12 +109,12 @@ export class ApiKeysDataService
},
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data.apiKeys.nodes[0]));
.pipe(map((result) => result.data.apiKeys.nodes[0]));
}
create(object: ApiKeyCreateInput): Observable<ApiKey | undefined> {
@ -140,17 +140,17 @@ export class ApiKeysDataService
variables: {
input: {
identifier: object.identifier,
permissions: object.permissions?.map(x => x.id),
permissions: object.permissions?.map((x) => x.id),
},
},
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data?.apiKey.create));
.pipe(map((result) => result.data?.apiKey.create));
}
update(object: ApiKeyUpdateInput): Observable<ApiKey | undefined> {
@ -177,17 +177,17 @@ export class ApiKeysDataService
input: {
id: object.id,
identifier: object.identifier,
permissions: object.permissions?.map(x => x.id),
permissions: object.permissions?.map((x) => x.id),
},
},
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data?.apiKey.update));
.pipe(map((result) => result.data?.apiKey.update));
}
delete(object: ApiKey): Observable<boolean> {
@ -205,12 +205,12 @@ export class ApiKeysDataService
},
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data?.apiKey.delete ?? false));
.pipe(map((result) => result.data?.apiKey.delete ?? false));
}
restore(object: ApiKey): Observable<boolean> {
@ -228,12 +228,12 @@ export class ApiKeysDataService
},
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data?.apiKey.restore ?? false));
.pipe(map((result) => result.data?.apiKey.restore ?? false));
}
getAllPermissions(): Observable<Permission[]> {
@ -251,12 +251,12 @@ export class ApiKeysDataService
`,
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data.permissions.nodes));
.pipe(map((result) => result.data.permissions.nodes));
}
static provide(): Provider[] {

View File

@ -1,22 +1,22 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { RouterModule, Routes } from '@angular/router';
import { PermissionGuard } from 'src/app/core/guard/permission.guard';
import { PermissionsEnum } from 'src/app/model/auth/permissionsEnum';
import { ApiKeyFormPageComponent } from 'src/app/modules/admin/administration/api-keys/form-page/api-key-form-page.component';
import { ApiKeysPage } from 'src/app/modules/admin/administration/api-keys/api-keys.page';
import { ApiKeysDataService } from 'src/app/modules/admin/administration/api-keys/api-keys.data.service';
import { ApiKeysColumns } from 'src/app/modules/admin/administration/api-keys/api-keys.columns';
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { SharedModule } from "src/app/modules/shared/shared.module";
import { RouterModule, Routes } from "@angular/router";
import { PermissionGuard } from "src/app/core/guard/permission.guard";
import { PermissionsEnum } from "src/app/model/auth/permissionsEnum";
import { ApiKeyFormPageComponent } from "src/app/modules/admin/administration/api-keys/form-page/api-key-form-page.component";
import { ApiKeysPage } from "src/app/modules/admin/administration/api-keys/api-keys.page";
import { ApiKeysDataService } from "src/app/modules/admin/administration/api-keys/api-keys.data.service";
import { ApiKeysColumns } from "src/app/modules/admin/administration/api-keys/api-keys.columns";
const routes: Routes = [
{
path: '',
title: 'Admin - ApiKeys | Maxlan',
path: "",
title: "Admin - ApiKeys | Maxlan",
component: ApiKeysPage,
children: [
{
path: 'create',
path: "create",
component: ApiKeyFormPageComponent,
canActivate: [PermissionGuard],
data: {
@ -24,7 +24,7 @@ const routes: Routes = [
},
},
{
path: 'edit/:id',
path: "edit/:id",
component: ApiKeyFormPageComponent,
canActivate: [PermissionGuard],
data: {

View File

@ -1,18 +1,18 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ApiKeysPage } from 'src/app/modules/admin/administration/api-keys/api-keys.page';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { TranslateModule } from '@ngx-translate/core';
import { AuthService } from 'src/app/service/auth.service';
import { KeycloakService } from 'keycloak-angular';
import { ErrorHandlingService } from 'src/app/service/error-handling.service';
import { ToastService } from 'src/app/service/toast.service';
import { ConfirmationService, MessageService } from 'primeng/api';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';
import { PageDataService } from 'src/app/core/base/page.data.service';
import { ApiKeysDataService } from 'src/app/modules/admin/administration/api-keys/api-keys.data.service';
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { ApiKeysPage } from "src/app/modules/admin/administration/api-keys/api-keys.page";
import { SharedModule } from "src/app/modules/shared/shared.module";
import { TranslateModule } from "@ngx-translate/core";
import { AuthService } from "src/app/service/auth.service";
import { KeycloakService } from "keycloak-angular";
import { ErrorHandlingService } from "src/app/service/error-handling.service";
import { ToastService } from "src/app/service/toast.service";
import { ConfirmationService, MessageService } from "primeng/api";
import { ActivatedRoute } from "@angular/router";
import { of } from "rxjs";
import { PageDataService } from "src/app/core/base/page.data.service";
import { ApiKeysDataService } from "src/app/modules/admin/administration/api-keys/api-keys.data.service";
describe('ApiKeysComponent', () => {
describe("ApiKeysComponent", () => {
let component: ApiKeysPage;
let fixture: ComponentFixture<ApiKeysPage>;
@ -45,7 +45,7 @@ describe('ApiKeysComponent', () => {
fixture.detectChanges();
});
it('should create', () => {
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,16 +1,16 @@
import { Component } from '@angular/core';
import { PageBase } from 'src/app/core/base/page-base';
import { ToastService } from 'src/app/service/toast.service';
import { ConfirmationDialogService } from 'src/app/service/confirmation-dialog.service';
import { PermissionsEnum } from 'src/app/model/auth/permissionsEnum';
import { ApiKey } from 'src/app/model/entities/api-key';
import { ApiKeysDataService } from 'src/app/modules/admin/administration/api-keys/api-keys.data.service';
import { ApiKeysColumns } from 'src/app/modules/admin/administration/api-keys/api-keys.columns';
import { Component } from "@angular/core";
import { PageBase } from "src/app/core/base/page-base";
import { ToastService } from "src/app/service/toast.service";
import { ConfirmationDialogService } from "src/app/service/confirmation-dialog.service";
import { PermissionsEnum } from "src/app/model/auth/permissionsEnum";
import { ApiKey } from "src/app/model/entities/api-key";
import { ApiKeysDataService } from "src/app/modules/admin/administration/api-keys/api-keys.data.service";
import { ApiKeysColumns } from "src/app/modules/admin/administration/api-keys/api-keys.columns";
@Component({
selector: 'app-api-keys',
templateUrl: './api-keys.page.html',
styleUrl: './api-keys.page.scss',
selector: "app-api-keys",
templateUrl: "./api-keys.page.html",
styleUrl: "./api-keys.page.scss",
})
export class ApiKeysPage extends PageBase<
ApiKey,
@ -19,7 +19,7 @@ export class ApiKeysPage extends PageBase<
> {
constructor(
private toast: ToastService,
private confirmation: ConfirmationDialogService
private confirmation: ConfirmationDialogService,
) {
super(true, {
read: [PermissionsEnum.apiKeys],
@ -34,7 +34,7 @@ export class ApiKeysPage extends PageBase<
this.loading = true;
this.dataService
.load(this.filter, this.sort, this.skip, this.take)
.subscribe(result => {
.subscribe((result) => {
this.result = result;
this.loading = false;
});
@ -42,12 +42,12 @@ export class ApiKeysPage extends PageBase<
delete(apiKey: ApiKey): void {
this.confirmation.confirmDialog({
header: 'dialog.delete.header',
message: 'dialog.delete.message',
header: "dialog.delete.header",
message: "dialog.delete.message",
accept: () => {
this.loading = true;
this.dataService.delete(apiKey).subscribe(() => {
this.toast.success('action.deleted');
this.toast.success("action.deleted");
this.load();
});
},
@ -57,12 +57,12 @@ export class ApiKeysPage extends PageBase<
restore(apiKey: ApiKey): void {
this.confirmation.confirmDialog({
header: 'dialog.restore.header',
message: 'dialog.restore.message',
header: "dialog.restore.header",
message: "dialog.restore.message",
accept: () => {
this.loading = true;
this.dataService.restore(apiKey).subscribe(() => {
this.toast.success('action.restored');
this.toast.success("action.restored");
this.load();
});
},

View File

@ -1,17 +1,17 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RoleFormPageComponent } from 'src/app/modules/admin/administration/roles/form-page/role-form-page.component';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { TranslateModule } from '@ngx-translate/core';
import { AuthService } from 'src/app/service/auth.service';
import { ErrorHandlingService } from 'src/app/service/error-handling.service';
import { ToastService } from 'src/app/service/toast.service';
import { ConfirmationService, MessageService } from 'primeng/api';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';
import { ApiKeysDataService } from 'src/app/modules/admin/administration/api-keys/api-keys.data.service';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { RoleFormPageComponent } from "src/app/modules/admin/administration/roles/form-page/role-form-page.component";
import { SharedModule } from "src/app/modules/shared/shared.module";
import { TranslateModule } from "@ngx-translate/core";
import { AuthService } from "src/app/service/auth.service";
import { ErrorHandlingService } from "src/app/service/error-handling.service";
import { ToastService } from "src/app/service/toast.service";
import { ConfirmationService, MessageService } from "primeng/api";
import { ActivatedRoute } from "@angular/router";
import { of } from "rxjs";
import { ApiKeysDataService } from "src/app/modules/admin/administration/api-keys/api-keys.data.service";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
describe('ApiKeyFormpageComponent', () => {
describe("ApiKeyFormpageComponent", () => {
let component: RoleFormPageComponent;
let fixture: ComponentFixture<RoleFormPageComponent>;
@ -44,7 +44,7 @@ describe('ApiKeyFormpageComponent', () => {
fixture.detectChanges();
});
it('should create', () => {
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,21 +1,21 @@
import { Component } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { InputSwitchChangeEvent } from 'primeng/inputswitch';
import { ToastService } from 'src/app/service/toast.service';
import { firstValueFrom } from 'rxjs';
import { FormPageBase } from 'src/app/core/base/form-page-base';
import { Permission } from 'src/app/model/entities/role';
import { Component } from "@angular/core";
import { FormControl, FormGroup, Validators } from "@angular/forms";
import { InputSwitchChangeEvent } from "primeng/inputswitch";
import { ToastService } from "src/app/service/toast.service";
import { firstValueFrom } from "rxjs";
import { FormPageBase } from "src/app/core/base/form-page-base";
import { Permission } from "src/app/model/entities/role";
import {
ApiKey,
ApiKeyCreateInput,
ApiKeyUpdateInput,
} from 'src/app/model/entities/api-key';
import { ApiKeysDataService } from 'src/app/modules/admin/administration/api-keys/api-keys.data.service';
} from "src/app/model/entities/api-key";
import { ApiKeysDataService } from "src/app/modules/admin/administration/api-keys/api-keys.data.service";
@Component({
selector: 'app-api-key-form-page',
templateUrl: './api-key-form-page.component.html',
styleUrl: './api-key-form-page.component.scss',
selector: "app-api-key-form-page",
templateUrl: "./api-key-form-page.component.html",
styleUrl: "./api-key-form-page.component.scss",
})
export class ApiKeyFormPageComponent extends FormPageBase<
ApiKey,
@ -38,7 +38,7 @@ export class ApiKeyFormPageComponent extends FormPageBase<
this.dataService
.load([{ id: { equal: this.nodeId } }])
.subscribe(apiKey => {
.subscribe((apiKey) => {
this.node = apiKey.nodes[0];
this.setForm(this.node);
});
@ -47,12 +47,12 @@ export class ApiKeyFormPageComponent extends FormPageBase<
async initializePermissions() {
const permissions = await firstValueFrom(
this.dataService.getAllPermissions()
this.dataService.getAllPermissions(),
);
this.allPermissions = permissions;
this.permissionGroups = permissions.reduce(
(acc, p) => {
const group = p.name.includes('.') ? p.name.split('.')[0] : p.name;
const group = p.name.includes(".") ? p.name.split(".")[0] : p.name;
if (!acc[group]) {
acc[group] = [];
@ -60,10 +60,10 @@ export class ApiKeyFormPageComponent extends FormPageBase<
acc[group].push(p);
return acc;
},
{} as { [key: string]: Permission[] }
{} as { [key: string]: Permission[] },
);
permissions.forEach(p => {
permissions.forEach((p) => {
this.form.addControl(p.name, new FormControl<boolean>(false));
});
}
@ -77,48 +77,48 @@ export class ApiKeyFormPageComponent extends FormPageBase<
id: new FormControl<number | undefined>(undefined),
identifier: new FormControl<string | undefined>(
undefined,
Validators.required
Validators.required,
),
});
this.form.controls['id'].disable();
this.form.controls["id"].disable();
}
setForm(node?: ApiKey) {
this.form.controls['id'].setValue(node?.id);
this.form.controls['identifier'].setValue(node?.identifier);
this.form.controls["id"].setValue(node?.id);
this.form.controls["identifier"].setValue(node?.identifier);
if (!node) return;
const permissions = node.permissions ?? [];
permissions.forEach(p => {
permissions.forEach((p) => {
this.form.controls[p.name].setValue(true);
});
}
getCreateInput(): ApiKeyCreateInput {
return {
identifier: this.form.controls['identifier'].pristine
identifier: this.form.controls["identifier"].pristine
? undefined
: (this.form.controls['identifier'].value ?? undefined),
: (this.form.controls["identifier"].value ?? undefined),
permissions: this.allPermissions.filter(
p => this.form.controls[p.name].value
(p) => this.form.controls[p.name].value,
),
};
}
getUpdateInput(): ApiKeyUpdateInput {
if (!this.node?.id) {
throw new Error('Node id is missing');
throw new Error("Node id is missing");
}
return {
id: this.form.controls['id'].value,
identifier: this.form.controls['identifier'].pristine
id: this.form.controls["id"].value,
identifier: this.form.controls["identifier"].pristine
? undefined
: (this.form.controls['identifier'].value ?? undefined),
: (this.form.controls["identifier"].value ?? undefined),
permissions: this.allPermissions.filter(
p => this.form.controls[p.name].value
(p) => this.form.controls[p.name].value,
),
};
}
@ -126,7 +126,7 @@ export class ApiKeyFormPageComponent extends FormPageBase<
create(apiKey: ApiKeyCreateInput): void {
this.dataService.create(apiKey).subscribe(() => {
this.spinner.hide();
this.toast.success('action.created');
this.toast.success("action.created");
this.close();
});
}
@ -134,20 +134,20 @@ export class ApiKeyFormPageComponent extends FormPageBase<
update(apiKey: ApiKeyUpdateInput): void {
this.dataService.update(apiKey).subscribe(() => {
this.spinner.hide();
this.toast.success('action.created');
this.toast.success("action.created");
this.close();
});
}
toggleGroup(event: InputSwitchChangeEvent, group: string) {
this.permissionGroups[group].forEach(p => {
this.permissionGroups[group].forEach((p) => {
this.form.controls[p.name].setValue(event.checked);
});
}
isGroupChecked(group: string) {
return this.permissionGroups[group].every(
p => this.form.controls[p.name].value
(p) => this.form.controls[p.name].value,
);
}

View File

@ -1,17 +1,17 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RoleFormPageComponent } from 'src/app/modules/admin/administration/roles/form-page/role-form-page.component';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { TranslateModule } from '@ngx-translate/core';
import { AuthService } from 'src/app/service/auth.service';
import { ErrorHandlingService } from 'src/app/service/error-handling.service';
import { ToastService } from 'src/app/service/toast.service';
import { ConfirmationService, MessageService } from 'primeng/api';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';
import { RolesDataService } from 'src/app/modules/admin/administration/roles/roles.data.service';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { RoleFormPageComponent } from "src/app/modules/admin/administration/roles/form-page/role-form-page.component";
import { SharedModule } from "src/app/modules/shared/shared.module";
import { TranslateModule } from "@ngx-translate/core";
import { AuthService } from "src/app/service/auth.service";
import { ErrorHandlingService } from "src/app/service/error-handling.service";
import { ToastService } from "src/app/service/toast.service";
import { ConfirmationService, MessageService } from "primeng/api";
import { ActivatedRoute } from "@angular/router";
import { of } from "rxjs";
import { RolesDataService } from "src/app/modules/admin/administration/roles/roles.data.service";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
describe('RoleFormpageComponent', () => {
describe("RoleFormpageComponent", () => {
let component: RoleFormPageComponent;
let fixture: ComponentFixture<RoleFormPageComponent>;
@ -44,7 +44,7 @@ describe('RoleFormpageComponent', () => {
fixture.detectChanges();
});
it('should create', () => {
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,21 +1,21 @@
import { Component } from '@angular/core';
import { Component } from "@angular/core";
import {
Permission,
Role,
RoleCreateInput,
RoleUpdateInput,
} from 'src/app/model/entities/role';
import { InputSwitchChangeEvent } from 'primeng/inputswitch';
import { ToastService } from 'src/app/service/toast.service';
import { firstValueFrom } from 'rxjs';
import { FormPageBase } from 'src/app/core/base/form-page-base';
import { RolesDataService } from 'src/app/modules/admin/administration/roles/roles.data.service';
import { FormControl, FormGroup, Validators } from '@angular/forms';
} from "src/app/model/entities/role";
import { InputSwitchChangeEvent } from "primeng/inputswitch";
import { ToastService } from "src/app/service/toast.service";
import { firstValueFrom } from "rxjs";
import { FormPageBase } from "src/app/core/base/form-page-base";
import { RolesDataService } from "src/app/modules/admin/administration/roles/roles.data.service";
import { FormControl, FormGroup, Validators } from "@angular/forms";
@Component({
selector: 'app-role-form-page',
templateUrl: './role-form-page.component.html',
styleUrl: './role-form-page.component.scss',
selector: "app-role-form-page",
templateUrl: "./role-form-page.component.html",
styleUrl: "./role-form-page.component.scss",
})
export class RoleFormPageComponent extends FormPageBase<
Role,
@ -36,7 +36,7 @@ export class RoleFormPageComponent extends FormPageBase<
return;
}
this.dataService.loadById(this.nodeId).subscribe(role => {
this.dataService.loadById(this.nodeId).subscribe((role) => {
this.node = role;
this.setForm(this.node);
});
@ -45,12 +45,12 @@ export class RoleFormPageComponent extends FormPageBase<
async initializePermissions() {
const permissions = await firstValueFrom(
this.dataService.getAllPermissions()
this.dataService.getAllPermissions(),
);
this.allPermissions = permissions;
this.permissionGroups = permissions.reduce(
(acc, p) => {
const group = p.name.includes('.') ? p.name.split('.')[0] : p.name;
const group = p.name.includes(".") ? p.name.split(".")[0] : p.name;
if (!acc[group]) {
acc[group] = [];
@ -58,10 +58,10 @@ export class RoleFormPageComponent extends FormPageBase<
acc[group].push(p);
return acc;
},
{} as { [key: string]: Permission[] }
{} as { [key: string]: Permission[] },
);
permissions.forEach(p => {
permissions.forEach((p) => {
this.form.addControl(p.name, new FormControl<boolean>(false));
});
}
@ -76,48 +76,48 @@ export class RoleFormPageComponent extends FormPageBase<
name: new FormControl<string | undefined>(undefined, Validators.required),
description: new FormControl<string | undefined>(undefined),
});
this.form.controls['id'].disable();
this.form.controls["id"].disable();
}
setForm(node?: Role) {
this.form.controls['id'].setValue(node?.id);
this.form.controls['name'].setValue(node?.name);
this.form.controls['description'].setValue(node?.description);
this.form.controls["id"].setValue(node?.id);
this.form.controls["name"].setValue(node?.name);
this.form.controls["description"].setValue(node?.description);
if (!node) return;
const permissions = node.permissions ?? [];
permissions.forEach(p => {
permissions.forEach((p) => {
this.form.controls[p.name].setValue(true);
});
}
getCreateInput(): RoleCreateInput {
return {
name: this.form.controls['name'].pristine
name: this.form.controls["name"].pristine
? undefined
: (this.form.controls['name'].value ?? undefined),
description: this.form.controls['description'].pristine
: (this.form.controls["name"].value ?? undefined),
description: this.form.controls["description"].pristine
? undefined
: (this.form.controls['description'].value ?? undefined),
: (this.form.controls["description"].value ?? undefined),
permissions: this.allPermissions.filter(
p => this.form.controls[p.name].value
(p) => this.form.controls[p.name].value,
),
};
}
getUpdateInput(): RoleUpdateInput {
return {
id: this.form.controls['id'].value,
name: this.form.controls['name'].pristine
id: this.form.controls["id"].value,
name: this.form.controls["name"].pristine
? undefined
: this.form.controls['name'].value,
description: this.form.controls['description'].pristine
: this.form.controls["name"].value,
description: this.form.controls["description"].pristine
? undefined
: this.form.controls['description'].value,
: this.form.controls["description"].value,
permissions: this.allPermissions.filter(
p => this.form.controls[p.name].value
(p) => this.form.controls[p.name].value,
),
};
}
@ -125,7 +125,7 @@ export class RoleFormPageComponent extends FormPageBase<
create(role: RoleCreateInput): void {
this.dataService.create(role).subscribe(() => {
this.spinner.hide();
this.toast.success('action.created');
this.toast.success("action.created");
this.close();
});
}
@ -133,20 +133,20 @@ export class RoleFormPageComponent extends FormPageBase<
update(role: RoleUpdateInput): void {
this.dataService.update(role).subscribe(() => {
this.spinner.hide();
this.toast.success('action.created');
this.toast.success("action.created");
this.close();
});
}
toggleGroup(event: InputSwitchChangeEvent, group: string) {
this.permissionGroups[group].forEach(p => {
this.permissionGroups[group].forEach((p) => {
this.form.controls[p.name].setValue(event.checked);
});
}
isGroupChecked(group: string) {
return this.permissionGroups[group].every(
p => this.form.controls[p.name].value
(p) => this.form.controls[p.name].value,
);
}

View File

@ -1,13 +1,13 @@
import { Injectable, Provider } from '@angular/core';
import { Role } from 'src/app/model/entities/role';
import { Injectable, Provider } from "@angular/core";
import { Role } from "src/app/model/entities/role";
import {
DB_MODEL_COLUMNS,
DESCRIPTION_COLUMN,
ID_COLUMN,
NAME_COLUMN,
PageColumns,
} from 'src/app/core/base/page.columns';
import { TableColumn } from 'src/app/modules/shared/components/table/table.model';
} from "src/app/core/base/page.columns";
import { TableColumn } from "src/app/modules/shared/components/table/table.model";
@Injectable()
export class RolesColumns extends PageColumns<Role> {

View File

@ -1,25 +1,25 @@
import { Injectable, Provider } from '@angular/core';
import { Observable } from 'rxjs';
import { Injectable, Provider } from "@angular/core";
import { Observable } from "rxjs";
import {
Create,
Delete,
PageDataService,
Restore,
Update,
} from 'src/app/core/base/page.data.service';
} from "src/app/core/base/page.data.service";
import {
Permission,
Role,
RoleCreateInput,
RoleUpdateInput,
} from 'src/app/model/entities/role';
import { Filter } from 'src/app/model/graphql/filter/filter.model';
import { Sort } from 'src/app/model/graphql/filter/sort.model';
import { Apollo, gql } from 'apollo-angular';
import { QueryResult } from 'src/app/model/entities/query-result';
import { DB_MODEL_FRAGMENT } from 'src/app/model/graphql/db-model.query';
import { catchError, map } from 'rxjs/operators';
import { SpinnerService } from 'src/app/service/spinner.service';
} from "src/app/model/entities/role";
import { Filter } from "src/app/model/graphql/filter/filter.model";
import { Sort } from "src/app/model/graphql/filter/sort.model";
import { Apollo, gql } from "apollo-angular";
import { QueryResult } from "src/app/model/entities/query-result";
import { DB_MODEL_FRAGMENT } from "src/app/model/graphql/db-model.query";
import { catchError, map } from "rxjs/operators";
import { SpinnerService } from "src/app/service/spinner.service";
@Injectable()
export class RolesDataService
@ -32,7 +32,7 @@ export class RolesDataService
{
constructor(
private spinner: SpinnerService,
private apollo: Apollo
private apollo: Apollo,
) {
super();
}
@ -41,7 +41,7 @@ export class RolesDataService
filter?: Filter[] | undefined,
sort?: Sort[] | undefined,
skip?: number | undefined,
take?: number | undefined
take?: number | undefined,
): Observable<QueryResult<Role>> {
return this.apollo
.query<{ roles: QueryResult<Role> }>({
@ -75,12 +75,12 @@ export class RolesDataService
},
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data.roles));
.pipe(map((result) => result.data.roles));
}
loadById(id: number): Observable<Role> {
@ -112,12 +112,12 @@ export class RolesDataService
},
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data.roles.nodes[0]));
.pipe(map((result) => result.data.roles.nodes[0]));
}
create(object: RoleCreateInput): Observable<Role | undefined> {
@ -145,17 +145,17 @@ export class RolesDataService
input: {
name: object.name,
description: object.description,
permissions: object.permissions?.map(x => x.id),
permissions: object.permissions?.map((x) => x.id),
},
},
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data?.role.create));
.pipe(map((result) => result.data?.role.create));
}
update(object: RoleUpdateInput): Observable<Role | undefined> {
@ -184,17 +184,17 @@ export class RolesDataService
id: object.id,
name: object.name,
description: object.description,
permissions: object.permissions?.map(x => x.id),
permissions: object.permissions?.map((x) => x.id),
},
},
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data?.role.update));
.pipe(map((result) => result.data?.role.update));
}
delete(object: Role): Observable<boolean> {
@ -212,12 +212,12 @@ export class RolesDataService
},
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data?.role.delete ?? false));
.pipe(map((result) => result.data?.role.delete ?? false));
}
restore(object: Role): Observable<boolean> {
@ -235,12 +235,12 @@ export class RolesDataService
},
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data?.role.restore ?? false));
.pipe(map((result) => result.data?.role.restore ?? false));
}
getAllPermissions(): Observable<Permission[]> {
@ -258,12 +258,12 @@ export class RolesDataService
`,
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data.permissions.nodes));
.pipe(map((result) => result.data.permissions.nodes));
}
static provide(): Provider[] {

View File

@ -1,22 +1,22 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { RouterModule, Routes } from '@angular/router';
import { PermissionGuard } from 'src/app/core/guard/permission.guard';
import { PermissionsEnum } from 'src/app/model/auth/permissionsEnum';
import { RoleFormPageComponent } from 'src/app/modules/admin/administration/roles/form-page/role-form-page.component';
import { RolesPage } from 'src/app/modules/admin/administration/roles/roles.page';
import { RolesDataService } from 'src/app/modules/admin/administration/roles/roles.data.service';
import { RolesColumns } from 'src/app/modules/admin/administration/roles/roles.columns';
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { SharedModule } from "src/app/modules/shared/shared.module";
import { RouterModule, Routes } from "@angular/router";
import { PermissionGuard } from "src/app/core/guard/permission.guard";
import { PermissionsEnum } from "src/app/model/auth/permissionsEnum";
import { RoleFormPageComponent } from "src/app/modules/admin/administration/roles/form-page/role-form-page.component";
import { RolesPage } from "src/app/modules/admin/administration/roles/roles.page";
import { RolesDataService } from "src/app/modules/admin/administration/roles/roles.data.service";
import { RolesColumns } from "src/app/modules/admin/administration/roles/roles.columns";
const routes: Routes = [
{
path: '',
title: 'Admin - Roles | Maxlan',
path: "",
title: "Admin - Roles | Maxlan",
component: RolesPage,
children: [
{
path: 'create',
path: "create",
component: RoleFormPageComponent,
canActivate: [PermissionGuard],
data: {
@ -24,7 +24,7 @@ const routes: Routes = [
},
},
{
path: 'edit/:id',
path: "edit/:id",
component: RoleFormPageComponent,
canActivate: [PermissionGuard],
data: {

View File

@ -1,18 +1,18 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RolesPage } from 'src/app/modules/admin/administration/roles/roles.page';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { TranslateModule } from '@ngx-translate/core';
import { AuthService } from 'src/app/service/auth.service';
import { KeycloakService } from 'keycloak-angular';
import { ErrorHandlingService } from 'src/app/service/error-handling.service';
import { ToastService } from 'src/app/service/toast.service';
import { ConfirmationService, MessageService } from 'primeng/api';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';
import { PageDataService } from 'src/app/core/base/page.data.service';
import { RolesDataService } from 'src/app/modules/admin/administration/roles/roles.data.service';
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { RolesPage } from "src/app/modules/admin/administration/roles/roles.page";
import { SharedModule } from "src/app/modules/shared/shared.module";
import { TranslateModule } from "@ngx-translate/core";
import { AuthService } from "src/app/service/auth.service";
import { KeycloakService } from "keycloak-angular";
import { ErrorHandlingService } from "src/app/service/error-handling.service";
import { ToastService } from "src/app/service/toast.service";
import { ConfirmationService, MessageService } from "primeng/api";
import { ActivatedRoute } from "@angular/router";
import { of } from "rxjs";
import { PageDataService } from "src/app/core/base/page.data.service";
import { RolesDataService } from "src/app/modules/admin/administration/roles/roles.data.service";
describe('RolesComponent', () => {
describe("RolesComponent", () => {
let component: RolesPage;
let fixture: ComponentFixture<RolesPage>;
@ -45,7 +45,7 @@ describe('RolesComponent', () => {
fixture.detectChanges();
});
it('should create', () => {
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,21 +1,21 @@
import { Component } from '@angular/core';
import { PageBase } from 'src/app/core/base/page-base';
import { Role } from 'src/app/model/entities/role';
import { ToastService } from 'src/app/service/toast.service';
import { ConfirmationDialogService } from 'src/app/service/confirmation-dialog.service';
import { PermissionsEnum } from 'src/app/model/auth/permissionsEnum';
import { RolesColumns } from 'src/app/modules/admin/administration/roles/roles.columns';
import { RolesDataService } from 'src/app/modules/admin/administration/roles/roles.data.service';
import { Component } from "@angular/core";
import { PageBase } from "src/app/core/base/page-base";
import { Role } from "src/app/model/entities/role";
import { ToastService } from "src/app/service/toast.service";
import { ConfirmationDialogService } from "src/app/service/confirmation-dialog.service";
import { PermissionsEnum } from "src/app/model/auth/permissionsEnum";
import { RolesColumns } from "src/app/modules/admin/administration/roles/roles.columns";
import { RolesDataService } from "src/app/modules/admin/administration/roles/roles.data.service";
@Component({
selector: 'app-roles',
templateUrl: './roles.page.html',
styleUrl: './roles.page.scss',
selector: "app-roles",
templateUrl: "./roles.page.html",
styleUrl: "./roles.page.scss",
})
export class RolesPage extends PageBase<Role, RolesDataService, RolesColumns> {
constructor(
private toast: ToastService,
private confirmation: ConfirmationDialogService
private confirmation: ConfirmationDialogService,
) {
super(true, {
read: [PermissionsEnum.roles],
@ -30,7 +30,7 @@ export class RolesPage extends PageBase<Role, RolesDataService, RolesColumns> {
this.loading = true;
this.dataService
.load(this.filter, this.sort, this.skip, this.take)
.subscribe(result => {
.subscribe((result) => {
this.result = result;
this.loading = false;
});
@ -38,12 +38,12 @@ export class RolesPage extends PageBase<Role, RolesDataService, RolesColumns> {
delete(role: Role): void {
this.confirmation.confirmDialog({
header: 'dialog.delete.header',
message: 'dialog.delete.message',
header: "dialog.delete.header",
message: "dialog.delete.message",
accept: () => {
this.loading = true;
this.dataService.delete(role).subscribe(() => {
this.toast.success('action.deleted');
this.toast.success("action.deleted");
this.load();
});
},
@ -53,12 +53,12 @@ export class RolesPage extends PageBase<Role, RolesDataService, RolesColumns> {
restore(role: Role): void {
this.confirmation.confirmDialog({
header: 'dialog.restore.header',
message: 'dialog.restore.message',
header: "dialog.restore.header",
message: "dialog.restore.message",
accept: () => {
this.loading = true;
this.dataService.restore(role).subscribe(() => {
this.toast.success('action.restored');
this.toast.success("action.restored");
this.load();
});
},

View File

@ -1,17 +1,17 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RoleFormPageComponent } from 'src/app/modules/admin/administration/roles/form-page/role-form-page.component';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { TranslateModule } from '@ngx-translate/core';
import { AuthService } from 'src/app/service/auth.service';
import { ErrorHandlingService } from 'src/app/service/error-handling.service';
import { ToastService } from 'src/app/service/toast.service';
import { ConfirmationService, MessageService } from 'primeng/api';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';
import { UsersDataService } from 'src/app/modules/admin/administration/users/users.data.service';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { RoleFormPageComponent } from "src/app/modules/admin/administration/roles/form-page/role-form-page.component";
import { SharedModule } from "src/app/modules/shared/shared.module";
import { TranslateModule } from "@ngx-translate/core";
import { AuthService } from "src/app/service/auth.service";
import { ErrorHandlingService } from "src/app/service/error-handling.service";
import { ToastService } from "src/app/service/toast.service";
import { ConfirmationService, MessageService } from "primeng/api";
import { ActivatedRoute } from "@angular/router";
import { of } from "rxjs";
import { UsersDataService } from "src/app/modules/admin/administration/users/users.data.service";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
describe('UserFormpageComponent', () => {
describe("UserFormpageComponent", () => {
let component: RoleFormPageComponent;
let fixture: ComponentFixture<RoleFormPageComponent>;
@ -44,7 +44,7 @@ describe('UserFormpageComponent', () => {
fixture.detectChanges();
});
it('should create', () => {
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,20 +1,20 @@
import { Component } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { ToastService } from 'src/app/service/toast.service';
import { FormPageBase } from 'src/app/core/base/form-page-base';
import { Component } from "@angular/core";
import { FormControl, FormGroup } from "@angular/forms";
import { ToastService } from "src/app/service/toast.service";
import { FormPageBase } from "src/app/core/base/form-page-base";
import {
NotExistingUser,
User,
UserCreateInput,
UserUpdateInput,
} from 'src/app/model/auth/user';
import { Role } from 'src/app/model/entities/role';
import { UsersDataService } from 'src/app/modules/admin/administration/users/users.data.service';
} from "src/app/model/auth/user";
import { Role } from "src/app/model/entities/role";
import { UsersDataService } from "src/app/modules/admin/administration/users/users.data.service";
@Component({
selector: 'app-user-form-page',
templateUrl: './user-form-page.component.html',
styleUrl: './user-form-page.component.scss',
selector: "app-user-form-page",
templateUrl: "./user-form-page.component.html",
styleUrl: "./user-form-page.component.scss",
})
export class UserFormPageComponent extends FormPageBase<
User,
@ -27,12 +27,12 @@ export class UserFormPageComponent extends FormPageBase<
constructor(private toast: ToastService) {
super();
this.dataService.getAllRoles().subscribe(roles => {
this.dataService.getAllRoles().subscribe((roles) => {
this.roles = roles;
});
if (!this.nodeId) {
this.dataService.getNotExistingUsersFromKeycloak().subscribe(users => {
this.dataService.getNotExistingUsersFromKeycloak().subscribe((users) => {
this.notExistingUsers = users;
this.node = this.new();
this.setForm(this.node);
@ -41,7 +41,7 @@ export class UserFormPageComponent extends FormPageBase<
return;
}
this.dataService.loadById(this.nodeId).subscribe(user => {
this.dataService.loadById(this.nodeId).subscribe((user) => {
this.node = user;
this.setForm(this.node);
});
@ -59,47 +59,47 @@ export class UserFormPageComponent extends FormPageBase<
email: new FormControl<string | undefined>(undefined),
roles: new FormControl<Role[]>([]),
});
this.form.controls['id'].disable();
this.form.controls['username'].disable();
this.form.controls['email'].disable();
this.form.controls["id"].disable();
this.form.controls["username"].disable();
this.form.controls["email"].disable();
}
setForm(node?: User) {
this.form.controls['id'].setValue(node?.id);
this.form.controls['username'].setValue(node?.username);
this.form.controls['email'].setValue(node?.email);
this.form.controls['roles'].setValue(node?.roles ?? []);
this.form.controls["id"].setValue(node?.id);
this.form.controls["username"].setValue(node?.username);
this.form.controls["email"].setValue(node?.email);
this.form.controls["roles"].setValue(node?.roles ?? []);
if (this.notExistingUsers.length > 0) {
this.form.controls['id'].enable();
this.form.controls['keycloakId'].reset(undefined, { required: true });
this.form.controls["id"].enable();
this.form.controls["keycloakId"].reset(undefined, { required: true });
}
}
getCreateInput(): UserCreateInput {
return {
keycloakId: this.form.controls['keycloakId'].pristine
keycloakId: this.form.controls["keycloakId"].pristine
? undefined
: this.form.controls['keycloakId'].value,
roles: this.form.controls['roles'].pristine
: this.form.controls["keycloakId"].value,
roles: this.form.controls["roles"].pristine
? undefined
: this.form.controls['roles'].value,
: this.form.controls["roles"].value,
};
}
getUpdateInput(): UserUpdateInput {
return {
id: this.form.controls['id'].value,
roles: this.form.controls['roles'].pristine
id: this.form.controls["id"].value,
roles: this.form.controls["roles"].pristine
? undefined
: this.form.controls['roles'].value,
: this.form.controls["roles"].value,
};
}
create(user: UserCreateInput): void {
this.dataService.create(user).subscribe(() => {
this.spinner.hide();
this.toast.success('action.created');
this.toast.success("action.created");
this.close();
});
}
@ -107,7 +107,7 @@ export class UserFormPageComponent extends FormPageBase<
update(user: UserUpdateInput): void {
this.dataService.update(user).subscribe(() => {
this.spinner.hide();
this.toast.success('action.created');
this.toast.success("action.created");
this.close();
});
}

View File

@ -1,11 +1,11 @@
import { Injectable, Provider } from '@angular/core';
import { Injectable, Provider } from "@angular/core";
import {
DB_MODEL_COLUMNS,
ID_COLUMN,
PageColumns,
} from 'src/app/core/base/page.columns';
import { TableColumn } from 'src/app/modules/shared/components/table/table.model';
import { User } from 'src/app/model/auth/user';
} from "src/app/core/base/page.columns";
import { TableColumn } from "src/app/modules/shared/components/table/table.model";
import { User } from "src/app/model/auth/user";
@Injectable()
export class UsersColumns extends PageColumns<User> {
@ -13,15 +13,15 @@ export class UsersColumns extends PageColumns<User> {
return [
ID_COLUMN,
{
name: 'username',
label: 'user.username',
type: 'text',
name: "username",
label: "user.username",
type: "text",
value: (row: User) => row.username,
},
{
name: 'email',
label: 'user.email',
type: 'text',
name: "email",
label: "user.email",
type: "text",
value: (row: User) => row.email,
},
...DB_MODEL_COLUMNS,

View File

@ -1,26 +1,26 @@
import { Injectable, Provider } from '@angular/core';
import { Observable } from 'rxjs';
import { Injectable, Provider } from "@angular/core";
import { Observable } from "rxjs";
import {
Create,
Delete,
PageDataService,
Restore,
Update,
} from 'src/app/core/base/page.data.service';
import { Filter } from 'src/app/model/graphql/filter/filter.model';
import { Sort } from 'src/app/model/graphql/filter/sort.model';
import { Apollo, gql } from 'apollo-angular';
import { QueryResult } from 'src/app/model/entities/query-result';
import { DB_MODEL_FRAGMENT } from 'src/app/model/graphql/db-model.query';
import { catchError, map } from 'rxjs/operators';
import { SpinnerService } from 'src/app/service/spinner.service';
} from "src/app/core/base/page.data.service";
import { Filter } from "src/app/model/graphql/filter/filter.model";
import { Sort } from "src/app/model/graphql/filter/sort.model";
import { Apollo, gql } from "apollo-angular";
import { QueryResult } from "src/app/model/entities/query-result";
import { DB_MODEL_FRAGMENT } from "src/app/model/graphql/db-model.query";
import { catchError, map } from "rxjs/operators";
import { SpinnerService } from "src/app/service/spinner.service";
import {
NotExistingUser,
User,
UserCreateInput,
UserUpdateInput,
} from 'src/app/model/auth/user';
import { Role } from 'src/app/model/entities/role';
} from "src/app/model/auth/user";
import { Role } from "src/app/model/entities/role";
@Injectable()
export class UsersDataService
@ -33,7 +33,7 @@ export class UsersDataService
{
constructor(
private spinner: SpinnerService,
private apollo: Apollo
private apollo: Apollo,
) {
super();
}
@ -42,7 +42,7 @@ export class UsersDataService
filter?: Filter[] | undefined,
sort?: Sort[] | undefined,
skip?: number | undefined,
take?: number | undefined
take?: number | undefined,
): Observable<QueryResult<User>> {
return this.apollo
.query<{ users: QueryResult<User> }>({
@ -77,12 +77,12 @@ export class UsersDataService
},
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data.users));
.pipe(map((result) => result.data.users));
}
loadById(id: number): Observable<User> {
@ -115,12 +115,12 @@ export class UsersDataService
},
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data.users.nodes[0]));
.pipe(map((result) => result.data.users.nodes[0]));
}
create(object: UserCreateInput): Observable<User | undefined> {
@ -145,17 +145,17 @@ export class UsersDataService
variables: {
input: {
keycloakId: object.keycloakId,
roles: object.roles?.map(x => x.id),
roles: object.roles?.map((x) => x.id),
},
},
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data?.user.create));
.pipe(map((result) => result.data?.user.create));
}
update(object: UserUpdateInput): Observable<User | undefined> {
@ -180,17 +180,17 @@ export class UsersDataService
variables: {
input: {
id: object.id,
roles: object.roles?.map(x => x.id),
roles: object.roles?.map((x) => x.id),
},
},
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data?.user.update));
.pipe(map((result) => result.data?.user.update));
}
delete(object: User): Observable<boolean> {
@ -208,12 +208,12 @@ export class UsersDataService
},
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data?.user.delete ?? false));
.pipe(map((result) => result.data?.user.delete ?? false));
}
restore(object: User): Observable<boolean> {
@ -231,12 +231,12 @@ export class UsersDataService
},
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data?.user.restore ?? false));
.pipe(map((result) => result.data?.user.restore ?? false));
}
getAllRoles(): Observable<Role[]> {
@ -254,12 +254,12 @@ export class UsersDataService
`,
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data.roles.nodes));
.pipe(map((result) => result.data.roles.nodes));
}
getNotExistingUsersFromKeycloak(): Observable<NotExistingUser[]> {
@ -277,12 +277,12 @@ export class UsersDataService
`,
})
.pipe(
catchError(err => {
catchError((err) => {
this.spinner.hide();
throw err;
})
}),
)
.pipe(map(result => result.data.notExistingUsersFromKeycloak.nodes));
.pipe(map((result) => result.data.notExistingUsersFromKeycloak.nodes));
}
static provide(): Provider[] {

View File

@ -1,22 +1,22 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { RouterModule, Routes } from '@angular/router';
import { PermissionGuard } from 'src/app/core/guard/permission.guard';
import { PermissionsEnum } from 'src/app/model/auth/permissionsEnum';
import { UserFormPageComponent } from 'src/app/modules/admin/administration/users/form-page/user-form-page.component';
import { UsersPage } from 'src/app/modules/admin/administration/users/users.page';
import { UsersDataService } from 'src/app/modules/admin/administration/users/users.data.service';
import { UsersColumns } from 'src/app/modules/admin/administration/users/users.columns';
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { SharedModule } from "src/app/modules/shared/shared.module";
import { RouterModule, Routes } from "@angular/router";
import { PermissionGuard } from "src/app/core/guard/permission.guard";
import { PermissionsEnum } from "src/app/model/auth/permissionsEnum";
import { UserFormPageComponent } from "src/app/modules/admin/administration/users/form-page/user-form-page.component";
import { UsersPage } from "src/app/modules/admin/administration/users/users.page";
import { UsersDataService } from "src/app/modules/admin/administration/users/users.data.service";
import { UsersColumns } from "src/app/modules/admin/administration/users/users.columns";
const routes: Routes = [
{
path: '',
title: 'Admin - Users | Maxlan',
path: "",
title: "Admin - Users | Maxlan",
component: UsersPage,
children: [
{
path: 'create',
path: "create",
component: UserFormPageComponent,
canActivate: [PermissionGuard],
data: {
@ -24,7 +24,7 @@ const routes: Routes = [
},
},
{
path: 'edit/:id',
path: "edit/:id",
component: UserFormPageComponent,
canActivate: [PermissionGuard],
data: {

View File

@ -1,18 +1,18 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { UsersPage } from 'src/app/modules/admin/administration/users/users.page';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { TranslateModule } from '@ngx-translate/core';
import { AuthService } from 'src/app/service/auth.service';
import { KeycloakService } from 'keycloak-angular';
import { ErrorHandlingService } from 'src/app/service/error-handling.service';
import { ToastService } from 'src/app/service/toast.service';
import { ConfirmationService, MessageService } from 'primeng/api';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';
import { PageDataService } from 'src/app/core/base/page.data.service';
import { UsersDataService } from 'src/app/modules/admin/administration/users/users.data.service';
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { UsersPage } from "src/app/modules/admin/administration/users/users.page";
import { SharedModule } from "src/app/modules/shared/shared.module";
import { TranslateModule } from "@ngx-translate/core";
import { AuthService } from "src/app/service/auth.service";
import { KeycloakService } from "keycloak-angular";
import { ErrorHandlingService } from "src/app/service/error-handling.service";
import { ToastService } from "src/app/service/toast.service";
import { ConfirmationService, MessageService } from "primeng/api";
import { ActivatedRoute } from "@angular/router";
import { of } from "rxjs";
import { PageDataService } from "src/app/core/base/page.data.service";
import { UsersDataService } from "src/app/modules/admin/administration/users/users.data.service";
describe('UsersComponent', () => {
describe("UsersComponent", () => {
let component: UsersPage;
let fixture: ComponentFixture<UsersPage>;
@ -45,7 +45,7 @@ describe('UsersComponent', () => {
fixture.detectChanges();
});
it('should create', () => {
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,21 +1,21 @@
import { Component } from '@angular/core';
import { PageBase } from 'src/app/core/base/page-base';
import { ToastService } from 'src/app/service/toast.service';
import { ConfirmationDialogService } from 'src/app/service/confirmation-dialog.service';
import { PermissionsEnum } from 'src/app/model/auth/permissionsEnum';
import { User } from 'src/app/model/auth/user';
import { UsersColumns } from 'src/app/modules/admin/administration/users/users.columns';
import { UsersDataService } from 'src/app/modules/admin/administration/users/users.data.service';
import { Component } from "@angular/core";
import { PageBase } from "src/app/core/base/page-base";
import { ToastService } from "src/app/service/toast.service";
import { ConfirmationDialogService } from "src/app/service/confirmation-dialog.service";
import { PermissionsEnum } from "src/app/model/auth/permissionsEnum";
import { User } from "src/app/model/auth/user";
import { UsersColumns } from "src/app/modules/admin/administration/users/users.columns";
import { UsersDataService } from "src/app/modules/admin/administration/users/users.data.service";
@Component({
selector: 'app-users',
templateUrl: './users.page.html',
styleUrl: './users.page.scss',
selector: "app-users",
templateUrl: "./users.page.html",
styleUrl: "./users.page.scss",
})
export class UsersPage extends PageBase<User, UsersDataService, UsersColumns> {
constructor(
private toast: ToastService,
private confirmation: ConfirmationDialogService
private confirmation: ConfirmationDialogService,
) {
super(true, {
read: [PermissionsEnum.users],
@ -30,7 +30,7 @@ export class UsersPage extends PageBase<User, UsersDataService, UsersColumns> {
this.loading = true;
this.dataService
.load(this.filter, this.sort, this.skip, this.take)
.subscribe(result => {
.subscribe((result) => {
this.result = result;
this.loading = false;
});
@ -38,12 +38,12 @@ export class UsersPage extends PageBase<User, UsersDataService, UsersColumns> {
delete(user: User): void {
this.confirmation.confirmDialog({
header: 'dialog.delete.header',
message: 'dialog.delete.message',
header: "dialog.delete.header",
message: "dialog.delete.message",
accept: () => {
this.loading = true;
this.dataService.delete(user).subscribe(() => {
this.toast.success('action.deleted');
this.toast.success("action.deleted");
this.load();
});
},
@ -53,12 +53,12 @@ export class UsersPage extends PageBase<User, UsersDataService, UsersColumns> {
restore(user: User): void {
this.confirmation.confirmDialog({
header: 'dialog.restore.header',
message: 'dialog.restore.message',
header: "dialog.restore.header",
message: "dialog.restore.message",
accept: () => {
this.loading = true;
this.dataService.restore(user).subscribe(() => {
this.toast.success('action.restored');
this.toast.success("action.restored");
this.load();
});
},

View File

@ -1,17 +1,17 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RoleFormPageComponent } from 'src/app/modules/admin/administration/roles/form-page/role-form-page.component';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { TranslateModule } from '@ngx-translate/core';
import { AuthService } from 'src/app/service/auth.service';
import { ErrorHandlingService } from 'src/app/service/error-handling.service';
import { ToastService } from 'src/app/service/toast.service';
import { ConfirmationService, MessageService } from 'primeng/api';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';
import { ApiKeysDataService } from 'src/app/modules/admin/administration/api-keys/api-keys.data.service';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { RoleFormPageComponent } from "src/app/modules/admin/administration/roles/form-page/role-form-page.component";
import { SharedModule } from "src/app/modules/shared/shared.module";
import { TranslateModule } from "@ngx-translate/core";
import { AuthService } from "src/app/service/auth.service";
import { ErrorHandlingService } from "src/app/service/error-handling.service";
import { ToastService } from "src/app/service/toast.service";
import { ConfirmationService, MessageService } from "primeng/api";
import { ActivatedRoute } from "@angular/router";
import { of } from "rxjs";
import { ApiKeysDataService } from "src/app/modules/admin/administration/api-keys/api-keys.data.service";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
describe('ApiKeyFormpageComponent', () => {
describe("ApiKeyFormpageComponent", () => {
let component: RoleFormPageComponent;
let fixture: ComponentFixture<RoleFormPageComponent>;
@ -44,7 +44,7 @@ describe('ApiKeyFormpageComponent', () => {
fixture.detectChanges();
});
it('should create', () => {
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,18 +1,18 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ApiKeysPage } from 'src/app/modules/admin/administration/api-keys/api-keys.page';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { TranslateModule } from '@ngx-translate/core';
import { AuthService } from 'src/app/service/auth.service';
import { KeycloakService } from 'keycloak-angular';
import { ErrorHandlingService } from 'src/app/service/error-handling.service';
import { ToastService } from 'src/app/service/toast.service';
import { ConfirmationService, MessageService } from 'primeng/api';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';
import { PageDataService } from 'src/app/core/base/page.data.service';
import { ApiKeysDataService } from 'src/app/modules/admin/administration/api-keys/api-keys.data.service';
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { ApiKeysPage } from "src/app/modules/admin/administration/api-keys/api-keys.page";
import { SharedModule } from "src/app/modules/shared/shared.module";
import { TranslateModule } from "@ngx-translate/core";
import { AuthService } from "src/app/service/auth.service";
import { KeycloakService } from "keycloak-angular";
import { ErrorHandlingService } from "src/app/service/error-handling.service";
import { ToastService } from "src/app/service/toast.service";
import { ConfirmationService, MessageService } from "primeng/api";
import { ActivatedRoute } from "@angular/router";
import { of } from "rxjs";
import { PageDataService } from "src/app/core/base/page.data.service";
import { ApiKeysDataService } from "src/app/modules/admin/administration/api-keys/api-keys.data.service";
describe('ApiKeysComponent', () => {
describe("ApiKeysComponent", () => {
let component: ApiKeysPage;
let fixture: ComponentFixture<ApiKeysPage>;
@ -45,7 +45,7 @@ describe('ApiKeysComponent', () => {
fixture.detectChanges();
});
it('should create', () => {
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,10 +1,9 @@
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {RouterModule, Routes} from '@angular/router';
import {SharedModule} from 'src/app/modules/shared/shared.module';
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { RouterModule, Routes } from "@angular/router";
import { SharedModule } from "src/app/modules/shared/shared.module";
const routes: Routes = [
];
const routes: Routes = [];
@NgModule({
declarations: [],

View File

@ -20,7 +20,7 @@
<input pInputText class="value" type="number" formControlName="id"/>
</div>
<div class="form-page-input">
<p class="label">{{ 'common.short_url' | translate }}</p>
<p class="label">{{ 'short_url.short_url' | translate }}</p>
<input
pInputText
class="value"
@ -28,7 +28,7 @@
formControlName="shortUrl"/>
</div>
<div class="form-page-input">
<p class="label">{{ 'common.target_url' | translate }}</p>
<p class="label">{{ 'short_url.target_url' | translate }}</p>
<input
pInputText
class="value"

View File

@ -1,17 +1,17 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RoleFormPageComponent } from 'src/app/modules/admin/administration/roles/form-page/role-form-page.component';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { TranslateModule } from '@ngx-translate/core';
import { AuthService } from 'src/app/service/auth.service';
import { ErrorHandlingService } from 'src/app/service/error-handling.service';
import { ToastService } from 'src/app/service/toast.service';
import { ConfirmationService, MessageService } from 'primeng/api';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';
import { ApiKeysDataService } from 'src/app/modules/admin/administration/api-keys/api-keys.data.service';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { RoleFormPageComponent } from "src/app/modules/admin/administration/roles/form-page/role-form-page.component";
import { SharedModule } from "src/app/modules/shared/shared.module";
import { TranslateModule } from "@ngx-translate/core";
import { AuthService } from "src/app/service/auth.service";
import { ErrorHandlingService } from "src/app/service/error-handling.service";
import { ToastService } from "src/app/service/toast.service";
import { ConfirmationService, MessageService } from "primeng/api";
import { ActivatedRoute } from "@angular/router";
import { of } from "rxjs";
import { ApiKeysDataService } from "src/app/modules/admin/administration/api-keys/api-keys.data.service";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
describe('ApiKeyFormpageComponent', () => {
describe("ApiKeyFormpageComponent", () => {
let component: RoleFormPageComponent;
let fixture: ComponentFixture<RoleFormPageComponent>;
@ -44,7 +44,7 @@ describe('ApiKeyFormpageComponent', () => {
fixture.detectChanges();
});
it('should create', () => {
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -65,9 +65,22 @@ export class ShortUrlFormPageComponent extends FormPageBase<
this.form.controls["id"].disable();
}
private generateRandomString(length: number): string {
const characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let result = "";
const charactersLength = characters.length;
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
setForm(node?: ShortUrl) {
this.form.controls["id"].setValue(node?.id);
this.form.controls["shortUrl"].setValue(node?.shortUrl);
this.form.controls["shortUrl"].setValue(
node?.shortUrl ?? this.generateRandomString(8),
);
this.form.controls["targetUrl"].setValue(node?.targetUrl);
this.form.controls["description"].setValue(node?.description);
this.form.controls["groupId"].setValue(node?.group?.id);
@ -75,9 +88,7 @@ export class ShortUrlFormPageComponent extends FormPageBase<
getCreateInput(): ShortUrlCreateInput {
return {
shortUrl: this.form.controls["shortUrl"].pristine
? undefined
: (this.form.controls["shortUrl"].value ?? undefined),
shortUrl: this.form.controls["shortUrl"].value ?? undefined,
targetUrl: this.form.controls["targetUrl"].pristine
? undefined
: (this.form.controls["targetUrl"].value ?? undefined),

View File

@ -14,14 +14,14 @@ export class ShortUrlsColumns extends PageColumns<ShortUrl> {
ID_COLUMN,
{
name: "short_url",
label: "common.short_url",
label: "short_url.short_url",
type: "text",
filterable: true,
value: (row: ShortUrl) => row.shortUrl,
},
{
name: "target_url",
label: "common.target_url",
label: "short_url.target_url",
type: "text",
filterable: true,
value: (row: ShortUrl) => row.targetUrl,
@ -33,13 +33,6 @@ export class ShortUrlsColumns extends PageColumns<ShortUrl> {
filterable: true,
value: (row: ShortUrl) => row.description,
},
{
name: "group",
label: "common.group",
type: "text",
filterable: true,
value: (row: ShortUrl) => row.group?.name,
},
...DB_MODEL_COLUMNS,
];
}

View File

@ -1,19 +1,107 @@
<app-table
[rows]="result.nodes"
[columns]="columns"
[rowsPerPageOptions]="rowsPerPageOptions"
[totalCount]="result.totalCount"
[requireAnyPermissions]="requiredPermissions"
countHeaderTranslation="group.count_header"
[loading]="loading"
[(filter)]="filter"
[(sort)]="sort"
[(skip)]="skip"
[(take)]="take"
(load)="load()"
[create]="true"
[update]="true"
(delete)="delete($event)"
(restore)="restore($event)"></app-table>
<router-outlet></router-outlet>
<ng-template #shortUrl let-url>
<div class="flex flex-col gap-2 bg rounded-l p-3">
<div class="flex flex-col gap-2">
<h3>{{ url.shortUrl }}</h3>
<div class="grid-container">
<span class="grid-label font-bold">{{ 'short_url.target_url' | translate }}:</span>
<a class="grid-value" [href]="url.targetUrl" target="_blank">{{ url.targetUrl }}</a>
</div>
<div class="grid-container">
<span class="grid-label font-bold">{{ 'common.description' | translate }}:</span>
<span class="grid-value">{{ url.description }}</span>
</div>
<div class="grid-container">
<span class="grid-label font-bold">{{ 'short_url.visits' | translate }}:</span>
<span class="grid-value">{{ url.visits }}</span>
</div>
</div>
<div class="flex justify-end">
<p-button
class="icon-btn btn"
icon="pi pi-clone"
(onClick)="copy(url.shortUrl)"></p-button>
<p-button
class="icon-btn btn"
icon="pi pi-external-link"
(onClick)="open(url.shortUrl)"></p-button>
<p-button
*ngIf="hasPermissions.update"
class="icon-btn btn"
icon="pi pi-pencil"
tooltipPosition="left"
pTooltip="{{ 'table.update' | translate }}"
[disabled]="url?.deleted"
routerLink="edit/{{ url.id }}"></p-button>
<p-button
*ngIf="hasPermissions.delete"
class="icon-btn btn danger-icon-btn"
icon="pi pi-trash"
tooltipPosition="left"
pTooltip="{{ 'table.delete' | translate }}"
[disabled]="url?.deleted"
(click)="delete(url)"></p-button>
<p-button
*ngIf="url?.deleted && hasPermissions.restore"
class="icon-btn btn"
icon="pi pi-undo"
tooltipPosition="left"
pTooltip="{{ 'table.restore' | translate }}"
(click)="restore(url)"></p-button>
</div>
</div>
</ng-template>
<div class="flex flex-col gap-2">
<div class="flex justify-between gap-1">
<div><h1>{{ 'short_url.short_url' | translate }}</h1></div>
<div class="flex space-x-2">
<p-button
*ngIf="hasPermissions.create"
class="icon-btn btn"
icon="pi pi-plus"
tooltipPosition="left"
pTooltip="{{ 'table.create' | translate }}"
routerLink="create"></p-button>
<p-button
class="icon-btn btn"
[styleClass]="showDeleted ? 'highlight2' : ''"
icon="pi pi-trash"
tooltipPosition="left"
pTooltip="{{
(showDeleted ? 'table.hide_deleted' : 'table.show_deleted')
| translate
}}"
(click)="toggleShowDeleted()"></p-button>
<p-button
class="icon-btn btn"
icon="pi pi-sort-alt-slash"
tooltipPosition="left"
pTooltip="{{ 'table.reset_sort' | translate }}"
(click)="resetSort()"></p-button>
<p-button
class="icon-btn btn"
icon="pi pi-filter-slash"
tooltipPosition="left"
pTooltip="{{ 'table.reset_filters' | translate }}"
(click)="resetFilters()"></p-button>
</div>
</div>
<div class="divider"></div>
<div class="bg2 rounded-xl p-3">
<div *ngFor="let url of shortUrlsWithoutGroup">
<ng-template [ngTemplateOutlet]="shortUrl" [ngTemplateOutletContext]="{ $implicit: url }"></ng-template>
</div>
</div>
<div *ngFor="let group of groupsFromGroupedShortUrls" class="bg2 rounded-xl p-3">
<div><h2>{{ group }}</h2></div>
<div class="flex flex-col gap-1.5">
<ng-template *ngFor="let url of groupedShortUrls[group]" [ngTemplateOutlet]="shortUrl"
[ngTemplateOutletContext]="{ $implicit: url }"></ng-template>
</div>
</div>
</div>

View File

@ -0,0 +1,14 @@
.grid-container {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 10px;
.grid-label {
grid-column: 1;
}
.grid-value {
grid-column: 2;
word-break: break-all;
}
}

View File

@ -1,18 +1,18 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ApiKeysPage } from 'src/app/modules/admin/administration/api-keys/api-keys.page';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { TranslateModule } from '@ngx-translate/core';
import { AuthService } from 'src/app/service/auth.service';
import { KeycloakService } from 'keycloak-angular';
import { ErrorHandlingService } from 'src/app/service/error-handling.service';
import { ToastService } from 'src/app/service/toast.service';
import { ConfirmationService, MessageService } from 'primeng/api';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';
import { PageDataService } from 'src/app/core/base/page.data.service';
import { ApiKeysDataService } from 'src/app/modules/admin/administration/api-keys/api-keys.data.service';
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { ApiKeysPage } from "src/app/modules/admin/administration/api-keys/api-keys.page";
import { SharedModule } from "src/app/modules/shared/shared.module";
import { TranslateModule } from "@ngx-translate/core";
import { AuthService } from "src/app/service/auth.service";
import { KeycloakService } from "keycloak-angular";
import { ErrorHandlingService } from "src/app/service/error-handling.service";
import { ToastService } from "src/app/service/toast.service";
import { ConfirmationService, MessageService } from "primeng/api";
import { ActivatedRoute } from "@angular/router";
import { of } from "rxjs";
import { PageDataService } from "src/app/core/base/page.data.service";
import { ApiKeysDataService } from "src/app/modules/admin/administration/api-keys/api-keys.data.service";
describe('ApiKeysComponent', () => {
describe("ApiKeysComponent", () => {
let component: ApiKeysPage;
let fixture: ComponentFixture<ApiKeysPage>;
@ -45,7 +45,7 @@ describe('ApiKeysComponent', () => {
fixture.detectChanges();
});
it('should create', () => {
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,4 +1,4 @@
import { Component } from "@angular/core";
import { Component, OnInit } from "@angular/core";
import { PageBase } from "src/app/core/base/page-base";
import { ToastService } from "src/app/service/toast.service";
import { ConfirmationDialogService } from "src/app/service/confirmation-dialog.service";
@ -6,20 +6,44 @@ import { PermissionsEnum } from "src/app/model/auth/permissionsEnum";
import { ShortUrl } from "src/app/model/entities/short-url";
import { ShortUrlsDataService } from "src/app/modules/admin/short-urls/short-urls.data.service";
import { ShortUrlsColumns } from "src/app/modules/admin/short-urls/short-urls.columns";
import { AuthService } from "src/app/service/auth.service";
import { Filter } from "src/app/model/graphql/filter/filter.model";
@Component({
selector: "app-short-urls",
templateUrl: "./short-urls.page.html",
styleUrl: "./short-urls.page.scss",
})
export class ShortUrlsPage extends PageBase<
ShortUrl,
ShortUrlsDataService,
ShortUrlsColumns
> {
export class ShortUrlsPage
extends PageBase<ShortUrl, ShortUrlsDataService, ShortUrlsColumns>
implements OnInit
{
shortUrlsWithoutGroup: ShortUrl[] = [];
groupedShortUrls: { [key: string]: ShortUrl[] } = {};
get groupsFromGroupedShortUrls() {
return Object.keys(this.groupedShortUrls);
}
private hide_deleted_filter: Filter = { deleted: { equal: false } };
get showDeleted() {
return !this.filter.some(
(f) => JSON.stringify(f) === JSON.stringify(this.hide_deleted_filter),
);
}
protected hasPermissions = {
read: false,
create: false,
update: false,
delete: false,
restore: false,
};
constructor(
private toast: ToastService,
private confirmation: ConfirmationDialogService,
private auth: AuthService,
) {
super(true, {
read: [PermissionsEnum.shortUrls],
@ -30,12 +54,41 @@ export class ShortUrlsPage extends PageBase<
});
}
async ngOnInit() {
this.hasPermissions = {
read: await this.auth.hasAnyPermissionLazy(
this.requiredPermissions.read ?? [],
),
create: await this.auth.hasAnyPermissionLazy(
this.requiredPermissions.create ?? [],
),
update: await this.auth.hasAnyPermissionLazy(
this.requiredPermissions.update ?? [],
),
delete: await this.auth.hasAnyPermissionLazy(
this.requiredPermissions.delete ?? [],
),
restore: await this.auth.hasAnyPermissionLazy(
this.requiredPermissions.restore ?? [],
),
};
}
load(): void {
this.loading = true;
this.dataService
.load(this.filter, this.sort, this.skip, this.take)
.subscribe((result) => {
this.result = result;
this.shortUrlsWithoutGroup = this.getShortUrlsWithoutGroup();
this.groupedShortUrls = this.getShortUrlsWithGroup();
console.warn(
"result",
result,
this.shortUrlsWithoutGroup,
this.groupedShortUrls,
);
this.loading = false;
});
}
@ -69,4 +122,54 @@ export class ShortUrlsPage extends PageBase<
messageParams: { entity: group.shortUrl },
});
}
toggleShowDeleted() {
if (!this.showDeleted) {
this.filter.splice(this.filter.indexOf(this.hide_deleted_filter), 1);
} else {
this.filter.push(this.hide_deleted_filter);
}
this.load();
}
resetSort() {
this.sort = [];
this.load();
}
resetFilters() {
this.filter = [];
this.load();
}
open(url: string) {
window.open(url, "_blank");
}
copy(val: string) {
navigator.clipboard.writeText(`${window.origin}/${val}`).then(() => {
this.toast.info("common.copied", "common.copied_to_clipboard");
});
}
getShortUrlsWithoutGroup(): ShortUrl[] {
return this.result.nodes.filter((shortUrl) => !shortUrl.group);
}
getShortUrlsWithGroup() {
const groupedShortUrls: { [key: string]: ShortUrl[] } = {};
this.result.nodes.forEach((shortUrl) => {
if (!shortUrl.group) return;
const groupName = shortUrl.group.name;
if (!groupedShortUrls[groupName]) {
groupedShortUrls[groupName] = [];
}
groupedShortUrls[groupName].push(shortUrl);
});
return groupedShortUrls;
}
}

View File

@ -1,8 +1,8 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { MenuBarComponent } from 'src/app/modules/shared/components/menu-bar/menu-bar.component';
import { MenuBarComponent } from "src/app/modules/shared/components/menu-bar/menu-bar.component";
describe('MenuBarComponent', () => {
describe("MenuBarComponent", () => {
let component: MenuBarComponent;
let fixture: ComponentFixture<MenuBarComponent>;
@ -16,7 +16,7 @@ describe('MenuBarComponent', () => {
fixture.detectChanges();
});
it('should create', () => {
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,10 +1,10 @@
import { Component, Input } from '@angular/core';
import { MenuElement } from 'src/app/model/view/menu-element';
import { Component, Input } from "@angular/core";
import { MenuElement } from "src/app/model/view/menu-element";
@Component({
selector: 'app-menu-bar',
templateUrl: './menu-bar.component.html',
styleUrl: './menu-bar.component.scss',
selector: "app-menu-bar",
templateUrl: "./menu-bar.component.html",
styleUrl: "./menu-bar.component.scss",
})
export class MenuBarComponent {
@Input() elements: MenuElement[] = [];

View File

@ -1,8 +1,8 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { SideMenuComponent } from './side-menu.component';
import { SideMenuComponent } from "./side-menu.component";
describe('SideMenuComponent', () => {
describe("SideMenuComponent", () => {
let component: SideMenuComponent;
let fixture: ComponentFixture<SideMenuComponent>;
@ -16,7 +16,7 @@ describe('SideMenuComponent', () => {
fixture.detectChanges();
});
it('should create', () => {
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,10 +1,10 @@
import { Component, Input } from '@angular/core';
import { MenuElement } from 'src/app/model/view/menu-element';
import { Component, Input } from "@angular/core";
import { MenuElement } from "src/app/model/view/menu-element";
@Component({
selector: 'app-side-menu',
templateUrl: './side-menu.component.html',
styleUrl: './side-menu.component.scss',
selector: "app-side-menu",
templateUrl: "./side-menu.component.html",
styleUrl: "./side-menu.component.scss",
})
export class SideMenuComponent {
@Input() elements: MenuElement[] = [];

View File

@ -1,7 +1,7 @@
<p-sidebar
[visible]="true"
position="right"
[style]="{ width: 'min-content', minWidth: '500px' }"
[style]="{ width: 'min-content', minWidth: '350px' }"
(onHide)="onClose.emit()"
(visibleChange)="!$event ? onClose.emit() : undefined">
<ng-template pTemplate="headless">

View File

@ -1,18 +1,18 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FormPageComponent } from 'src/app/modules/shared/components/slidein/form-page.component';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { TranslateModule } from '@ngx-translate/core';
import { AuthService } from 'src/app/service/auth.service';
import { KeycloakService } from 'keycloak-angular';
import { ErrorHandlingService } from 'src/app/service/error-handling.service';
import { ToastService } from 'src/app/service/toast.service';
import { ConfirmationService, MessageService } from 'primeng/api';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';
import { FormGroup } from '@angular/forms';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { FormPageComponent } from "src/app/modules/shared/components/slidein/form-page.component";
import { SharedModule } from "src/app/modules/shared/shared.module";
import { TranslateModule } from "@ngx-translate/core";
import { AuthService } from "src/app/service/auth.service";
import { KeycloakService } from "keycloak-angular";
import { ErrorHandlingService } from "src/app/service/error-handling.service";
import { ToastService } from "src/app/service/toast.service";
import { ConfirmationService, MessageService } from "primeng/api";
import { ActivatedRoute } from "@angular/router";
import { of } from "rxjs";
import { FormGroup } from "@angular/forms";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
describe('FormpageComponent', () => {
describe("FormpageComponent", () => {
let component: FormPageComponent<string>;
let fixture: ComponentFixture<FormPageComponent<string>>;
@ -46,7 +46,7 @@ describe('FormpageComponent', () => {
fixture.detectChanges();
});
it('should create', () => {
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -5,18 +5,18 @@ import {
Input,
Output,
TemplateRef,
} from '@angular/core';
import { FormGroup } from '@angular/forms';
import { SpinnerService } from 'src/app/service/spinner.service';
} from "@angular/core";
import { FormGroup } from "@angular/forms";
import { SpinnerService } from "src/app/service/spinner.service";
import {
FormPageContentDirective,
FormPageHeaderDirective,
} from 'src/app/modules/shared/form';
} from "src/app/modules/shared/form";
@Component({
selector: 'app-form-page',
templateUrl: './form-page.component.html',
styleUrl: './form-page.component.scss',
selector: "app-form-page",
templateUrl: "./form-page.component.html",
styleUrl: "./form-page.component.scss",
})
export class FormPageComponent<T> {
@Input({ required: true }) formGroup!: FormGroup;

View File

@ -73,7 +73,7 @@
[class]="column.class ?? ''">
<div class="flex items-center space-x-2">
<span>{{ column.label | translate }}</span>
<p-sortIcon [field]="column.name"></p-sortIcon>
<p-sortIcon *ngIf="column.sortable !== false" [field]="column.name"></p-sortIcon>
</div>
</th>
<th *ngIf="update || delete.observed"></th>
@ -136,7 +136,12 @@
</ng-container>
</td>
</ng-container>
<td class="flex max-w-32">
<td class="flex overflow-hidden">
<ng-container
*ngTemplateOutlet="
customActions;
context: { $implicit: row }
"></ng-container>
<p-button
*ngIf="update && hasPermissions.update"
class="icon-btn btn"

View File

@ -1,17 +1,17 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { TableComponent } from './table.component';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { TranslateModule } from '@ngx-translate/core';
import { AuthService } from 'src/app/service/auth.service';
import { KeycloakService } from 'keycloak-angular';
import { ErrorHandlingService } from 'src/app/service/error-handling.service';
import { ToastService } from 'src/app/service/toast.service';
import { ConfirmationService, MessageService } from 'primeng/api';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';
import { TableComponent } from "./table.component";
import { SharedModule } from "src/app/modules/shared/shared.module";
import { TranslateModule } from "@ngx-translate/core";
import { AuthService } from "src/app/service/auth.service";
import { KeycloakService } from "keycloak-angular";
import { ErrorHandlingService } from "src/app/service/error-handling.service";
import { ToastService } from "src/app/service/toast.service";
import { ConfirmationService, MessageService } from "primeng/api";
import { ActivatedRoute } from "@angular/router";
import { of } from "rxjs";
describe('TableComponent', () => {
describe("TableComponent", () => {
let component: TableComponent<string>;
let fixture: ComponentFixture<TableComponent<string>>;
@ -40,7 +40,7 @@ describe('TableComponent', () => {
fixture.detectChanges();
});
it('should create', () => {
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,26 +1,44 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import {
Component,
ContentChild,
Directive,
EventEmitter,
Input,
OnInit,
Output,
TemplateRef,
} from "@angular/core";
import {
FilterMode,
ResolvedTableColumn,
TableColumn,
TableRequireAnyPermissions,
} from 'src/app/modules/shared/components/table/table.model';
import { TableLazyLoadEvent } from 'primeng/table';
import { RowsPerPageOption } from 'src/app/service/filter.service';
import { Filter } from 'src/app/model/graphql/filter/filter.model';
import { Sort, SortOrder } from 'src/app/model/graphql/filter/sort.model';
import { FormControl, FormGroup } from '@angular/forms';
import { debounceTime, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Logger } from 'src/app/service/logger.service';
import { AuthService } from 'src/app/service/auth.service';
import { ToastService } from 'src/app/service/toast.service';
} from "src/app/modules/shared/components/table/table.model";
import { TableLazyLoadEvent } from "primeng/table";
import { RowsPerPageOption } from "src/app/service/filter.service";
import { Filter } from "src/app/model/graphql/filter/filter.model";
import { Sort, SortOrder } from "src/app/model/graphql/filter/sort.model";
import { FormControl, FormGroup } from "@angular/forms";
import { debounceTime, Subject } from "rxjs";
import { takeUntil } from "rxjs/operators";
import { Logger } from "src/app/service/logger.service";
import { AuthService } from "src/app/service/auth.service";
import { ToastService } from "src/app/service/toast.service";
const logger = new Logger('TableComponent');
const logger = new Logger("TableComponent");
@Directive({
// eslint-disable-next-line @angular-eslint/directive-selector
selector: "[customAction]",
})
export class CustomActionDirective {
constructor(public templateRef: TemplateRef<unknown>) {}
}
@Component({
selector: 'app-table',
templateUrl: './table.component.html',
styleUrl: './table.component.scss',
selector: "app-table",
templateUrl: "./table.component.html",
styleUrl: "./table.component.scss",
})
export class TableComponent<T> implements OnInit {
private _rows: T[] = [];
@ -57,17 +75,20 @@ export class TableComponent<T> implements OnInit {
@Output() load = new EventEmitter<void>();
@Input() loading = true;
@Input() dataKey = 'id';
@Input() responsiveLayout: 'stack' | 'scroll' = 'stack';
@Input() dataKey = "id";
@Input() responsiveLayout: "stack" | "scroll" = "stack";
@Input() create = false;
@Input() update = false;
@Input() createBaseUrl = '';
@Input() updateBaseUrl = '';
@Input() createBaseUrl = "";
@Input() updateBaseUrl = "";
@Output() delete: EventEmitter<T> = new EventEmitter<T>();
@Output() restore: EventEmitter<T> = new EventEmitter<T>();
@ContentChild(CustomActionDirective, { read: TemplateRef })
customActions!: TemplateRef<never>;
protected resolvedColumns: ResolvedTableColumn<T>[][] = [];
protected filterForm!: FormGroup;
protected defaultFilterForm!: FormGroup;
@ -76,12 +97,12 @@ export class TableComponent<T> implements OnInit {
get showDeleted() {
return !this.filter.some(
f => JSON.stringify(f) === JSON.stringify(this.hide_deleted_filter)
(f) => JSON.stringify(f) === JSON.stringify(this.hide_deleted_filter),
);
}
get showFilters() {
return this.columns.some(x => x.filterable);
return this.columns.some((x) => x.filterable);
}
protected unsubscriber$ = new Subject<void>();
@ -96,25 +117,25 @@ export class TableComponent<T> implements OnInit {
constructor(
private auth: AuthService,
private toast: ToastService
private toast: ToastService,
) {}
async ngOnInit() {
this.hasPermissions = {
read: await this.auth.hasAnyPermissionLazy(
this.requireAnyPermissions.read ?? []
this.requireAnyPermissions.read ?? [],
),
create: await this.auth.hasAnyPermissionLazy(
this.requireAnyPermissions.create ?? []
this.requireAnyPermissions.create ?? [],
),
update: await this.auth.hasAnyPermissionLazy(
this.requireAnyPermissions.update ?? []
this.requireAnyPermissions.update ?? [],
),
delete: await this.auth.hasAnyPermissionLazy(
this.requireAnyPermissions.delete ?? []
this.requireAnyPermissions.delete ?? [],
),
restore: await this.auth.hasAnyPermissionLazy(
this.requireAnyPermissions.restore ?? []
this.requireAnyPermissions.restore ?? [],
),
};
@ -131,9 +152,9 @@ export class TableComponent<T> implements OnInit {
}
const resolvedColumns: ResolvedTableColumn<T>[][] = [];
this.rows.forEach(row => {
this.rows.forEach((row) => {
const resolvedRow: ResolvedTableColumn<T>[] = [];
this.columns.forEach(column => {
this.columns.forEach((column) => {
resolvedRow.push({
value: column.value(row),
data: row,
@ -147,7 +168,7 @@ export class TableComponent<T> implements OnInit {
}
loadData(event: TableLazyLoadEvent) {
logger.trace('lazy load event', event);
logger.trace("lazy load event", event);
const { rows, first, sortField, sortOrder } = event;
const reload =
@ -172,9 +193,9 @@ export class TableComponent<T> implements OnInit {
) {
if (sortField instanceof Array) {
this.sortChange.emit(
sortField.map(x => ({
sortField.map((x) => ({
[x]: sortOrder === 1 ? SortOrder.ASC : SortOrder.DESC,
}))
})),
);
} else {
this.sortChange.emit([
@ -211,17 +232,17 @@ export class TableComponent<T> implements OnInit {
buildDefaultFilterForm() {
this.defaultFilterForm = new FormGroup({});
this.columns
.filter(x => x.filterable)
.forEach(x => {
.filter((x) => x.filterable)
.forEach((x) => {
let control!: FormControl;
if (x.type === 'text') {
if (x.type === "text") {
control = new FormControl<string | undefined>(undefined);
} else if (x.type === 'number') {
} else if (x.type === "number") {
control = new FormControl<number | undefined>(undefined);
} else if (x.type === 'bool') {
} else if (x.type === "bool") {
control = new FormControl<boolean | undefined>(undefined);
} else if (x.type === 'date') {
} else if (x.type === "date") {
control = new FormControl<Date | undefined>(undefined);
} else {
control = new FormControl<unknown | undefined>(undefined);
@ -231,14 +252,14 @@ export class TableComponent<T> implements OnInit {
}
setDefaultFilterForm() {
this.defaultFilter.forEach(x => {
Object.keys(x).forEach(key => {
this.defaultFilter.forEach((x) => {
Object.keys(x).forEach((key) => {
const value = x[key];
if (!(key in this.defaultFilterForm.controls)) {
return;
}
if (typeof value === 'object' && value !== null) {
Object.keys(value).forEach(subKey => {
if (typeof value === "object" && value !== null) {
Object.keys(value).forEach((subKey) => {
this.defaultFilterForm.get([key])?.setValue(value[subKey]);
});
} else {
@ -253,38 +274,41 @@ export class TableComponent<T> implements OnInit {
this.filterForm.valueChanges
.pipe(takeUntil(this.unsubscriber$), debounceTime(200))
.subscribe(changes => {
logger.trace('Filter input', changes);
.subscribe((changes) => {
logger.trace("Filter input", changes);
if (this.filterForm.disabled) {
return;
}
const filter = Object.keys(changes)
.filter(
key =>
(key) =>
changes[key] !== undefined &&
changes[key] !== null &&
changes[key] !== ''
changes[key] !== "",
)
.map(key => {
const column = this.columns.find(x => x.name === key);
.map((key) => {
const column = this.columns.find((x) => x.name === key);
if (!column || !column.filterable) {
return {};
}
let value = changes[key];
let defaultFilterMode = 'contains';
let defaultFilterMode: FilterMode = "contains";
switch (column.type) {
case 'number':
defaultFilterMode = 'equal';
case "number":
defaultFilterMode = "equal";
value = +value;
break;
case 'bool':
defaultFilterMode = 'equal';
case "bool":
defaultFilterMode = "equal";
}
const filterMode = column.filterMode || defaultFilterMode;
if (column.filterFactory) {
return column.filterFactory(key, filterMode, value);
}
return { [key]: { [filterMode]: value } };
});
@ -300,7 +324,7 @@ export class TableComponent<T> implements OnInit {
copy(val: T | T[keyof T] | string) {
navigator.clipboard.writeText(val as string).then(() => {
this.toast.info('common.copied', 'common.copied_to_clipboard');
this.toast.info("common.copied", "common.copied_to_clipboard");
});
}
}

View File

@ -1,6 +1,8 @@
import { PermissionsEnum } from 'src/app/model/auth/permissionsEnum';
import { PermissionsEnum } from "src/app/model/auth/permissionsEnum";
import { Filter } from "src/app/model/graphql/filter/filter.model";
export type TableColumnValue<T> = T | T[keyof T] | string;
export type FilterMode = "contains" | "startsWith" | "endsWith" | "equal";
export interface TableColumn<T> {
name: string;
@ -12,7 +14,8 @@ export interface TableColumn<T> {
hidden?: boolean;
sortable?: boolean;
filterable?: boolean;
filterMode?: 'contains' | 'startsWith' | 'endsWith' | 'equals';
filterMode?: FilterMode;
filterFactory?: (key: string, mode: FilterMode, value: T) => Filter;
sort?: (a: T, b: T) => number;
filter?: (row: T, filter: string) => boolean;
width?: string;

View File

@ -1,17 +1,17 @@
import { addMinutes, format, parseISO } from 'date-fns';
import { addMinutes, format, parseISO } from "date-fns";
export function formatUTCDateToClientTimezone(date: string) {
const dateTZ = addMinutes(
parseISO(date),
new Date().getTimezoneOffset() * -1
new Date().getTimezoneOffset() * -1,
);
return format(dateTZ, 'yyyy-MM-dd HH:mm:ss');
return format(dateTZ, "yyyy-MM-dd HH:mm:ss");
}
export function formatUTCDateToGermanLocaleAndTimezone(date: string) {
const dateTZ = addMinutes(
parseISO(date),
new Date().getTimezoneOffset() * -1
new Date().getTimezoneOffset() * -1,
);
return format(dateTZ, 'dd.MM.yy HH:mm:ss');
return format(dateTZ, "dd.MM.yy HH:mm:ss");
}

View File

@ -1,8 +1,8 @@
import { Directive, TemplateRef } from '@angular/core';
import { Directive, TemplateRef } from "@angular/core";
@Directive({
// eslint-disable-next-line @angular-eslint/directive-selector
selector: '[formPageHeader]',
selector: "[formPageHeader]",
})
export class FormPageHeaderDirective {
constructor(public templateRef: TemplateRef<unknown>) {}
@ -10,7 +10,7 @@ export class FormPageHeaderDirective {
@Directive({
// eslint-disable-next-line @angular-eslint/directive-selector
selector: '[formPageContent]',
selector: "[formPageContent]",
})
export class FormPageContentDirective {
constructor(public templateRef: TemplateRef<unknown>) {}

View File

@ -1,15 +1,15 @@
import { Pipe, PipeTransform } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { Pipe, PipeTransform } from "@angular/core";
import { TranslateService } from "@ngx-translate/core";
@Pipe({
name: 'bool',
name: "bool",
})
export class BoolPipe implements PipeTransform {
constructor(private translate: TranslateService) {}
transform(value: unknown): string {
return this.translate.instant(
value === true || value === 'true' ? 'bool.true' : 'bool.false'
value === true || value === "true" ? "bool.true" : "bool.false",
);
}
}

View File

@ -1,23 +1,23 @@
import { Pipe, PipeTransform } from '@angular/core';
import { format } from 'date-fns';
import { Pipe, PipeTransform } from "@angular/core";
import { format } from "date-fns";
@Pipe({
name: 'customDate',
name: "customDate",
})
export class CustomDatePipe implements PipeTransform {
transform(value: unknown, dateFormat: string = 'yyyy-MM-dd'): string {
transform(value: unknown, dateFormat: string = "yyyy-MM-dd"): string {
if (!value) {
return '';
return "";
}
try {
const date =
typeof value === 'string' || typeof value === 'number'
typeof value === "string" || typeof value === "number"
? new Date(value)
: value;
return format(date as Date, dateFormat);
} catch (error) {
console.error('Error formatting date:', error);
return '';
console.error("Error formatting date:", error);
return "";
}
}
}

View File

@ -1,14 +1,14 @@
import { Pipe, PipeTransform } from '@angular/core';
import { Pipe, PipeTransform } from "@angular/core";
@Pipe({
name: 'protect',
name: "protect",
})
export class ProtectPipe implements PipeTransform {
transform(text?: unknown): string {
const len = 8;
if (text && typeof text === 'string' && text.length) {
return '*'.repeat(text.length);
if (text && typeof text === "string" && text.length) {
return "*".repeat(text.length);
}
return '*'.repeat(len);
return "*".repeat(len);
}
}

View File

@ -1,63 +1,66 @@
import { inject, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { StepsModule } from 'primeng/steps';
import { DialogModule } from 'primeng/dialog';
import { ToastModule } from 'primeng/toast';
import { ProgressSpinnerModule } from 'primeng/progressspinner';
import { ButtonModule } from 'primeng/button';
import { ButtonGroupModule } from 'primeng/buttongroup';
import { ConfirmDialogModule } from 'primeng/confirmdialog';
import { TableModule } from 'primeng/table';
import { InputTextModule } from 'primeng/inputtext';
import { CheckboxModule } from 'primeng/checkbox';
import { DropdownModule } from 'primeng/dropdown';
import { TranslateModule } from '@ngx-translate/core';
import { ImageModule } from 'primeng/image';
import { TabMenuModule } from 'primeng/tabmenu';
import { MenubarModule } from 'primeng/menubar';
import { PanelMenuModule } from 'primeng/panelmenu';
import { CardModule } from 'primeng/card';
import { MultiSelectModule } from 'primeng/multiselect';
import { SplitButtonModule } from 'primeng/splitbutton';
import { CalendarModule } from 'primeng/calendar';
import { PaginatorModule } from 'primeng/paginator';
import { DataViewModule } from 'primeng/dataview';
import { TagModule } from 'primeng/tag';
import { SidebarModule } from 'primeng/sidebar';
import { FileUploadModule } from 'primeng/fileupload';
import { MenuModule } from 'primeng/menu';
import { ChipModule } from 'primeng/chip';
import { BadgeModule } from 'primeng/badge';
import { ContextMenuModule } from 'primeng/contextmenu';
import { DragDropModule } from 'primeng/dragdrop';
import { InputSwitchModule } from 'primeng/inputswitch';
import { SelectButtonModule } from 'primeng/selectbutton';
import { BreadcrumbModule } from 'primeng/breadcrumb';
import { OverlayPanelModule } from 'primeng/overlaypanel';
import { TerminalModule } from 'primeng/terminal';
import { RatingModule } from 'primeng/rating';
import { FocusTrapModule } from 'primeng/focustrap';
import { InputMaskModule } from 'primeng/inputmask';
import { TriStateCheckboxModule } from 'primeng/tristatecheckbox';
import { InputTextareaModule } from 'primeng/inputtextarea';
import { MenuBarComponent } from 'src/app/modules/shared/components/menu-bar/menu-bar.component';
import { SideMenuComponent } from './components/side-menu/side-menu.component';
import { TableComponent } from './components/table/table.component';
import { BoolPipe } from 'src/app/modules/shared/pipes/bool.pipe';
import { CustomDatePipe } from 'src/app/modules/shared/pipes/customDate.pipe';
import { FormPageComponent } from 'src/app/modules/shared/components/slidein/form-page.component';
import { inject, NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { StepsModule } from "primeng/steps";
import { DialogModule } from "primeng/dialog";
import { ToastModule } from "primeng/toast";
import { ProgressSpinnerModule } from "primeng/progressspinner";
import { ButtonModule } from "primeng/button";
import { ButtonGroupModule } from "primeng/buttongroup";
import { ConfirmDialogModule } from "primeng/confirmdialog";
import { TableModule } from "primeng/table";
import { InputTextModule } from "primeng/inputtext";
import { CheckboxModule } from "primeng/checkbox";
import { DropdownModule } from "primeng/dropdown";
import { TranslateModule } from "@ngx-translate/core";
import { ImageModule } from "primeng/image";
import { TabMenuModule } from "primeng/tabmenu";
import { MenubarModule } from "primeng/menubar";
import { PanelMenuModule } from "primeng/panelmenu";
import { CardModule } from "primeng/card";
import { MultiSelectModule } from "primeng/multiselect";
import { SplitButtonModule } from "primeng/splitbutton";
import { CalendarModule } from "primeng/calendar";
import { PaginatorModule } from "primeng/paginator";
import { DataViewModule } from "primeng/dataview";
import { TagModule } from "primeng/tag";
import { SidebarModule } from "primeng/sidebar";
import { FileUploadModule } from "primeng/fileupload";
import { MenuModule } from "primeng/menu";
import { ChipModule } from "primeng/chip";
import { BadgeModule } from "primeng/badge";
import { ContextMenuModule } from "primeng/contextmenu";
import { DragDropModule } from "primeng/dragdrop";
import { InputSwitchModule } from "primeng/inputswitch";
import { SelectButtonModule } from "primeng/selectbutton";
import { BreadcrumbModule } from "primeng/breadcrumb";
import { OverlayPanelModule } from "primeng/overlaypanel";
import { TerminalModule } from "primeng/terminal";
import { RatingModule } from "primeng/rating";
import { FocusTrapModule } from "primeng/focustrap";
import { InputMaskModule } from "primeng/inputmask";
import { TriStateCheckboxModule } from "primeng/tristatecheckbox";
import { InputTextareaModule } from "primeng/inputtextarea";
import { MenuBarComponent } from "src/app/modules/shared/components/menu-bar/menu-bar.component";
import { SideMenuComponent } from "./components/side-menu/side-menu.component";
import {
CustomActionDirective,
TableComponent,
} from "./components/table/table.component";
import { BoolPipe } from "src/app/modules/shared/pipes/bool.pipe";
import { CustomDatePipe } from "src/app/modules/shared/pipes/customDate.pipe";
import { FormPageComponent } from "src/app/modules/shared/components/slidein/form-page.component";
import {
FormPageContentDirective,
FormPageHeaderDirective,
} from 'src/app/modules/shared/form';
import { ProtectPipe } from './pipes/protect.pipe';
import { provideApollo } from 'apollo-angular';
import { HttpLink } from 'apollo-angular/http';
import { environment } from 'src/environments/environment';
import { InMemoryCache } from '@apollo/client/core';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { tokenInterceptor } from 'src/app/core/token.interceptor';
} from "src/app/modules/shared/form";
import { ProtectPipe } from "./pipes/protect.pipe";
import { provideApollo } from "apollo-angular";
import { HttpLink } from "apollo-angular/http";
import { environment } from "src/environments/environment";
import { InMemoryCache } from "@apollo/client/core";
import { provideHttpClient, withInterceptors } from "@angular/common/http";
import { tokenInterceptor } from "src/app/core/token.interceptor";
const sharedModules = [
StepsModule,
@ -114,6 +117,7 @@ const sharedComponents = [
FormPageComponent,
FormPageHeaderDirective,
FormPageContentDirective,
CustomActionDirective,
];
@NgModule({
@ -131,13 +135,13 @@ const sharedComponents = [
defaultOptions: {
watchQuery: {
fetchPolicy: 'no-cache',
fetchPolicy: "no-cache",
},
query: {
fetchPolicy: 'no-cache',
fetchPolicy: "no-cache",
},
mutate: {
fetchPolicy: 'no-cache',
fetchPolicy: "no-cache",
},
},
};

Some files were not shown because too many files have changed in this diff Show More