Adjustements everywhere

This commit is contained in:
2023-01-26 14:58:16 +01:00
parent ac744604ed
commit 012c80d29e
13 changed files with 125 additions and 59 deletions

View File

@@ -15,10 +15,10 @@ class EntityType(BaseModel):
class Individual(EntityType): class Individual(EntityType):
type: Literal['individual'] = 'individual' type: Literal['individual'] = 'individual'
firstname: Indexed(str, index_type=TEXT) firstname: Indexed(str)
middlenames: List[Indexed(str)] = Field(default=[]) middlename: Indexed(str) = ""
lastname: Indexed(str) lastname: Indexed(str)
surnames: List[Indexed(str)] = Field(default=[]) surnames: List[Indexed(str)] = []
day_of_birth: date day_of_birth: date
@@ -29,15 +29,8 @@ class Individual(EntityType):
return '{} {}'.format(self.firstname, self.lastname) return '{} {}'.format(self.firstname, self.lastname)
@staticmethod
def get_label(data) -> str:
if len(data['surname']) > 0:
return '{} "{}" {}'.format(data['firstname'], data['surnames'][0], data['lastname'])
return '{} {}'.format(data['firstname'], data['lastname']) class Employee(BaseModel):
class Employee(EntityType):
role: Indexed(str) role: Indexed(str)
entity_id: str = Field(foreignKey={ entity_id: str = Field(foreignKey={
"reference": { "reference": {
@@ -55,7 +48,7 @@ class Corporation(EntityType):
employees: List[Employee] = Field(default=[]) employees: List[Employee] = Field(default=[])
class Institution(BaseModel): class Institution(EntityType):
type: Literal['institution'] = 'institution' type: Literal['institution'] = 'institution'
title: Indexed(str) title: Indexed(str)
activity: Indexed(str) activity: Indexed(str)
@@ -70,6 +63,8 @@ class Entity(Document):
@validator("label", always=True) @validator("label", always=True)
def generate_label(cls, v, values, **kwargs): def generate_label(cls, v, values, **kwargs):
if 'entity_data' not in values:
return v
return values['entity_data'].label return values['entity_data'].label
created_at: datetime = Field(default=datetime.utcnow(), nullable=False) created_at: datetime = Field(default=datetime.utcnow(), nullable=False)

View File

@@ -1,7 +1,7 @@
from typing import Optional from typing import Optional
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from .models import Entity, EntityType, Individual, Corporation from .models import Entity, Institution, Individual, Corporation
from ..core.schemas import Writer from ..core.schemas import Writer
@@ -10,10 +10,10 @@ class EntityRead(Entity):
class EntityCreate(Writer): class EntityCreate(Writer):
entity_data: Individual | Corporation = Field(..., discriminator='type') entity_data: Individual | Corporation | Institution = Field(..., discriminator='type')
address: Optional[str] = "" address: Optional[str] = ""
class EntityUpdate(BaseModel): class EntityUpdate(BaseModel):
entity_data: Individual | Corporation = Field(..., discriminator='type') entity_data: Individual | Corporation | Institution = Field(..., discriminator='type')
address: Optional[str] = "" address: Optional[str] = ""

View File

@@ -19,7 +19,7 @@ async def handle_migration(args):
content = json.load(f) content = json.load(f)
for r in content: for r in content:
obj = m(**r) obj = m(**r)
obj.save() await obj.save()
elif args.action == "export-fixtures": elif args.action == "export-fixtures":
for m in models: for m in models:

View File

@@ -2,10 +2,10 @@
<form cForm [formGroup]="form" (ngSubmit)="onSubmit(model)"> <form cForm [formGroup]="form" (ngSubmit)="onSubmit(model)">
<span class="col col-form-label" *ngIf="loading$ | async">Loading...</span> <span class="col col-form-label" *ngIf="loading$ | async">Loading...</span>
<formly-form [form]="form" [fields]="fields" [model]="model"></formly-form> <formly-form [form]="form" [fields]="fields" [model]="model"></formly-form>
<button cButton color="primary"> <button class="btn btn-success btn-lg" type="submit" [disabled]="!form.valid">
{{ this.isCreateForm() ? "Create" : "Update" }} {{ this.isCreateForm() ? "Create" : "Update" }}
</button> </button>
<button cButton *ngIf="!this.isCreateForm()" (click)="onDelete()" color="danger"> <button class="btn btn-danger btn-lg float-end" type="button" *ngIf="!this.isCreateForm()" (click)="onDelete()">
Delete Delete
</button> </button>
</form> </form>

View File

@@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core'; import { Component, Input, OnInit, Output, EventEmitter } from '@angular/core';
import { FormGroup } from '@angular/forms'; import { FormGroup } from '@angular/forms';
import { FormlyFieldConfig } from '@ngx-formly/core' import { FormlyFieldConfig } from '@ngx-formly/core'
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
@@ -19,6 +19,12 @@ export interface Model {
export class CardComponent implements OnInit { export class CardComponent implements OnInit {
@Input() resource: string | undefined; @Input() resource: string | undefined;
@Input() resource_id: string | null = null; @Input() resource_id: string | null = null;
@Input() is_modal: Boolean = false;
@Output() resourceCreated: EventEmitter<string> = new EventEmitter();
@Output() resourceDeleted: EventEmitter<string> = new EventEmitter();
form = new FormGroup({}); form = new FormGroup({});
model = {}; model = {};
fields: FormlyFieldConfig[] = []; fields: FormlyFieldConfig[] = [];
@@ -60,7 +66,11 @@ export class CardComponent implements OnInit {
if (this.isCreateForm()) { if (this.isCreateForm()) {
this.crudService.create(this.resource!, model).subscribe((response: any) => { this.crudService.create(this.resource!, model).subscribe((response: any) => {
this._loading$.next(false); this._loading$.next(false);
this.router.navigate([`../${response.id}`], {relativeTo: this.route}); if (! this.is_modal) {
this.router.navigate([`../${response.id}`], {relativeTo: this.route});
} else {
this.resourceCreated.emit(response.id)
}
}); });
} else { } else {
this.crudService.update(this.resource!, model).subscribe((model: any) => { this.crudService.update(this.resource!, model).subscribe((model: any) => {
@@ -74,7 +84,11 @@ export class CardComponent implements OnInit {
this._loading$.next(true); this._loading$.next(true);
this.crudService.delete(this.resource!, this.model).subscribe((model: any) => { this.crudService.delete(this.resource!, this.model).subscribe((model: any) => {
this._loading$.next(false); this._loading$.next(false);
this.router.navigate(['../'], {relativeTo: this.route}); if (! this.is_modal) {
this.router.navigate(['../'], {relativeTo: this.route});
} else {
this.resourceDeleted.emit("")
}
}); });
} }

View File

@@ -20,12 +20,14 @@ export class CrudFormlyJsonschemaService extends FormlyJsonschema {
} }
getCreateFields(resourceName: string): Observable<FormlyFieldConfig> { getCreateFields(resourceName: string): Observable<FormlyFieldConfig> {
resourceName = resourceName.charAt(0).toUpperCase() + resourceName.slice(1);
return this.jsonSchemasService.getCreateResource(resourceName).pipe( return this.jsonSchemasService.getCreateResource(resourceName).pipe(
map((schemas: any) => this.toFieldConfig(schemas)), map((schemas: any) => this.toFieldConfig(schemas)),
) )
} }
getUpdateFields(resourceName: string): Observable<FormlyFieldConfig> { getUpdateFields(resourceName: string): Observable<FormlyFieldConfig> {
resourceName = resourceName.charAt(0).toUpperCase() + resourceName.slice(1);
return this.jsonSchemasService.getUpdateResource(resourceName).pipe( return this.jsonSchemasService.getUpdateResource(resourceName).pipe(
map((schemas: any) => this.toFieldConfig(schemas)), map((schemas: any) => this.toFieldConfig(schemas)),
) )
@@ -35,8 +37,16 @@ export class CrudFormlyJsonschemaService extends FormlyJsonschema {
export class CrudFormlyJsonschemaOptions implements FormlyJsonschemaOptions { export class CrudFormlyJsonschemaOptions implements FormlyJsonschemaOptions {
map = (field: any, schema: any) => { map = (field: any, schema: any) => {
if (schema.hasOwnProperty('foreignKey')) { if (schema.hasOwnProperty('foreignKey')) {
field.type = "foreign-key";
field.foreignKey = schema['foreignKey']; field.foreignKey = schema['foreignKey'];
} else if (schema.format === 'date-time') {
field.type = "datetime";
} else if (schema.format === 'date') {
field.type = "date";
} else if (schema.hasOwnProperty('enum') && schema.enum.length == 1 && schema.enum[0] == schema.default ) {
field.type = "hidden";
} }
return field; return field;
} }
} }

View File

@@ -19,6 +19,7 @@ import { NgbModule} from "@ng-bootstrap/ng-bootstrap";
import { JsonschemasService } from "./jsonschemas.service"; import { JsonschemasService } from "./jsonschemas.service";
import { MultiSchemaTypeComponent } from "./types/multischema.type"; import { MultiSchemaTypeComponent } from "./types/multischema.type";
import { ForeignkeyTypeComponent } from "./types/foreignkey.type"; import { ForeignkeyTypeComponent } from "./types/foreignkey.type";
import {HiddenTypeComponent} from "./types/hidden.type";
@NgModule({ @NgModule({
@@ -31,6 +32,7 @@ import { ForeignkeyTypeComponent } from "./types/foreignkey.type";
ArrayTypeComponent, ArrayTypeComponent,
MultiSchemaTypeComponent, MultiSchemaTypeComponent,
ForeignkeyTypeComponent, ForeignkeyTypeComponent,
HiddenTypeComponent,
], ],
providers: [ JsonschemasService, ApiService, CrudService, CrudFormlyJsonschemaService ], providers: [ JsonschemasService, ApiService, CrudService, CrudFormlyJsonschemaService ],
imports: [ imports: [
@@ -48,6 +50,7 @@ import { ForeignkeyTypeComponent } from "./types/foreignkey.type";
{ name: 'array', component: ArrayTypeComponent }, { name: 'array', component: ArrayTypeComponent },
{ name: 'multischema', component: MultiSchemaTypeComponent }, { name: 'multischema', component: MultiSchemaTypeComponent },
{ name: 'foreign-key', component: ForeignkeyTypeComponent }, { name: 'foreign-key', component: ForeignkeyTypeComponent },
{ name: 'hidden', component: HiddenTypeComponent },
] ]
}), }),
FormlyBootstrapModule FormlyBootstrapModule

View File

@@ -44,12 +44,6 @@ export class JsonschemasService {
} }
} else if (prop.hasOwnProperty('items') && this.is_reference(prop.items)) { } else if (prop.hasOwnProperty('items') && this.is_reference(prop.items)) {
this.resolveReference(resource, prop.items); this.resolveReference(resource, prop.items);
} else if (prop.format === 'date-time') {
prop.type = "datetime";
} else if (prop.format === 'date') {
prop.type = "date";
} else if (prop.hasOwnProperty('foreignKey')) {
prop.type = "foreign-key";
} }
} }

View File

@@ -14,11 +14,14 @@ import { FieldArrayType } from '@ngx-formly/core';
<div class="alert alert-danger" role="alert" *ngIf="showError && formControl.errors"> <div class="alert alert-danger" role="alert" *ngIf="showError && formControl.errors">
<formly-validation-message [field]="field"></formly-validation-message> <formly-validation-message [field]="field"></formly-validation-message>
</div> </div>
<div class="row">
<div *ngFor="let field of field.fieldGroup; let i = index" class="row align-items-start"> <div *ngFor="let field of field.fieldGroup; let i = index" class="card col-sm-6">
<formly-field class="col" [field]="field"></formly-field> <div class="card-body">
<div *ngIf="field.props!['removable'] !== false" class="col-2 text-right"> <formly-field class="col" [field]="field"></formly-field>
<button class="btn btn-danger" type="button" (click)="remove(i)">-</button> <div *ngIf="field.props!['removable'] !== false" class="col-2 text-right">
<button class="btn btn-danger" type="button" (click)="remove(i)">-</button>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,8 +1,10 @@
import {AfterContentInit, Component, OnInit} from '@angular/core'; import {AfterContentInit, Component, OnInit} from '@angular/core';
import {Observable, OperatorFunction, switchMapTo, of, from, exhaustAll, mergeAll, concatAll} from 'rxjs'; import {Observable, OperatorFunction, switchMapTo, of, from, exhaustAll, mergeAll, concatAll} from 'rxjs';
import { catchError } from 'rxjs/operators'; import { catchError } from 'rxjs/operators';
import { debounceTime, distinctUntilChanged, map, tap, merge } from 'rxjs/operators'; import { debounceTime, distinctUntilChanged, map, tap, merge } from 'rxjs/operators';
import { FieldType, FieldTypeConfig} from '@ngx-formly/core'; import { FieldType, FieldTypeConfig} from '@ngx-formly/core';
import { ModalDismissReasons, NgbModal } from '@ng-bootstrap/ng-bootstrap';
import {CrudService, Filters, SortBy} from "../crud.service"; import {CrudService, Filters, SortBy} from "../crud.service";
import {formatDate} from "@angular/common"; import {formatDate} from "@angular/common";
@@ -29,35 +31,47 @@ import {formatDate} from "@angular/common";
[resultFormatter]="formatter" [resultFormatter]="formatter"
[editable]="false" /> [editable]="false" />
<div class="input-group-append"> <div class="input-group-append">
<button class="btn btn-outline-secondary cil-plus" type="button">Add</button> <button class="btn btn-success" type="button" (click)="add(foreignModal)"><span class="cil-plus btn-icon mr-2"></span> Add</button>
</div> </div>
</div> </div>
<div class="input-group" *ngIf="this.hasValue()"> <div class="input-group" *ngIf="this.hasValue()">
<input type="text" <input type="text"
class="form-control" class="form-control"
value="{{this.foreignModel.label}}" value="{{this.foreignLabel}}"
disabled="" disabled=""
readonly="readonly" readonly="readonly"
/> />
<div class="input-group-append"> <div class="input-group-append">
<button class="btn btn-outline-secondary cil-plus" type="button">See</button> <button class="btn btn-info" type="button" (click)="see(foreignModal)"><span class="cil-zoom btn-icon"></span>See</button>
</div> </div>
<div class="input-group-append"> <div class="input-group-append">
<button class="btn btn-outline-secondary cil-plus" type="button">Remove</button> <button class="btn btn-danger" type="button" (click)="remove()"><span class="cil-x btn-icon mr-2"></span>Remove</button>
</div> </div>
</div> </div>
</div> </div>
<ng-template #foreignModal let-modal>
<div class="modal-header">
<button type="button" class="btn-close" aria-label="Close"
(click)="modal.dismiss('Cross click')"></button>
</div>
<div class="modal-body">
<crud-card *ngIf="this.hasValue()" [resource]="this.foreignResource" [resource_id]="this.foreignModel._id" [is_modal]="true" (resourceDeleted)="onResourceDeleted($event)"></crud-card>
<crud-card *ngIf="! this.hasValue()" [resource]="this.foreignResource" [is_modal]="true" (resourceCreated)="onResourceCreated($event)"></crud-card>
</div>
<div class="modal-footer">
</div>
</ng-template>
`, `,
}) })
export class ForeignkeyTypeComponent extends FieldType<FieldTypeConfig> implements AfterContentInit export class ForeignkeyTypeComponent extends FieldType<FieldTypeConfig> implements OnInit
{ {
public foreignModel: any = {} public foreignModel: any = {}
public foreignLabel: string = "" public foreignLabel: string = ""
public foreignId: string = ""
public foreignResource : string = ""; public foreignResource : string = "";
public errorMsg: string = ""; public errorMsg: string = "";
public displayModal = false;
constructor(private crudService: CrudService) { constructor(private crudService: CrudService, private modalService: NgbModal) {
super(); super();
} }
@@ -68,17 +82,20 @@ export class ForeignkeyTypeComponent extends FieldType<FieldTypeConfig> implemen
formatter = (foreignModel: any) => foreignModel.label; formatter = (foreignModel: any) => foreignModel.label;
ngAfterContentInit() { ngOnInit() {
// @ts-ignore // @ts-ignore
this.foreignResource = this.field.foreignKey.reference.resource; this.foreignResource = this.field.foreignKey.reference.resource;
if (this.hasValue()) { if (this.hasValue()) {
this.crudService.get(this.foreignResource, this.formControl.value).subscribe((value: any) => { this.getResource(this.formControl.value)
this.foreignModel = value;
this.foreignLabel = this.foreignModel.label;
});
} }
} }
getResource(id: string) {
this.crudService.get(this.foreignResource, id).subscribe((value: any) => {
this.setValue(value);
});
}
search: OperatorFunction<string, readonly string[]> = (text$: Observable<string>) => { search: OperatorFunction<string, readonly string[]> = (text$: Observable<string>) => {
return text$.pipe( return text$.pipe(
debounceTime(200), debounceTime(200),
@@ -101,11 +118,40 @@ export class ForeignkeyTypeComponent extends FieldType<FieldTypeConfig> implemen
} }
selectedItem(event: any) { selectedItem(event: any) {
this.formControl.setValue(event.item._id) this.setValue(event.item);
this.foreignLabel = event.item.label; }
setValue(model: any) {
this.formControl.setValue(model._id)
this.foreignModel = model;
this.foreignLabel = model.label;
} }
hasValue() { hasValue() {
return this.formControl.value !== undefined; return this.formControl.value !== undefined;
} }
add(modal: any) {
this.modalService.open(modal);
}
onResourceCreated(resource_id: string) {
this.modalService.dismissAll();
this.getResource(resource_id);
}
see(modal: any) {
this.modalService.open(modal);
}
onResourceDeleted(resource_id: string) {
this.modalService.dismissAll();
this.remove();
}
remove() {
this.foreignModel = {};
this.foreignLabel = "";
this.formControl.setValue(undefined);
}
} }

View File

@@ -0,0 +1,10 @@
import { Component } from "@angular/core";
import { FieldType, FieldTypeConfig } from "@ngx-formly/core";
@Component({
selector: 'app-form-hidden-type',
template: `
<input type="hidden" [formControl]="formControl" class="form-control" [formlyAttributes]="field"/>
`,
})
export class HiddenTypeComponent extends FieldType<FieldTypeConfig> {}

View File

@@ -1,20 +1,16 @@
import {Component, OnInit} from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { FieldType } from '@ngx-formly/core'; import { FieldType } from '@ngx-formly/core';
import {Observable} from "rxjs";
@Component({ @Component({
selector: 'formly-multi-schema-type', selector: 'formly-multi-schema-type',
template: ` template: `
<div class="card mb-3">
<div class="card-body">
<label *ngIf="props.label" class="form-label">{{ props.label }}</label> <label *ngIf="props.label" class="form-label">{{ props.label }}</label>
<p *ngIf="props.description">{{ props.description }}</p> <p *ngIf="props.description">{{ props.description }}</p>
<div class="alert alert-danger" role="alert" *ngIf="showError && formControl.errors"> <div class="alert alert-danger" role="alert" *ngIf="showError && formControl.errors">
<formly-validation-message [field]="field"></formly-validation-message> <formly-validation-message [field]="field"></formly-validation-message>
</div> </div>
<formly-field *ngFor="let f of field.fieldGroup" [field]="f"></formly-field> <formly-field *ngFor="let f of field.fieldGroup" [field]="f"></formly-field>
</div>
</div>
`, `,
}) })
export class MultiSchemaTypeComponent extends FieldType implements OnInit { export class MultiSchemaTypeComponent extends FieldType implements OnInit {
@@ -24,11 +20,6 @@ export class MultiSchemaTypeComponent extends FieldType implements OnInit {
option.label = f.fieldGroup![1].fieldGroup![option.value].props!.label; option.label = f.fieldGroup![1].fieldGroup![option.value].props!.label;
f.fieldGroup![1].fieldGroup![option.value].props!.label = ""; f.fieldGroup![1].fieldGroup![option.value].props!.label = "";
}); });
f.fieldGroup![1].fieldGroup!.forEach(function (field) {
//field.fieldGroup![0].hide = true;
});
} }
} }

View File

@@ -5,7 +5,7 @@ import { FieldType } from '@ngx-formly/core';
selector: 'formly-object-type', selector: 'formly-object-type',
template: ` template: `
<div class="mb-3"> <div class="mb-3">
<legend *ngIf="props.label">{{ props.label }}</legend> <label *ngIf="props.label">{{ props.label }}</label>
<p *ngIf="props.description">{{ props.description }}</p> <p *ngIf="props.description">{{ props.description }}</p>
<div class="alert alert-danger" role="alert" *ngIf="showError && formControl.errors"> <div class="alert alert-danger" role="alert" *ngIf="showError && formControl.errors">
<formly-validation-message [field]="field"></formly-validation-message> <formly-validation-message [field]="field"></formly-validation-message>