Adding Date and working on fereign keys
This commit is contained in:
@@ -24,8 +24,13 @@ class Individual(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class Employee(BaseModel):
|
class Employee(BaseModel):
|
||||||
entity_id: str
|
|
||||||
role: str
|
role: str
|
||||||
|
entity_id: str = Field(foreignKey={
|
||||||
|
"reference": {
|
||||||
|
"resource": "entity",
|
||||||
|
"fields": "_id"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
class Corporation(BaseModel):
|
class Corporation(BaseModel):
|
||||||
@@ -46,6 +51,7 @@ class Entity(Document):
|
|||||||
|
|
||||||
class Settings:
|
class Settings:
|
||||||
bson_encoders = {
|
bson_encoders = {
|
||||||
date: lambda dt: datetime(year=dt.year, month=dt.month, day=dt.day, hour=0, minute=0, second=0) \
|
date: lambda dt: dt if hasattr(dt, 'hour')
|
||||||
if not hasattr(dt, 'hour') else dt
|
else datetime(year=dt.year, month=dt.month, day=dt.day,
|
||||||
|
hour=0, minute=0, second=0)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, Input, OnInit } 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 { FormlyJsonschema } from '@ngx-formly/core/json-schema';
|
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
|
||||||
import { CrudService } from '../crud.service'
|
import { CrudService } from '../crud.service'
|
||||||
import { BehaviorSubject } from "rxjs";
|
import { BehaviorSubject } from "rxjs";
|
||||||
import { JsonschemasService } from "../jsonschemas.service";
|
import {CrudFormlyJsonschemaService} from "../crud-formly-jsonschema.service";
|
||||||
|
|
||||||
export interface Model {
|
export interface Model {
|
||||||
email: string;
|
email: string;
|
||||||
@@ -33,27 +32,27 @@ export class CardComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor(private crudService: CrudService,
|
constructor(private crudService: CrudService,
|
||||||
private jsonSchemasService: JsonschemasService,
|
private formlyJsonschema: CrudFormlyJsonschemaService,
|
||||||
private formlyJsonschema: FormlyJsonschema,
|
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this._loading$.next(true);
|
this._loading$.next(true);
|
||||||
|
let fields$;
|
||||||
if (this.isCreateForm()) {
|
if (this.isCreateForm()) {
|
||||||
this.jsonSchemasService.getCreateResource(this.resource!).subscribe((schemas: any) => {
|
fields$ = this.formlyJsonschema.getCreateFields(this.resource!);
|
||||||
this.fields = [this.formlyJsonschema.toFieldConfig(schemas)];
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
this.jsonSchemasService.getUpdateResource(this.resource!).subscribe((schemas: any) => {
|
|
||||||
this.fields = [this.formlyJsonschema.toFieldConfig(schemas)];
|
|
||||||
})
|
|
||||||
this.crudService.get(this.resource!, this.resource_id!).subscribe((model: any) => {
|
this.crudService.get(this.resource!, this.resource_id!).subscribe((model: any) => {
|
||||||
this.model = model
|
this.model = model
|
||||||
this._loading$.next(false);
|
this._loading$.next(false);
|
||||||
});
|
});
|
||||||
|
fields$ = this.formlyJsonschema.getUpdateFields(this.resource!);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fields$.subscribe((fields: any) => {
|
||||||
|
this.fields = [fields]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onSubmit(model: any) {
|
onSubmit(model: any) {
|
||||||
|
|||||||
34
front/app/src/common/crud/crud-formly-jsonschema.service.ts
Normal file
34
front/app/src/common/crud/crud-formly-jsonschema.service.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { FormlyJsonschema } from "@ngx-formly/core/json-schema";
|
||||||
|
import { FormlyJsonschemaOptions } from "@ngx-formly/core/json-schema/formly-json-schema.service";
|
||||||
|
import { FormlyFieldConfig } from "@ngx-formly/core";
|
||||||
|
import { JSONSchema7 } from 'json-schema';
|
||||||
|
import {JsonschemasService } from "./jsonschemas.service";
|
||||||
|
import {Observable, map, tap} from "rxjs";
|
||||||
|
import {Injectable} from "@angular/core";
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class CrudFormlyJsonschemaService extends FormlyJsonschema {
|
||||||
|
constructor(private jsonSchemasService: JsonschemasService) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
override toFieldConfig(schema: JSONSchema7, options?: FormlyJsonschemaOptions): FormlyFieldConfig {
|
||||||
|
return super.toFieldConfig(schema, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
getCreateFields(resourceName: string): Observable<FormlyFieldConfig> {
|
||||||
|
return this.jsonSchemasService.getCreateResource(resourceName).pipe(
|
||||||
|
map((schemas: any) => this.toFieldConfig(schemas)),
|
||||||
|
tap(console.log),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
getUpdateFields(resourceName: string): Observable<FormlyFieldConfig> {
|
||||||
|
return this.jsonSchemasService.getUpdateResource(resourceName).pipe(
|
||||||
|
map((schemas: any) => this.toFieldConfig(schemas)),
|
||||||
|
tap(console.log),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,10 +12,13 @@ import { ListComponent } from './list/list.component';
|
|||||||
import { ArrayTypeComponent } from "./types/array.type";
|
import { ArrayTypeComponent } from "./types/array.type";
|
||||||
import { ObjectTypeComponent } from "./types/object.type";
|
import { ObjectTypeComponent } from "./types/object.type";
|
||||||
import { DatetimeTypeComponent } from "./types/datetime.type";
|
import { DatetimeTypeComponent } from "./types/datetime.type";
|
||||||
|
import { DateTypeComponent } from "./types/date.type";
|
||||||
import { ApiService, CrudService } from "./crud.service";
|
import { ApiService, CrudService } from "./crud.service";
|
||||||
|
import { CrudFormlyJsonschemaService } from "./crud-formly-jsonschema.service";
|
||||||
import { NgbModule} from "@ng-bootstrap/ng-bootstrap";
|
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";
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@@ -24,10 +27,12 @@ import { MultiSchemaTypeComponent } from "./types/multischema.type";
|
|||||||
ListComponent,
|
ListComponent,
|
||||||
ObjectTypeComponent,
|
ObjectTypeComponent,
|
||||||
DatetimeTypeComponent,
|
DatetimeTypeComponent,
|
||||||
|
DateTypeComponent,
|
||||||
ArrayTypeComponent,
|
ArrayTypeComponent,
|
||||||
MultiSchemaTypeComponent
|
MultiSchemaTypeComponent,
|
||||||
|
ForeignkeyTypeComponent,
|
||||||
],
|
],
|
||||||
providers: [ JsonschemasService, ApiService, CrudService ],
|
providers: [ JsonschemasService, ApiService, CrudService, CrudFormlyJsonschemaService ],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
@@ -39,8 +44,10 @@ import { MultiSchemaTypeComponent } from "./types/multischema.type";
|
|||||||
types: [
|
types: [
|
||||||
{ name: 'object', component: ObjectTypeComponent },
|
{ name: 'object', component: ObjectTypeComponent },
|
||||||
{ name: 'datetime', component: DatetimeTypeComponent },
|
{ name: 'datetime', component: DatetimeTypeComponent },
|
||||||
|
{ name: 'date', component: DateTypeComponent },
|
||||||
{ name: 'array', component: ArrayTypeComponent },
|
{ name: 'array', component: ArrayTypeComponent },
|
||||||
{ name: 'multischema', component: MultiSchemaTypeComponent },
|
{ name: 'multischema', component: MultiSchemaTypeComponent },
|
||||||
|
{ name: 'foreign-key', component: ForeignkeyTypeComponent },
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
FormlyBootstrapModule
|
FormlyBootstrapModule
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Injectable, Inject } from '@angular/core';
|
import { Injectable, Inject } from '@angular/core';
|
||||||
import { Schema } from "./jsonschemas.service";
|
import { Schema } from "./jsonschemas.service";
|
||||||
|
import {catchError} from "rxjs/operators";
|
||||||
|
import {from} from "rxjs";
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {ApiService} from "./crud.service";
|
import { Observable } from "rxjs";
|
||||||
import {Observable} from "rxjs";
|
import { Injectable } from "@angular/core";
|
||||||
import {Injectable} from "@angular/core";
|
import { ApiService } from "./crud.service";
|
||||||
|
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
@@ -9,7 +9,9 @@ import {Injectable} from "@angular/core";
|
|||||||
export class JsonschemasService {
|
export class JsonschemasService {
|
||||||
private rawSchemas: any | null = null;
|
private rawSchemas: any | null = null;
|
||||||
|
|
||||||
constructor(private apiService: ApiService) {}
|
constructor(
|
||||||
|
private apiService: ApiService
|
||||||
|
) {}
|
||||||
|
|
||||||
getSchemas(): Observable<Schema> {
|
getSchemas(): Observable<Schema> {
|
||||||
return new Observable<Schema>((observer) => {
|
return new Observable<Schema>((observer) => {
|
||||||
@@ -44,6 +46,10 @@ export class JsonschemasService {
|
|||||||
this.resolveReference(resource, prop.items);
|
this.resolveReference(resource, prop.items);
|
||||||
} else if (prop.format === 'date-time') {
|
} else if (prop.format === 'date-time') {
|
||||||
prop.type = "datetime";
|
prop.type = "datetime";
|
||||||
|
} else if (prop.format === 'date') {
|
||||||
|
prop.type = "date";
|
||||||
|
} else if (prop.hasOwnProperty('foreignKey')) {
|
||||||
|
prop.type = "foreign-key";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
72
front/app/src/common/crud/types/date.type.ts
Normal file
72
front/app/src/common/crud/types/date.type.ts
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
|
||||||
|
import { Component, ElementRef, OnInit, ViewChild} from '@angular/core';
|
||||||
|
import { formatDate } from "@angular/common";
|
||||||
|
import { NgbDateStruct, NgbTimeStruct } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import { FieldType, FieldTypeConfig } from '@ngx-formly/core';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-form-datepicker-type',
|
||||||
|
template: `
|
||||||
|
<label *ngIf="props.label && props['hideLabel'] !== true" [attr.for]="id"
|
||||||
|
class="form-label">{{ props.label }}
|
||||||
|
<span *ngIf="props.required && props['hideRequiredMarker'] !== true" aria-hidden="true">*</span>
|
||||||
|
</label>
|
||||||
|
<div class="input-group" *ngIf="! this.field.props.readonly">
|
||||||
|
<input type="hidden"
|
||||||
|
[formControl]="formControl"
|
||||||
|
[formlyAttributes]="field"
|
||||||
|
[class.is-invalid]="showError"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
class="form-control"
|
||||||
|
placeholder="yyyy-mm-dd"
|
||||||
|
name="dp"
|
||||||
|
[(ngModel)]="date"
|
||||||
|
(ngModelChange)="changeDatetime($event)"
|
||||||
|
ngbDatepicker
|
||||||
|
#d="ngbDatepicker"
|
||||||
|
/>
|
||||||
|
<button class="btn btn-outline-secondary bi bi-calendar3" (click)="d.toggle()" type="button"></button>
|
||||||
|
</div>
|
||||||
|
<div class="input-group" *ngIf="this.field.props.readonly">
|
||||||
|
<input class="form-control" value="{{ this.datetime.toLocaleString() }}" disabled=""/>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
export class DateTypeComponent extends FieldType<FieldTypeConfig> implements OnInit
|
||||||
|
{
|
||||||
|
public time : NgbTimeStruct = { hour: 12, minute: 0, second: 0 }
|
||||||
|
public date : NgbDateStruct = { year: 2023, month: 1, day: 9 }
|
||||||
|
public datetime : Date = new Date()
|
||||||
|
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.formControl.valueChanges.subscribe(value => {
|
||||||
|
this.datetime = new Date(value)
|
||||||
|
this.date = this.getDateStruct(this.datetime);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getDateStruct(d: Date) {
|
||||||
|
return {
|
||||||
|
year: d.getFullYear(),
|
||||||
|
month: d.getMonth() + 1,
|
||||||
|
day: d.getDate(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
changeDatetime(event: any) {
|
||||||
|
this.datetime.setFullYear(this.date.year)
|
||||||
|
this.datetime.setMonth(this.date.month - 1)
|
||||||
|
this.datetime.setDate(this.date.day)
|
||||||
|
|
||||||
|
this.formControl.setValue(
|
||||||
|
formatDate(this.datetime, 'YYYY-MM-dd', 'EN_US', 'CET')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,14 +6,14 @@ import { FieldType, FieldTypeConfig } from '@ngx-formly/core';
|
|||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-form-datepicker-type',
|
selector: 'app-form-datetimepicker-type',
|
||||||
template: `
|
template: `
|
||||||
<label *ngIf="props.label && props['hideLabel'] !== true" [attr.for]="id"
|
<label *ngIf="props.label && props['hideLabel'] !== true" [attr.for]="id"
|
||||||
class="form-label">{{ props.label }}
|
class="form-label">{{ props.label }}
|
||||||
<span *ngIf="props.required && props['hideRequiredMarker'] !== true" aria-hidden="true">*</span>
|
<span *ngIf="props.required && props['hideRequiredMarker'] !== true" aria-hidden="true">*</span>
|
||||||
</label>
|
</label>
|
||||||
<div class="input-group" *ngIf="! this.field.props.readonly">
|
<div class="input-group" *ngIf="! this.field.props.readonly">
|
||||||
<input type="text"
|
<input type="hidden"
|
||||||
[formControl]="formControl"
|
[formControl]="formControl"
|
||||||
[formlyAttributes]="field"
|
[formlyAttributes]="field"
|
||||||
[class.is-invalid]="showError"
|
[class.is-invalid]="showError"
|
||||||
|
|||||||
142
front/app/src/common/crud/types/foreignkey.type.ts
Normal file
142
front/app/src/common/crud/types/foreignkey.type.ts
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
import {Component, OnInit} from '@angular/core';
|
||||||
|
import {Observable, OperatorFunction, switchMapTo, of, from, exhaustAll, mergeAll, concatAll} from 'rxjs';
|
||||||
|
import { catchError } from 'rxjs/operators';
|
||||||
|
import { debounceTime, distinctUntilChanged, map, tap, merge } from 'rxjs/operators';
|
||||||
|
import { FieldType, FieldTypeConfig} from '@ngx-formly/core';
|
||||||
|
import {CrudService} from "../crud.service";
|
||||||
|
|
||||||
|
const states = [
|
||||||
|
'Alabama',
|
||||||
|
'Alaska',
|
||||||
|
'American Samoa',
|
||||||
|
'Arizona',
|
||||||
|
'Arkansas',
|
||||||
|
'California',
|
||||||
|
'Colorado',
|
||||||
|
'Connecticut',
|
||||||
|
'Delaware',
|
||||||
|
'District Of Columbia',
|
||||||
|
'Federated States Of Micronesia',
|
||||||
|
'Florida',
|
||||||
|
'Georgia',
|
||||||
|
'Guam',
|
||||||
|
'Hawaii',
|
||||||
|
'Idaho',
|
||||||
|
'Illinois',
|
||||||
|
'Indiana',
|
||||||
|
'Iowa',
|
||||||
|
'Kansas',
|
||||||
|
'Kentucky',
|
||||||
|
'Louisiana',
|
||||||
|
'Maine',
|
||||||
|
'Marshall Islands',
|
||||||
|
'Maryland',
|
||||||
|
'Massachusetts',
|
||||||
|
'Michigan',
|
||||||
|
'Minnesota',
|
||||||
|
'Mississippi',
|
||||||
|
'Missouri',
|
||||||
|
'Montana',
|
||||||
|
'Nebraska',
|
||||||
|
'Nevada',
|
||||||
|
'New Hampshire',
|
||||||
|
'New Jersey',
|
||||||
|
'New Mexico',
|
||||||
|
'New York',
|
||||||
|
'North Carolina',
|
||||||
|
'North Dakota',
|
||||||
|
'Northern Mariana Islands',
|
||||||
|
'Ohio',
|
||||||
|
'Oklahoma',
|
||||||
|
'Oregon',
|
||||||
|
'Palau',
|
||||||
|
'Pennsylvania',
|
||||||
|
'Puerto Rico',
|
||||||
|
'Rhode Island',
|
||||||
|
'South Carolina',
|
||||||
|
'South Dakota',
|
||||||
|
'Tennessee',
|
||||||
|
'Texas',
|
||||||
|
'Utah',
|
||||||
|
'Vermont',
|
||||||
|
'Virgin Islands',
|
||||||
|
'Virginia',
|
||||||
|
'Washington',
|
||||||
|
'West Virginia',
|
||||||
|
'Wisconsin',
|
||||||
|
'Wyoming',
|
||||||
|
];
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'formly-array-type',
|
||||||
|
template: `
|
||||||
|
<div class="mb-3">
|
||||||
|
<label *ngIf="props.label && props['hideLabel'] !== true" [attr.for]="id"
|
||||||
|
class="form-label">{{ props.label }}
|
||||||
|
<span *ngIf="props.required && props['hideRequiredMarker'] !== true" aria-hidden="true">*</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="alert alert-danger" role="alert" *ngIf="showError && formControl.errors">
|
||||||
|
<formly-validation-message [field]="field"></formly-validation-message>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input
|
||||||
|
class="form-control"
|
||||||
|
name="autocomplete"
|
||||||
|
[(ngModel)]="foreignId"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Type the first letters..."
|
||||||
|
[(ngModel)]="foreignId"
|
||||||
|
[ngbTypeahead]="search" >
|
||||||
|
<div class="input-group-append">
|
||||||
|
<button class="btn btn-outline-secondary cil-plus" type="button">Button</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
export class ForeignkeyTypeComponent extends FieldType<FieldTypeConfig> implements OnInit
|
||||||
|
{
|
||||||
|
public foreignId: string = ""
|
||||||
|
public foreignResource : string = "";
|
||||||
|
public errorMsg: string = "";
|
||||||
|
|
||||||
|
constructor(private crudService: CrudService) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
asyncSelected: string = "toto";
|
||||||
|
typeaheadLoading: boolean = false;
|
||||||
|
typeaheadNoResults: boolean = true;
|
||||||
|
dataSource: Observable<any> = new Observable();
|
||||||
|
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.foreignResource = this.field.key!.toString().split('_')[0];
|
||||||
|
this.dataSource = new Observable((observer: any) => {
|
||||||
|
observer.next(this.asyncSelected);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// fired every time search string is changed
|
||||||
|
search: OperatorFunction<string, readonly string[]> = (text$: Observable<string>) => {
|
||||||
|
return text$.pipe(
|
||||||
|
debounceTime(200),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
map((term) => this.getList(term)),
|
||||||
|
concatAll(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
getList(term: string) : Observable<readonly string[]> {
|
||||||
|
return this.crudService.getList(this.foreignResource, 0, 10, '_id', 'asc')
|
||||||
|
.pipe(
|
||||||
|
map((result: any) => result["items"]),
|
||||||
|
tap(console.log),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user