Coupled paraterized dictionary

This commit is contained in:
2023-02-06 17:44:03 +01:00
parent d12e35cc10
commit 920bb39ca1
8 changed files with 188 additions and 18 deletions

View File

@@ -40,7 +40,8 @@ class ProvisionTemplateReference(BaseModel):
"schema": "ProvisionTemplate",
"displayedFields": ['title', 'body']
},
}
},
props={"parametrized": True}
)
@@ -56,6 +57,9 @@ class ContractTemplate(CrudDocument):
default=[],
props={"items-per-row": "1", "numbered": True}
)
variables: List[DictionaryEntry] = Field(default=[], format="dictionary")
variables: List[DictionaryEntry] = Field(
default=[],
format="dictionary",
)

View File

@@ -1,7 +1,7 @@
from pydantic import BaseModel
from pydantic import BaseModel, Field
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.models import text_area
@@ -17,6 +17,11 @@ class ContractTemplateCreate(Writer):
class ContractTemplateUpdate(BaseModel):
name: str
parties: List[PartyTemplate] = []
variables: List[DictionaryEntry] = Field(
default=[],
format="dictionary",
props={"required": False}
)
provisions: List[ProvisionTemplateReference] = []

View File

@@ -19,6 +19,7 @@ export class CardComponent implements OnInit {
@Input() is_modal: Boolean = false;
@Output() resourceCreated: EventEmitter<string> = new EventEmitter();
@Output() resourceUpdated: 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.model = model;
this._modelLoading$.next(false);
this.resourceUpdated.emit(model._id)
});
}
}

View File

@@ -45,6 +45,8 @@ export class CrudFormlyJsonschemaOptions implements FormlyJsonschemaOptions {
field.type = "date";
} else if (schema.hasOwnProperty('enum') && schema.enum.length == 1 && schema.enum[0] == schema.default ) {
field.type = "hidden";
} else if (schema.type == "array" && schema.format == "dictionary") {
field.type = "dictionary";
}
if (schema.hasOwnProperty('props')) {

View File

@@ -20,6 +20,8 @@ import { JsonschemasService } from "./jsonschemas.service";
import { MultiSchemaTypeComponent } from "./types/multischema.type";
import { ForeignkeyTypeComponent } from "./types/foreignkey.type";
import {HiddenTypeComponent} from "./types/hidden.type";
import {DictionaryTypeComponent} from "./types/dictionary.type";
import {DictionaryService} from "./types/dictionary.service";
@NgModule({
@@ -33,8 +35,15 @@ import {HiddenTypeComponent} from "./types/hidden.type";
MultiSchemaTypeComponent,
ForeignkeyTypeComponent,
HiddenTypeComponent,
DictionaryTypeComponent
],
providers: [
JsonschemasService,
ApiService,
CrudService,
CrudFormlyJsonschemaService,
DictionaryService
],
providers: [ JsonschemasService, ApiService, CrudService, CrudFormlyJsonschemaService ],
imports: [
CommonModule,
HttpClientModule,
@@ -51,6 +60,7 @@ import {HiddenTypeComponent} from "./types/hidden.type";
{ name: 'multischema', component: MultiSchemaTypeComponent },
{ name: 'foreign-key', component: ForeignkeyTypeComponent },
{ name: 'hidden', component: HiddenTypeComponent },
{ name: 'dictionary', component: DictionaryTypeComponent },
]
}),
FormlyBootstrapModule

View 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)
}
}

View 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
}
}

View File

@@ -7,6 +7,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { CrudService, Filters } from "../crud.service";
import { CrudFormlyJsonschemaService } from "../crud-formly-jsonschema.service";
import { FormGroup } from "@angular/forms";
import {DictionaryService} from "./dictionary.service";
@Component({
selector: 'formly-foreignkey-type',
@@ -61,13 +62,14 @@ import { FormGroup } from "@angular/forms";
[resource_id]="this.foreignModel._id"
[schema]="this.foreignSchema"
[is_modal]="true"
(resourceDeleted)="onResourceDeleted($event)">
(resourceDeleted)="onResourceDeleted($event)"
(resourceUpdated)="onResourceModified($event)">
</crud-card>
<crud-card *ngIf="! this.hasValue()"
[resource]="this.foreignResource"
[schema]="this.foreignSchema"
[is_modal]="true"
(resourceCreated)="onResourceCreated($event)">
(resourceCreated)="onResourceModified($event)">
</crud-card>
</div>
<div class="modal-footer">
@@ -88,7 +90,8 @@ export class ForeignkeyTypeComponent extends FieldType<FieldTypeConfig> implemen
constructor(private crudService: CrudService,
private formlyJsonschema: CrudFormlyJsonschemaService,
private modalService: NgbModal
private modalService: NgbModal,
protected service: DictionaryService
) {
super();
}
@@ -114,18 +117,12 @@ export class ForeignkeyTypeComponent extends FieldType<FieldTypeConfig> implemen
this.foreignModel = {};
this.foreignLabel = "";
} else if (v != this.foreignModel._id) {
this.getResource(v).pipe(
map(v => { this.setModel(v); return v; }),
map( v => this.formControl.patchValue(v._id))
).subscribe()
this.loadModel(v);
}
})
).subscribe();
if (this.hasValue()) {
this.getResource(this.formControl.value).pipe(
map( v => { this.setModel(v); return v; }),
map( v => this.formControl.patchValue(v._id))
).subscribe()
this.loadModel(this.formControl.value);
}
}
@@ -133,6 +130,13 @@ export class ForeignkeyTypeComponent extends FieldType<FieldTypeConfig> implemen
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>) => {
return text$.pipe(
debounceTime(200),
@@ -163,6 +167,7 @@ export class ForeignkeyTypeComponent extends FieldType<FieldTypeConfig> implemen
this.foreignModel = model;
this.foreignLabel = model.label;
this.loadDisplayedFields();
this.service.updateParameters(this.field.id!, this.getParameters())
}
hasValue() {
@@ -173,9 +178,9 @@ export class ForeignkeyTypeComponent extends FieldType<FieldTypeConfig> implemen
this.modalService.open(modal, { size: 'xl' });
}
onResourceCreated(resource_id: string) {
onResourceModified(resource_id: string) {
this.modalService.dismissAll();
this.getResource(resource_id);
this.loadModel(resource_id);
}
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
}
}