Coupled paraterized dictionary
This commit is contained in:
@@ -40,7 +40,8 @@ class ProvisionTemplateReference(BaseModel):
|
|||||||
"schema": "ProvisionTemplate",
|
"schema": "ProvisionTemplate",
|
||||||
"displayedFields": ['title', 'body']
|
"displayedFields": ['title', 'body']
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
|
props={"parametrized": True}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -56,6 +57,9 @@ class ContractTemplate(CrudDocument):
|
|||||||
default=[],
|
default=[],
|
||||||
props={"items-per-row": "1", "numbered": True}
|
props={"items-per-row": "1", "numbered": True}
|
||||||
)
|
)
|
||||||
variables: List[DictionaryEntry] = Field(default=[], format="dictionary")
|
variables: List[DictionaryEntry] = Field(
|
||||||
|
default=[],
|
||||||
|
format="dictionary",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from pydantic import BaseModel
|
from pydantic import BaseModel, Field
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from .models import ContractTemplate, ProvisionTemplate, PartyTemplate, ProvisionTemplateReference
|
from .models import ContractTemplate, ProvisionTemplate, PartyTemplate, ProvisionTemplateReference, DictionaryEntry
|
||||||
from ..core.schemas import Writer
|
from ..core.schemas import Writer
|
||||||
from ..core.models import text_area
|
from ..core.models import text_area
|
||||||
|
|
||||||
@@ -17,6 +17,11 @@ class ContractTemplateCreate(Writer):
|
|||||||
class ContractTemplateUpdate(BaseModel):
|
class ContractTemplateUpdate(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
parties: List[PartyTemplate] = []
|
parties: List[PartyTemplate] = []
|
||||||
|
variables: List[DictionaryEntry] = Field(
|
||||||
|
default=[],
|
||||||
|
format="dictionary",
|
||||||
|
props={"required": False}
|
||||||
|
)
|
||||||
provisions: List[ProvisionTemplateReference] = []
|
provisions: List[ProvisionTemplateReference] = []
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export class CardComponent implements OnInit {
|
|||||||
@Input() is_modal: Boolean = false;
|
@Input() is_modal: Boolean = false;
|
||||||
|
|
||||||
@Output() resourceCreated: EventEmitter<string> = new EventEmitter();
|
@Output() resourceCreated: EventEmitter<string> = new EventEmitter();
|
||||||
|
@Output() resourceUpdated: EventEmitter<string> = new EventEmitter();
|
||||||
@Output() resourceDeleted: EventEmitter<string> = new EventEmitter();
|
@Output() resourceDeleted: EventEmitter<string> = new EventEmitter();
|
||||||
|
|
||||||
|
|
||||||
@@ -81,6 +82,7 @@ export class CardComponent implements OnInit {
|
|||||||
this.crudService.update(this.resource!, model).subscribe((model: any) => {
|
this.crudService.update(this.resource!, model).subscribe((model: any) => {
|
||||||
this.model = model;
|
this.model = model;
|
||||||
this._modelLoading$.next(false);
|
this._modelLoading$.next(false);
|
||||||
|
this.resourceUpdated.emit(model._id)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ export class CrudFormlyJsonschemaOptions implements FormlyJsonschemaOptions {
|
|||||||
field.type = "date";
|
field.type = "date";
|
||||||
} else if (schema.hasOwnProperty('enum') && schema.enum.length == 1 && schema.enum[0] == schema.default ) {
|
} else if (schema.hasOwnProperty('enum') && schema.enum.length == 1 && schema.enum[0] == schema.default ) {
|
||||||
field.type = "hidden";
|
field.type = "hidden";
|
||||||
|
} else if (schema.type == "array" && schema.format == "dictionary") {
|
||||||
|
field.type = "dictionary";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (schema.hasOwnProperty('props')) {
|
if (schema.hasOwnProperty('props')) {
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ 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";
|
import {HiddenTypeComponent} from "./types/hidden.type";
|
||||||
|
import {DictionaryTypeComponent} from "./types/dictionary.type";
|
||||||
|
import {DictionaryService} from "./types/dictionary.service";
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@@ -33,8 +35,15 @@ import {HiddenTypeComponent} from "./types/hidden.type";
|
|||||||
MultiSchemaTypeComponent,
|
MultiSchemaTypeComponent,
|
||||||
ForeignkeyTypeComponent,
|
ForeignkeyTypeComponent,
|
||||||
HiddenTypeComponent,
|
HiddenTypeComponent,
|
||||||
|
DictionaryTypeComponent
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
JsonschemasService,
|
||||||
|
ApiService,
|
||||||
|
CrudService,
|
||||||
|
CrudFormlyJsonschemaService,
|
||||||
|
DictionaryService
|
||||||
],
|
],
|
||||||
providers: [ JsonschemasService, ApiService, CrudService, CrudFormlyJsonschemaService ],
|
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
@@ -51,6 +60,7 @@ import {HiddenTypeComponent} from "./types/hidden.type";
|
|||||||
{ name: 'multischema', component: MultiSchemaTypeComponent },
|
{ name: 'multischema', component: MultiSchemaTypeComponent },
|
||||||
{ name: 'foreign-key', component: ForeignkeyTypeComponent },
|
{ name: 'foreign-key', component: ForeignkeyTypeComponent },
|
||||||
{ name: 'hidden', component: HiddenTypeComponent },
|
{ name: 'hidden', component: HiddenTypeComponent },
|
||||||
|
{ name: 'dictionary', component: DictionaryTypeComponent },
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
FormlyBootstrapModule
|
FormlyBootstrapModule
|
||||||
|
|||||||
23
front/app/src/common/crud/types/dictionary.service.ts
Normal file
23
front/app/src/common/crud/types/dictionary.service.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import {Observable, Subject} from "rxjs";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DictionaryService {
|
||||||
|
fieldsParameters: {[field_id: string]: string[]} = {}
|
||||||
|
parameters: string[] = []
|
||||||
|
parameters$: Subject<string[]> = new Subject<string[]>()
|
||||||
|
|
||||||
|
updateParameters(field_id: string, newParameters: string[]) {
|
||||||
|
this.fieldsParameters[field_id] = newParameters;
|
||||||
|
|
||||||
|
this.parameters = [].concat();
|
||||||
|
for (const field of Object.values(this.fieldsParameters)) {
|
||||||
|
this.parameters = this.parameters.concat(field);
|
||||||
|
}
|
||||||
|
this.parameters = this.parameters.filter(
|
||||||
|
(item,index) => this.parameters.indexOf(item) === index
|
||||||
|
);
|
||||||
|
|
||||||
|
this.parameters$.next(this.parameters)
|
||||||
|
}
|
||||||
|
}
|
||||||
97
front/app/src/common/crud/types/dictionary.type.ts
Normal file
97
front/app/src/common/crud/types/dictionary.type.ts
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import {FieldType, FieldTypeConfig, FormlyFieldConfig, FormlyFormOptions} from '@ngx-formly/core';
|
||||||
|
import {FormControl, FormGroup, FormArray} from "@angular/forms";
|
||||||
|
import {DictionaryService} from "./dictionary.service";
|
||||||
|
import {JSONSchema7} from "json-schema";
|
||||||
|
import {FormlyJsonschema} from "@ngx-formly/core/json-schema";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'formly-dictionary-type',
|
||||||
|
template: `
|
||||||
|
<div class="mb-3">
|
||||||
|
<ngb-accordion #acc="ngbAccordion" activeIds="ngb-panel-0">
|
||||||
|
<ngb-panel>
|
||||||
|
<ng-template ngbPanelTitle>
|
||||||
|
<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>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<div class="alert alert-danger" role="alert" *ngIf="showError && formControl.errors">
|
||||||
|
<formly-validation-message [field]="field"></formly-validation-message>
|
||||||
|
</div>
|
||||||
|
<formly-form [model]="parameterModel" [fields]="parameterFields" [form]="parameterForm"></formly-form>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
</ngb-accordion>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
export class DictionaryTypeComponent extends FieldType<FieldTypeConfig> implements OnInit
|
||||||
|
{
|
||||||
|
public errorMsg: string = "";
|
||||||
|
|
||||||
|
parameterForm: FormGroup = new FormGroup({});
|
||||||
|
parameterList: string[] = [];
|
||||||
|
parameterModel: {[field_id: string]: string} = {};
|
||||||
|
parameterFields: FormlyFieldConfig[] = [];
|
||||||
|
|
||||||
|
constructor(protected service: DictionaryService,
|
||||||
|
private formlyJsonschema: FormlyJsonschema) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
for (const entry of this.formControl.value) {
|
||||||
|
this.parameterModel[entry.key] = entry.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.service.parameters$.subscribe((parameters) => {
|
||||||
|
this.parameterList = parameters;
|
||||||
|
for (const pname of parameters) {
|
||||||
|
if (Object.keys(this.parameterModel).indexOf(pname) == -1) {
|
||||||
|
this.parameterModel[pname] = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.parameterFields = [this.formlyJsonschema.toFieldConfig(
|
||||||
|
this.getFormSchema(parameters)
|
||||||
|
)];
|
||||||
|
this.parameterForm.setValue(this.parameterModel, {emitEvent: false});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.parameterForm.valueChanges.subscribe((values) => {
|
||||||
|
this.parameterModel = values;
|
||||||
|
|
||||||
|
const formValue: { key :string, value: string }[] = []
|
||||||
|
for (const [key, value] of Object.entries(this.parameterModel)) {
|
||||||
|
formValue.push({key, value});
|
||||||
|
}
|
||||||
|
this.formControl.setValue(formValue)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getFormSchema(properties: string[]) {
|
||||||
|
const schema: JSONSchema7 = {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let required: string[] = []
|
||||||
|
for (const pname of properties) {
|
||||||
|
schema.properties![pname] = {
|
||||||
|
type: "string",
|
||||||
|
title: pname
|
||||||
|
}
|
||||||
|
if (this.field.props.required) {
|
||||||
|
required.push(pname)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
schema.required = required
|
||||||
|
|
||||||
|
return schema
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
|||||||
import { CrudService, Filters } from "../crud.service";
|
import { CrudService, Filters } from "../crud.service";
|
||||||
import { CrudFormlyJsonschemaService } from "../crud-formly-jsonschema.service";
|
import { CrudFormlyJsonschemaService } from "../crud-formly-jsonschema.service";
|
||||||
import { FormGroup } from "@angular/forms";
|
import { FormGroup } from "@angular/forms";
|
||||||
|
import {DictionaryService} from "./dictionary.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'formly-foreignkey-type',
|
selector: 'formly-foreignkey-type',
|
||||||
@@ -61,13 +62,14 @@ import { FormGroup } from "@angular/forms";
|
|||||||
[resource_id]="this.foreignModel._id"
|
[resource_id]="this.foreignModel._id"
|
||||||
[schema]="this.foreignSchema"
|
[schema]="this.foreignSchema"
|
||||||
[is_modal]="true"
|
[is_modal]="true"
|
||||||
(resourceDeleted)="onResourceDeleted($event)">
|
(resourceDeleted)="onResourceDeleted($event)"
|
||||||
|
(resourceUpdated)="onResourceModified($event)">
|
||||||
</crud-card>
|
</crud-card>
|
||||||
<crud-card *ngIf="! this.hasValue()"
|
<crud-card *ngIf="! this.hasValue()"
|
||||||
[resource]="this.foreignResource"
|
[resource]="this.foreignResource"
|
||||||
[schema]="this.foreignSchema"
|
[schema]="this.foreignSchema"
|
||||||
[is_modal]="true"
|
[is_modal]="true"
|
||||||
(resourceCreated)="onResourceCreated($event)">
|
(resourceCreated)="onResourceModified($event)">
|
||||||
</crud-card>
|
</crud-card>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
@@ -88,7 +90,8 @@ export class ForeignkeyTypeComponent extends FieldType<FieldTypeConfig> implemen
|
|||||||
|
|
||||||
constructor(private crudService: CrudService,
|
constructor(private crudService: CrudService,
|
||||||
private formlyJsonschema: CrudFormlyJsonschemaService,
|
private formlyJsonschema: CrudFormlyJsonschemaService,
|
||||||
private modalService: NgbModal
|
private modalService: NgbModal,
|
||||||
|
protected service: DictionaryService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
@@ -114,18 +117,12 @@ export class ForeignkeyTypeComponent extends FieldType<FieldTypeConfig> implemen
|
|||||||
this.foreignModel = {};
|
this.foreignModel = {};
|
||||||
this.foreignLabel = "";
|
this.foreignLabel = "";
|
||||||
} else if (v != this.foreignModel._id) {
|
} else if (v != this.foreignModel._id) {
|
||||||
this.getResource(v).pipe(
|
this.loadModel(v);
|
||||||
map(v => { this.setModel(v); return v; }),
|
|
||||||
map( v => this.formControl.patchValue(v._id))
|
|
||||||
).subscribe()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
).subscribe();
|
).subscribe();
|
||||||
if (this.hasValue()) {
|
if (this.hasValue()) {
|
||||||
this.getResource(this.formControl.value).pipe(
|
this.loadModel(this.formControl.value);
|
||||||
map( v => { this.setModel(v); return v; }),
|
|
||||||
map( v => this.formControl.patchValue(v._id))
|
|
||||||
).subscribe()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,6 +130,13 @@ export class ForeignkeyTypeComponent extends FieldType<FieldTypeConfig> implemen
|
|||||||
return this.crudService.get(this.foreignResource, id);
|
return this.crudService.get(this.foreignResource, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadModel(id:string) {
|
||||||
|
this.getResource(id).pipe(
|
||||||
|
map(v => { this.setModel(v); return v; }),
|
||||||
|
map( v => this.formControl.patchValue(v._id))
|
||||||
|
).subscribe()
|
||||||
|
}
|
||||||
|
|
||||||
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),
|
||||||
@@ -163,6 +167,7 @@ export class ForeignkeyTypeComponent extends FieldType<FieldTypeConfig> implemen
|
|||||||
this.foreignModel = model;
|
this.foreignModel = model;
|
||||||
this.foreignLabel = model.label;
|
this.foreignLabel = model.label;
|
||||||
this.loadDisplayedFields();
|
this.loadDisplayedFields();
|
||||||
|
this.service.updateParameters(this.field.id!, this.getParameters())
|
||||||
}
|
}
|
||||||
|
|
||||||
hasValue() {
|
hasValue() {
|
||||||
@@ -173,9 +178,9 @@ export class ForeignkeyTypeComponent extends FieldType<FieldTypeConfig> implemen
|
|||||||
this.modalService.open(modal, { size: 'xl' });
|
this.modalService.open(modal, { size: 'xl' });
|
||||||
}
|
}
|
||||||
|
|
||||||
onResourceCreated(resource_id: string) {
|
onResourceModified(resource_id: string) {
|
||||||
this.modalService.dismissAll();
|
this.modalService.dismissAll();
|
||||||
this.getResource(resource_id);
|
this.loadModel(resource_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
see(modal: any) {
|
see(modal: any) {
|
||||||
@@ -213,4 +218,26 @@ export class ForeignkeyTypeComponent extends FieldType<FieldTypeConfig> implemen
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getParameters() {
|
||||||
|
return this.extractParameters(this.foreignModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
extractParameters(obj: any) {
|
||||||
|
let result: string[] = [];
|
||||||
|
for (const [k, v] of Object.entries(obj)) {
|
||||||
|
if (typeof(obj[k]) == "string") {
|
||||||
|
const matches = obj[k].match(/%[^\s.]+%/g);
|
||||||
|
if (matches) {
|
||||||
|
result = result.concat(matches.map((p: string | any[]) => p.slice(1,-1)) || []);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result.concat();
|
||||||
|
} else if (typeof(obj[k]) == "object") {
|
||||||
|
result = result.concat(this.extractParameters(obj[k]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user