From ddb3706e44ce9631ae96f0dde85591e16946c12c Mon Sep 17 00:00:00 2001 From: ewandor Date: Wed, 18 Jan 2023 19:43:13 +0100 Subject: [PATCH] Fully generic CRUD pages --- .../views/entities/entities-routing.module.ts | 2 +- .../app/views/entities/entities.component.ts | 21 ++++----- .../src/app/views/entities/entities.module.ts | 3 +- .../src/common/crud/card/card.component.ts | 14 +++--- front/app/src/common/crud/crud.module.ts | 4 +- front/app/src/common/crud/crud.service.ts | 38 ++++++++------- .../src/common/crud/jsonschemas.service.ts | 6 +-- .../src/common/crud/list/list.component.html | 12 ++--- .../src/common/crud/list/list.component.ts | 46 ++++++++++++++----- 9 files changed, 84 insertions(+), 62 deletions(-) diff --git a/front/app/src/app/views/entities/entities-routing.module.ts b/front/app/src/app/views/entities/entities-routing.module.ts index 27123dbd..87e49d2c 100644 --- a/front/app/src/app/views/entities/entities-routing.module.ts +++ b/front/app/src/app/views/entities/entities-routing.module.ts @@ -1,7 +1,7 @@ import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; -import {EntitiesComponent, EntityCardComponent, EntityListComponent, EntityNewComponent} from "./entities.component"; +import { EntityCardComponent, EntityListComponent, EntityNewComponent } from "./entities.component"; import {ListComponent} from "../../../common/crud/list/list.component"; import {CardComponent} from "../../../common/crud/card/card.component"; import {ColorsComponent} from "../theme/colors.component"; diff --git a/front/app/src/app/views/entities/entities.component.ts b/front/app/src/app/views/entities/entities.component.ts index 3e8a61d9..61d50548 100644 --- a/front/app/src/app/views/entities/entities.component.ts +++ b/front/app/src/app/views/entities/entities.component.ts @@ -6,35 +6,32 @@ import { DOCUMENT } from '@angular/common'; import { getStyle, rgbToHex } from '@coreui/utils/src'; -@Component({ - template: '' -}) -export class EntitiesComponent { - constructor() { - } +export class BaseEntitiesComponent { + protected resource: string = "Entity"; } @Component({ - template: '' + template: '' }) -export class EntityListComponent { +export class EntityListComponent extends BaseEntitiesComponent{ } @Component({ - template: '' + template: '' }) -export class EntityNewComponent { +export class EntityNewComponent extends BaseEntitiesComponent { } @Component({ - template: '' + template: '' }) -export class EntityCardComponent implements OnInit { +export class EntityCardComponent extends BaseEntitiesComponent implements OnInit { resource_id: string | null = null; constructor(private route: ActivatedRoute,) { + super(); } ngOnInit(): void { diff --git a/front/app/src/app/views/entities/entities.module.ts b/front/app/src/app/views/entities/entities.module.ts index 94b00955..f7bd2f71 100644 --- a/front/app/src/app/views/entities/entities.module.ts +++ b/front/app/src/app/views/entities/entities.module.ts @@ -3,7 +3,7 @@ import { NgModule } from '@angular/core'; import { EntitiesRoutingModule } from './entities-routing.module'; import { CrudModule } from '@common/crud/crud.module' -import {EntitiesComponent, EntityCardComponent, EntityListComponent, EntityNewComponent} from "./entities.component"; +import { EntityCardComponent, EntityListComponent, EntityNewComponent} from "./entities.component"; @@ -14,7 +14,6 @@ import {EntitiesComponent, EntityCardComponent, EntityListComponent, EntityNewCo EntitiesRoutingModule ], declarations: [ - EntitiesComponent, EntityListComponent, EntityNewComponent, EntityCardComponent, diff --git a/front/app/src/common/crud/card/card.component.ts b/front/app/src/common/crud/card/card.component.ts index 3e63483d..75b36906 100644 --- a/front/app/src/common/crud/card/card.component.ts +++ b/front/app/src/common/crud/card/card.component.ts @@ -18,11 +18,11 @@ export interface Model { styleUrls: ['./card.component.css'] }) export class CardComponent implements OnInit { + @Input() resource: string | undefined; @Input() resource_id: string | null = null; form = new FormGroup({}); model = {}; fields: FormlyFieldConfig[] = []; - resource: string = "Entity"; schemas = JSON.parse(`{}`); @@ -41,14 +41,14 @@ export class CardComponent implements OnInit { ngOnInit(): void { this._loading$.next(true); if (this.isCreateForm()) { - this.jsonSchemasService.getCreateResource(this.resource).subscribe((schemas: any) => { + this.jsonSchemasService.getCreateResource(this.resource!).subscribe((schemas: any) => { this.fields = [this.formlyJsonschema.toFieldConfig(schemas)]; }) } else { - this.jsonSchemasService.getUpdateResource(this.resource).subscribe((schemas: any) => { + this.jsonSchemasService.getUpdateResource(this.resource!).subscribe((schemas: any) => { this.fields = [this.formlyJsonschema.toFieldConfig(schemas)]; }) - this.crudService.get(this.resource_id!).subscribe((model: any) => { + this.crudService.get(this.resource!, this.resource_id!).subscribe((model: any) => { this.model = model this._loading$.next(false); }); @@ -58,12 +58,12 @@ export class CardComponent implements OnInit { onSubmit(model: any) { this._loading$.next(true); if (this.isCreateForm()) { - this.crudService.create(model).subscribe((response: any) => { + this.crudService.create(this.resource!, model).subscribe((response: any) => { this._loading$.next(false); - this.router.navigateByUrl('/entities/' + response.id); + this.router.navigateByUrl(response.id); }); } else { - this.crudService.update(model).subscribe((model: any) => { + this.crudService.update(this.resource!, model).subscribe((model: any) => { this.model = model; this._loading$.next(false); }); diff --git a/front/app/src/common/crud/crud.module.ts b/front/app/src/common/crud/crud.module.ts index 3e915dc7..91b61043 100644 --- a/front/app/src/common/crud/crud.module.ts +++ b/front/app/src/common/crud/crud.module.ts @@ -12,7 +12,7 @@ import { FormlyBootstrapModule } from '@ngx-formly/bootstrap'; import { CardComponent } from './card/card.component'; import { ListComponent } from './list/list.component'; import { ObjectTypeComponent } from "./object.type"; -import { CrudService } from "./crud.service"; +import {ApiService, CrudService} from "./crud.service"; import {NgbModule} from "@ng-bootstrap/ng-bootstrap"; import {JsonschemasService} from "./jsonschemas.service"; @@ -23,7 +23,7 @@ import {JsonschemasService} from "./jsonschemas.service"; ListComponent, ObjectTypeComponent ], - providers: [ CrudService, JsonschemasService ], + providers: [ JsonschemasService, ApiService, CrudService ], imports: [ CommonModule, HttpClientModule, diff --git a/front/app/src/common/crud/crud.service.ts b/front/app/src/common/crud/crud.service.ts index a970cfbf..75fab457 100644 --- a/front/app/src/common/crud/crud.service.ts +++ b/front/app/src/common/crud/crud.service.ts @@ -1,41 +1,47 @@ import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; +import { Injectable, Inject } from '@angular/core'; import { Schema } from "./jsonschemas.service"; @Injectable() -export class CrudService { +export class ApiService { + constructor(protected http: HttpClient) {} - constructor(private http: HttpClient) {} + protected api_root: string = '/api/v1' + + public getSchema() { + return this.http.get(`${this.api_root}/openapi.json`); + } +} + + +@Injectable() +export class CrudService extends ApiService { public loading: boolean = false; - public getSchema() { - return this.http.get(`/api/v1/openapi.json`); - } - - public getList(page: number, size: number, sortColumn: string, sortDirection: string) { - return this.http.get<{ menu: [{}] }>( - `/api/v1/entity/?size=${size}&page=${page + 1}&sort_by=${sortDirection}(${sortColumn})` + public getList(resource: string, page: number, size: number, sortColumn: string, sortDirection: string) { + return this.http.get<{ items: [{}] }>( + `${this.api_root}/${resource.toLowerCase()}/?size=${size}&page=${page + 1}&sort_by=${sortDirection}(${sortColumn})` ); } - public get(id: string) { + public get(resource: string, id: string) { return this.http.get<{}>( - `/api/v1/entity/${id}` + `${this.api_root}/${resource.toLowerCase()}/${id}` ); } - public update(model: any) { + public update(resource: string, model: any) { return this.http.put<{ menu: [{}] }>( - `/api/v1/entity/${model._id}`, + `${this.api_root}/${resource.toLowerCase()}/${model._id}`, model ); } - public create(model: any) { + public create(resource: string, model: any) { return this.http.post<{ menu: [{}] }>( - `/api/v1/entity/`, + `${this.api_root}/${resource.toLowerCase()}/`, model ); } diff --git a/front/app/src/common/crud/jsonschemas.service.ts b/front/app/src/common/crud/jsonschemas.service.ts index c8c4093a..e9ae9c3c 100644 --- a/front/app/src/common/crud/jsonschemas.service.ts +++ b/front/app/src/common/crud/jsonschemas.service.ts @@ -1,4 +1,4 @@ -import {CrudService} from "./crud.service"; +import {ApiService} from "./crud.service"; import {Observable} from "rxjs"; import {Injectable} from "@angular/core"; @@ -9,12 +9,12 @@ import {Injectable} from "@angular/core"; export class JsonschemasService { private rawSchemas: any | null = null; - constructor(private crudService: CrudService) {} + constructor(private apiService: ApiService) {} getSchemas(): Observable { return new Observable((observer) => { if (this.rawSchemas === null) { - this.crudService.getSchema().subscribe((jsonSchemas: any) => { + this.apiService.getSchema().subscribe((jsonSchemas: any) => { this.rawSchemas = jsonSchemas; observer.next(this.rawSchemas) }); diff --git a/front/app/src/common/crud/list/list.component.html b/front/app/src/common/crud/list/list.component.html index b0475b9c..51a9ad8a 100644 --- a/front/app/src/common/crud/list/list.component.html +++ b/front/app/src/common/crud/list/list.component.html @@ -16,18 +16,14 @@ - - - - + - - - - +
#NameTypeAddress{{ col }}
{{ row.id }} + +
diff --git a/front/app/src/common/crud/list/list.component.ts b/front/app/src/common/crud/list/list.component.ts index d601962f..fbfdb1eb 100644 --- a/front/app/src/common/crud/list/list.component.ts +++ b/front/app/src/common/crud/list/list.component.ts @@ -1,9 +1,9 @@ -import { Component, ViewChildren, QueryList } from '@angular/core'; +import { Component, ViewChildren, QueryList, Input, OnInit } from '@angular/core'; import { BehaviorSubject } from "rxjs"; -import { Location } from '@angular/common'; -import { Router } from '@angular/router'; -import { CrudService} from "../crud.service"; +import { ActivatedRoute, Router } from '@angular/router'; +import { CrudService } from "../crud.service"; import { NgbdSortableHeader, SortColumn, SortDirection } from './sortable.directive'; +import { JsonschemasService } from "../jsonschemas.service"; interface SearchResult { @@ -22,18 +22,42 @@ interface State { @Component({ selector: 'crud-list', templateUrl: './list.component.html', - styleUrls: ['./list.component.css'] + styleUrls: ['./list.component.css'], }) -export class ListComponent { - displayedColumns: string[] = ['type', 'name', 'address', '_id',]; +export class ListComponent implements OnInit { + @Input() resource: string = ""; + @Input() columns: string[] = []; + + public displayedColumns: string[] = []; loading: boolean = false; @ViewChildren(NgbdSortableHeader) headers: QueryList = new QueryList(); - constructor(private location: Location, public service: CrudService, private router: Router) { + constructor(private service: CrudService, + private jsonSchemasService: JsonschemasService, + private router: Router, + private route: ActivatedRoute, + ) { } + + ngOnInit(): void { + this.jsonSchemasService.getUpdateResource(this.resource!).subscribe((schemas: any) => { + if (this.columns.length == 0) { + for (let param_name in schemas.properties) { + if (param_name != "_id") { + this.displayedColumns.push(param_name); + } + } + } else { + for (let column in this.columns) { + if (column in schemas.properties) { + this.displayedColumns.push(column); + } + } + } + }) this._search(); - } + } private _loading$ = new BehaviorSubject(true); //private _search$ = new Subject(); @@ -50,7 +74,7 @@ export class ListComponent { private _search() { this._loading$.next(true); - this.service.getList(this.page - 1, this.pageSize, this.sortColumn, this.sortDirection).subscribe((data: any) => { + this.service.getList(this.resource, this.page - 1, this.pageSize, this.sortColumn, this.sortDirection).subscribe((data: any) => { this._listData$.next(data.items); this._total$.next(data.total); this._state.pageSize = data.size; @@ -72,7 +96,7 @@ export class ListComponent { } onSelect(id: string) { - this.router.navigateByUrl('/entities/' + id); + this.router.navigate([id], {relativeTo: this.route}); } get listData$() {