From 165c140a25b0fb491fca13639169231ea855d5c8 Mon Sep 17 00:00:00 2001 From: edraft Date: Fri, 18 Apr 2025 11:03:13 +0200 Subject: [PATCH] Added history to frontend --- api/src/core/database/abc/db_model_abc.py | 2 +- web/src/app/model/entities/domain.ts | 4 +- web/src/app/model/entities/group.ts | 4 +- web/src/app/model/entities/short-url.ts | 4 +- .../admin/domains/domains.data.service.ts | 46 ++++++++++++- .../modules/admin/domains/domains.module.ts | 11 +++- .../modules/admin/domains/domains.page.html | 1 + .../domains/history/history.component.html | 3 + .../domains/history/history.component.scss | 0 .../domains/history/history.component.spec.ts | 65 +++++++++++++++++++ .../domains/history/history.component.ts | 18 +++++ .../admin/groups/groups.data.service.ts | 47 +++++++++++++- .../app/modules/admin/groups/groups.module.ts | 39 ++++++----- .../app/modules/admin/groups/groups.page.html | 1 + .../groups/history/history.component.html | 3 + .../groups/history/history.component.scss | 0 .../groups/history/history.component.spec.ts | 65 +++++++++++++++++++ .../admin/groups/history/history.component.ts | 18 +++++ .../short-urls/history/history.component.html | 3 + .../short-urls/history/history.component.scss | 0 .../history/history.component.spec.ts | 65 +++++++++++++++++++ .../short-urls/history/history.component.ts | 18 +++++ .../short-urls/short-urls.data.service.ts | 56 +++++++++++++++- .../admin/short-urls/short-urls.module.ts | 11 +++- .../admin/short-urls/short-urls.page.html | 6 ++ 25 files changed, 461 insertions(+), 29 deletions(-) create mode 100644 web/src/app/modules/admin/domains/history/history.component.html create mode 100644 web/src/app/modules/admin/domains/history/history.component.scss create mode 100644 web/src/app/modules/admin/domains/history/history.component.spec.ts create mode 100644 web/src/app/modules/admin/domains/history/history.component.ts create mode 100644 web/src/app/modules/admin/groups/history/history.component.html create mode 100644 web/src/app/modules/admin/groups/history/history.component.scss create mode 100644 web/src/app/modules/admin/groups/history/history.component.spec.ts create mode 100644 web/src/app/modules/admin/groups/history/history.component.ts create mode 100644 web/src/app/modules/admin/short-urls/history/history.component.html create mode 100644 web/src/app/modules/admin/short-urls/history/history.component.scss create mode 100644 web/src/app/modules/admin/short-urls/history/history.component.spec.ts create mode 100644 web/src/app/modules/admin/short-urls/history/history.component.ts diff --git a/api/src/core/database/abc/db_model_abc.py b/api/src/core/database/abc/db_model_abc.py index 66b1127..eddf74f 100644 --- a/api/src/core/database/abc/db_model_abc.py +++ b/api/src/core/database/abc/db_model_abc.py @@ -54,7 +54,7 @@ class DbModelABC(ABC): from data.schemas.administration.user_dao import userDao - return await userDao.get_by_id(self._editor_id) + return await userDao.find_single_by({"id": self._editor_id}) @property def created(self) -> datetime: diff --git a/web/src/app/model/entities/domain.ts b/web/src/app/model/entities/domain.ts index c81d199..90c3744 100644 --- a/web/src/app/model/entities/domain.ts +++ b/web/src/app/model/entities/domain.ts @@ -1,6 +1,6 @@ -import { DbModel } from 'src/app/model/entities/db-model'; +import { DbModelWithHistory } from 'src/app/model/entities/db-model'; -export interface Domain extends DbModel { +export interface Domain extends DbModelWithHistory { name: string; } diff --git a/web/src/app/model/entities/group.ts b/web/src/app/model/entities/group.ts index 94be2dc..e2cf4fe 100644 --- a/web/src/app/model/entities/group.ts +++ b/web/src/app/model/entities/group.ts @@ -1,7 +1,7 @@ -import { DbModel } from 'src/app/model/entities/db-model'; +import { DbModelWithHistory } from 'src/app/model/entities/db-model'; import { Role } from 'src/app/model/entities/role'; -export interface Group extends DbModel { +export interface Group extends DbModelWithHistory { name: string; roles: Role[]; } diff --git a/web/src/app/model/entities/short-url.ts b/web/src/app/model/entities/short-url.ts index 8ddaba4..2813501 100644 --- a/web/src/app/model/entities/short-url.ts +++ b/web/src/app/model/entities/short-url.ts @@ -1,8 +1,8 @@ -import { DbModel } from 'src/app/model/entities/db-model'; +import { DbModelWithHistory } from 'src/app/model/entities/db-model'; import { Group } from 'src/app/model/entities/group'; import { Domain } from 'src/app/model/entities/domain'; -export interface ShortUrl extends DbModel { +export interface ShortUrl extends DbModelWithHistory { shortUrl: string; targetUrl: string; description: string; diff --git a/web/src/app/modules/admin/domains/domains.data.service.ts b/web/src/app/modules/admin/domains/domains.data.service.ts index d3a6272..162f453 100644 --- a/web/src/app/modules/admin/domains/domains.data.service.ts +++ b/web/src/app/modules/admin/domains/domains.data.service.ts @@ -11,7 +11,10 @@ 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 { + DB_HISTORY_MODEL_FRAGMENT, + 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 { @@ -19,10 +22,11 @@ import { DomainCreateInput, DomainUpdateInput, } from 'src/app/model/entities/domain'; +import { PageWithHistoryDataService } from 'src/app/core/base/page-with-history.data.service'; @Injectable() export class DomainsDataService - extends PageDataService + extends PageWithHistoryDataService implements Create, Update, @@ -109,6 +113,40 @@ export class DomainsDataService .pipe(map(result => result.data.domains.nodes[0])); } + loadHistory(id: number) { + return this.apollo + .query<{ domains: QueryResult }>({ + query: gql` + query getDomainHistory($id: Int) { + domains(filter: { id: { equal: $id } }) { + count + totalCount + nodes { + history { + id + name + + ...DB_HISTORY_MODEL + } + } + } + } + + ${DB_HISTORY_MODEL_FRAGMENT} + `, + variables: { + id, + }, + }) + .pipe( + catchError(err => { + this.spinner.hide(); + throw err; + }) + ) + .pipe(map(result => result.data?.domains?.nodes?.[0]?.history ?? [])); + } + onChange(): Observable { return this.apollo .subscribe<{ domainChange: void }>({ @@ -238,6 +276,10 @@ export class DomainsDataService provide: PageDataService, useClass: DomainsDataService, }, + { + provide: PageWithHistoryDataService, + useClass: DomainsDataService, + }, DomainsDataService, ]; } diff --git a/web/src/app/modules/admin/domains/domains.module.ts b/web/src/app/modules/admin/domains/domains.module.ts index 62fe081..fe3365a 100644 --- a/web/src/app/modules/admin/domains/domains.module.ts +++ b/web/src/app/modules/admin/domains/domains.module.ts @@ -8,6 +8,7 @@ import { DomainsPage } from 'src/app/modules/admin/domains/domains.page'; import { DomainFormPageComponent } from 'src/app/modules/admin/domains/form-page/domain-form-page.component'; import { DomainsDataService } from 'src/app/modules/admin/domains/domains.data.service'; import { DomainsColumns } from 'src/app/modules/admin/domains/domains.columns'; +import { HistoryComponent } from 'src/app/modules/admin/domains/history/history.component'; const routes: Routes = [ { @@ -31,12 +32,20 @@ const routes: Routes = [ permissions: [PermissionsEnum.apiKeysUpdate], }, }, + { + path: 'history/:historyId', + component: HistoryComponent, + canActivate: [PermissionGuard], + data: { + permissions: [PermissionsEnum.domains], + }, + }, ], }, ]; @NgModule({ - declarations: [DomainsPage, DomainFormPageComponent], + declarations: [DomainsPage, DomainFormPageComponent, HistoryComponent], imports: [CommonModule, SharedModule, RouterModule.forChild(routes)], providers: [DomainsDataService.provide(), DomainsColumns.provide()], }) diff --git a/web/src/app/modules/admin/domains/domains.page.html b/web/src/app/modules/admin/domains/domains.page.html index dd8b0a9..d186529 100644 --- a/web/src/app/modules/admin/domains/domains.page.html +++ b/web/src/app/modules/admin/domains/domains.page.html @@ -11,6 +11,7 @@ [(skip)]="skip" [(take)]="take" (load)="load()" + [history]="true" [create]="true" [update]="true" (delete)="delete($event)" diff --git a/web/src/app/modules/admin/domains/history/history.component.html b/web/src/app/modules/admin/domains/history/history.component.html new file mode 100644 index 0000000..c929dc0 --- /dev/null +++ b/web/src/app/modules/admin/domains/history/history.component.html @@ -0,0 +1,3 @@ + diff --git a/web/src/app/modules/admin/domains/history/history.component.scss b/web/src/app/modules/admin/domains/history/history.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/web/src/app/modules/admin/domains/history/history.component.spec.ts b/web/src/app/modules/admin/domains/history/history.component.spec.ts new file mode 100644 index 0000000..c0679d0 --- /dev/null +++ b/web/src/app/modules/admin/domains/history/history.component.spec.ts @@ -0,0 +1,65 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HistoryComponent } from './history.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 { PageDataService } from 'src/app/core/base/page.data.service'; +import { IpListDataService } from 'src/app/modules/admin/tools/ip-list/ip-list.data.service'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { PageColumns } from 'src/app/core/base/page.columns'; +import { MockPageColumns } from 'src/app/modules/shared/test/page.columns.mock'; + +describe('HistoryComponent', () => { + let component: HistoryComponent; + let fixture: ComponentFixture>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [HistoryComponent], + imports: [ + BrowserAnimationsModule, + SharedModule, + TranslateModule.forRoot(), + ], + providers: [ + AuthService, + KeycloakService, + ErrorHandlingService, + ToastService, + MessageService, + ConfirmationService, + { + provide: ActivatedRoute, + useValue: { + snapshot: { params: { historyId: '3' } }, + }, + }, + { + provide: PageDataService, + useClass: IpListDataService, + }, + { + provide: PageColumns, + useClass: MockPageColumns, + }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(HistoryComponent); + component = fixture.componentInstance; + //eslint-disable-next-line @typescript-eslint/no-unused-vars + component.loadHistory = (id: number) => of([]); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/web/src/app/modules/admin/domains/history/history.component.ts b/web/src/app/modules/admin/domains/history/history.component.ts new file mode 100644 index 0000000..e9c25f6 --- /dev/null +++ b/web/src/app/modules/admin/domains/history/history.component.ts @@ -0,0 +1,18 @@ +import { Component } from '@angular/core'; +import { PageWithHistoryDataService } from 'src/app/core/base/page-with-history.data.service'; +import { PageColumns } from 'src/app/core/base/page.columns'; + +@Component({ + selector: 'app-history', + templateUrl: './history.component.html', + styleUrl: './history.component.scss', +}) +export class HistoryComponent { + loadHistory = (id: number) => this.data.loadHistory(id); + columns = this._columns.get(); + + constructor( + public data: PageWithHistoryDataService, + private _columns: PageColumns + ) {} +} diff --git a/web/src/app/modules/admin/groups/groups.data.service.ts b/web/src/app/modules/admin/groups/groups.data.service.ts index 93be7ec..2aabf70 100644 --- a/web/src/app/modules/admin/groups/groups.data.service.ts +++ b/web/src/app/modules/admin/groups/groups.data.service.ts @@ -11,7 +11,10 @@ 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 { + DB_HISTORY_MODEL_FRAGMENT, + 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 { @@ -19,10 +22,12 @@ import { GroupCreateInput, GroupUpdateInput, } from 'src/app/model/entities/group'; +import { PageWithHistoryDataService } from 'src/app/core/base/page-with-history.data.service'; +import { Domain } from 'src/app/model/entities/domain'; @Injectable() export class GroupsDataService - extends PageDataService + extends PageWithHistoryDataService implements Create, Update, @@ -117,6 +122,40 @@ export class GroupsDataService .pipe(map(result => result.data.groups.nodes[0])); } + loadHistory(id: number) { + return this.apollo + .query<{ groups: QueryResult }>({ + query: gql` + query getGroupHistory($id: Int) { + groups(filter: { id: { equal: $id } }) { + count + totalCount + nodes { + history { + id + name + + ...DB_HISTORY_MODEL + } + } + } + } + + ${DB_HISTORY_MODEL_FRAGMENT} + `, + variables: { + id, + }, + }) + .pipe( + catchError(err => { + this.spinner.hide(); + throw err; + }) + ) + .pipe(map(result => result.data?.groups?.nodes?.[0]?.history ?? [])); + } + onChange(): Observable { return this.apollo .subscribe<{ groupChange: void }>({ @@ -248,6 +287,10 @@ export class GroupsDataService provide: PageDataService, useClass: GroupsDataService, }, + { + provide: PageWithHistoryDataService, + useClass: GroupsDataService, + }, GroupsDataService, ]; } diff --git a/web/src/app/modules/admin/groups/groups.module.ts b/web/src/app/modules/admin/groups/groups.module.ts index 5fbdb22..813c76f 100644 --- a/web/src/app/modules/admin/groups/groups.module.ts +++ b/web/src/app/modules/admin/groups/groups.module.ts @@ -1,22 +1,23 @@ -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 { GroupsPage } from "src/app/modules/admin/groups/groups.page"; -import { GroupFormPageComponent } from "src/app/modules/admin/groups/form-page/group-form-page.component"; -import { GroupsDataService } from "src/app/modules/admin/groups/groups.data.service"; -import { GroupsColumns } from "src/app/modules/admin/groups/groups.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 { GroupsPage } from 'src/app/modules/admin/groups/groups.page'; +import { GroupFormPageComponent } from 'src/app/modules/admin/groups/form-page/group-form-page.component'; +import { GroupsDataService } from 'src/app/modules/admin/groups/groups.data.service'; +import { GroupsColumns } from 'src/app/modules/admin/groups/groups.columns'; +import { HistoryComponent } from 'src/app/modules/admin/groups/history/history.component'; const routes: Routes = [ { - path: "", - title: "Groups", + path: '', + title: 'Groups', component: GroupsPage, children: [ { - path: "create", + path: 'create', component: GroupFormPageComponent, canActivate: [PermissionGuard], data: { @@ -24,19 +25,27 @@ const routes: Routes = [ }, }, { - path: "edit/:id", + path: 'edit/:id', component: GroupFormPageComponent, canActivate: [PermissionGuard], data: { permissions: [PermissionsEnum.apiKeysUpdate], }, }, + { + path: 'history/:historyId', + component: HistoryComponent, + canActivate: [PermissionGuard], + data: { + permissions: [PermissionsEnum.domains], + }, + }, ], }, ]; @NgModule({ - declarations: [GroupsPage, GroupFormPageComponent], + declarations: [GroupsPage, GroupFormPageComponent, HistoryComponent], imports: [CommonModule, SharedModule, RouterModule.forChild(routes)], providers: [GroupsDataService.provide(), GroupsColumns.provide()], }) diff --git a/web/src/app/modules/admin/groups/groups.page.html b/web/src/app/modules/admin/groups/groups.page.html index d9a1c72..e25ea68 100644 --- a/web/src/app/modules/admin/groups/groups.page.html +++ b/web/src/app/modules/admin/groups/groups.page.html @@ -11,6 +11,7 @@ [(skip)]="skip" [(take)]="take" (load)="load()" + [history]="true" [create]="true" [update]="true" (delete)="delete($event)" diff --git a/web/src/app/modules/admin/groups/history/history.component.html b/web/src/app/modules/admin/groups/history/history.component.html new file mode 100644 index 0000000..c929dc0 --- /dev/null +++ b/web/src/app/modules/admin/groups/history/history.component.html @@ -0,0 +1,3 @@ + diff --git a/web/src/app/modules/admin/groups/history/history.component.scss b/web/src/app/modules/admin/groups/history/history.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/web/src/app/modules/admin/groups/history/history.component.spec.ts b/web/src/app/modules/admin/groups/history/history.component.spec.ts new file mode 100644 index 0000000..c0679d0 --- /dev/null +++ b/web/src/app/modules/admin/groups/history/history.component.spec.ts @@ -0,0 +1,65 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HistoryComponent } from './history.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 { PageDataService } from 'src/app/core/base/page.data.service'; +import { IpListDataService } from 'src/app/modules/admin/tools/ip-list/ip-list.data.service'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { PageColumns } from 'src/app/core/base/page.columns'; +import { MockPageColumns } from 'src/app/modules/shared/test/page.columns.mock'; + +describe('HistoryComponent', () => { + let component: HistoryComponent; + let fixture: ComponentFixture>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [HistoryComponent], + imports: [ + BrowserAnimationsModule, + SharedModule, + TranslateModule.forRoot(), + ], + providers: [ + AuthService, + KeycloakService, + ErrorHandlingService, + ToastService, + MessageService, + ConfirmationService, + { + provide: ActivatedRoute, + useValue: { + snapshot: { params: { historyId: '3' } }, + }, + }, + { + provide: PageDataService, + useClass: IpListDataService, + }, + { + provide: PageColumns, + useClass: MockPageColumns, + }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(HistoryComponent); + component = fixture.componentInstance; + //eslint-disable-next-line @typescript-eslint/no-unused-vars + component.loadHistory = (id: number) => of([]); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/web/src/app/modules/admin/groups/history/history.component.ts b/web/src/app/modules/admin/groups/history/history.component.ts new file mode 100644 index 0000000..e9c25f6 --- /dev/null +++ b/web/src/app/modules/admin/groups/history/history.component.ts @@ -0,0 +1,18 @@ +import { Component } from '@angular/core'; +import { PageWithHistoryDataService } from 'src/app/core/base/page-with-history.data.service'; +import { PageColumns } from 'src/app/core/base/page.columns'; + +@Component({ + selector: 'app-history', + templateUrl: './history.component.html', + styleUrl: './history.component.scss', +}) +export class HistoryComponent { + loadHistory = (id: number) => this.data.loadHistory(id); + columns = this._columns.get(); + + constructor( + public data: PageWithHistoryDataService, + private _columns: PageColumns + ) {} +} diff --git a/web/src/app/modules/admin/short-urls/history/history.component.html b/web/src/app/modules/admin/short-urls/history/history.component.html new file mode 100644 index 0000000..c929dc0 --- /dev/null +++ b/web/src/app/modules/admin/short-urls/history/history.component.html @@ -0,0 +1,3 @@ + diff --git a/web/src/app/modules/admin/short-urls/history/history.component.scss b/web/src/app/modules/admin/short-urls/history/history.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/web/src/app/modules/admin/short-urls/history/history.component.spec.ts b/web/src/app/modules/admin/short-urls/history/history.component.spec.ts new file mode 100644 index 0000000..c0679d0 --- /dev/null +++ b/web/src/app/modules/admin/short-urls/history/history.component.spec.ts @@ -0,0 +1,65 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HistoryComponent } from './history.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 { PageDataService } from 'src/app/core/base/page.data.service'; +import { IpListDataService } from 'src/app/modules/admin/tools/ip-list/ip-list.data.service'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { PageColumns } from 'src/app/core/base/page.columns'; +import { MockPageColumns } from 'src/app/modules/shared/test/page.columns.mock'; + +describe('HistoryComponent', () => { + let component: HistoryComponent; + let fixture: ComponentFixture>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [HistoryComponent], + imports: [ + BrowserAnimationsModule, + SharedModule, + TranslateModule.forRoot(), + ], + providers: [ + AuthService, + KeycloakService, + ErrorHandlingService, + ToastService, + MessageService, + ConfirmationService, + { + provide: ActivatedRoute, + useValue: { + snapshot: { params: { historyId: '3' } }, + }, + }, + { + provide: PageDataService, + useClass: IpListDataService, + }, + { + provide: PageColumns, + useClass: MockPageColumns, + }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(HistoryComponent); + component = fixture.componentInstance; + //eslint-disable-next-line @typescript-eslint/no-unused-vars + component.loadHistory = (id: number) => of([]); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/web/src/app/modules/admin/short-urls/history/history.component.ts b/web/src/app/modules/admin/short-urls/history/history.component.ts new file mode 100644 index 0000000..e9c25f6 --- /dev/null +++ b/web/src/app/modules/admin/short-urls/history/history.component.ts @@ -0,0 +1,18 @@ +import { Component } from '@angular/core'; +import { PageWithHistoryDataService } from 'src/app/core/base/page-with-history.data.service'; +import { PageColumns } from 'src/app/core/base/page.columns'; + +@Component({ + selector: 'app-history', + templateUrl: './history.component.html', + styleUrl: './history.component.scss', +}) +export class HistoryComponent { + loadHistory = (id: number) => this.data.loadHistory(id); + columns = this._columns.get(); + + constructor( + public data: PageWithHistoryDataService, + private _columns: PageColumns + ) {} +} diff --git a/web/src/app/modules/admin/short-urls/short-urls.data.service.ts b/web/src/app/modules/admin/short-urls/short-urls.data.service.ts index a43033d..da1dc5c 100644 --- a/web/src/app/modules/admin/short-urls/short-urls.data.service.ts +++ b/web/src/app/modules/admin/short-urls/short-urls.data.service.ts @@ -11,7 +11,10 @@ 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 { + DB_HISTORY_MODEL_FRAGMENT, + 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 { @@ -21,6 +24,7 @@ import { } from 'src/app/model/entities/short-url'; import { Group } from 'src/app/model/entities/group'; import { Domain } from 'src/app/model/entities/domain'; +import { PageWithHistoryDataService } from 'src/app/core/base/page-with-history.data.service'; @Injectable() export class ShortUrlsDataService @@ -132,6 +136,52 @@ export class ShortUrlsDataService .pipe(map(result => result.data.shortUrls.nodes[0])); } + loadHistory(id: number) { + return this.apollo + .query<{ shortUrls: QueryResult }>({ + query: gql` + query getDomainHistory($id: Int) { + shortUrls(filter: { id: { equal: $id } }) { + count + totalCount + nodes { + history { + id + shortUrl + targetUrl + description + loadingScreen + visits + group { + id + name + } + domain { + id + name + } + + ...DB_HISTORY_MODEL + } + } + } + } + + ${DB_HISTORY_MODEL_FRAGMENT} + `, + variables: { + id, + }, + }) + .pipe( + catchError(err => { + this.spinner.hide(); + throw err; + }) + ) + .pipe(map(result => result.data?.shortUrls?.nodes?.[0]?.history ?? [])); + } + onChange(): Observable { return merge( this.apollo @@ -329,6 +379,10 @@ export class ShortUrlsDataService provide: PageDataService, useClass: ShortUrlsDataService, }, + { + provide: PageWithHistoryDataService, + useClass: ShortUrlsDataService, + }, ShortUrlsDataService, ]; } diff --git a/web/src/app/modules/admin/short-urls/short-urls.module.ts b/web/src/app/modules/admin/short-urls/short-urls.module.ts index 6e5b0e2..4af7061 100644 --- a/web/src/app/modules/admin/short-urls/short-urls.module.ts +++ b/web/src/app/modules/admin/short-urls/short-urls.module.ts @@ -8,6 +8,7 @@ import { ShortUrlsPage } from 'src/app/modules/admin/short-urls/short-urls.page' import { ShortUrlFormPageComponent } from 'src/app/modules/admin/short-urls/form-page/short-url-form-page.component'; 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 { HistoryComponent } from 'src/app/modules/admin/short-urls/history/history.component'; const routes: Routes = [ { @@ -31,12 +32,20 @@ const routes: Routes = [ permissions: [PermissionsEnum.shortUrlsUpdate], }, }, + { + path: 'history/:historyId', + component: HistoryComponent, + canActivate: [PermissionGuard], + data: { + permissions: [PermissionsEnum.domains], + }, + }, ], }, ]; @NgModule({ - declarations: [ShortUrlsPage, ShortUrlFormPageComponent], + declarations: [ShortUrlsPage, ShortUrlFormPageComponent, HistoryComponent], imports: [CommonModule, SharedModule, RouterModule.forChild(routes)], providers: [ShortUrlsDataService.provide(), ShortUrlsColumns.provide()], }) diff --git a/web/src/app/modules/admin/short-urls/short-urls.page.html b/web/src/app/modules/admin/short-urls/short-urls.page.html index 1a54a6c..5624bb5 100644 --- a/web/src/app/modules/admin/short-urls/short-urls.page.html +++ b/web/src/app/modules/admin/short-urls/short-urls.page.html @@ -67,6 +67,12 @@ tooltipPosition="left" pTooltip="{{ 'table.restore' | translate }}" (click)="restore(url)"> +