Skip to content

Commit

Permalink
Feat/edit site (#56)
Browse files Browse the repository at this point in the history
* feat: edit site (init value btn-select)

- Change button select to accept incoming intial values
- Change visit component to add btn-select and form-g inside html

- WIP: update form component when initial values is up to date

Reviewed-by: andriac
[Refs_ticket] :  #5 , #6

* feat: get information when edit site

- Get all fields from specific site.json into editform
- Fix problem redirection if edit object site

- WIP : check how to update specific fields from object
- WIP : check how to manage listOption types site when reload or when
  come back into component after first init

Reviewed-by: andriac
[Refs_ticket]: #5 , #6

* fix: forgot add apiService property binding

Reviewed-by:andriac

* feat: update site with good properties

Change types_site object to array of ids
Remove extra key "dataComplement" to assign config

Reviewed-by:andriac
[Refs_ticket]: #5 , #6

* feat: prevent form appear if no type-site

- Hide form if btn-list type-site not selected
- Add custom error message mat-error if not selected (directive + custom
  message)

WIP: error message is showing up only if not selected after touched .
Maybe need to use asyncValidator ?

Reviewed-by: andriac
[Refs_tickets]: #5 , #6 , #54

* feat: change order to emit event bEdit

- Change order between change formService.changeData and bEditChange
- Preprocess for types_site seems to be useless (see todo)

Reviewed-by: andriac
[Refs_ticket]: : #5 , #6 , #54

* feat: solve request changes

- Apply prettier
- Change object key [''] by type properties
- Remove unused preprocess_data lines

[Refs_ticket] : closes #54
  • Loading branch information
andriacap authored and amandine-sahl committed Dec 8, 2023
1 parent 43c6d49 commit cf3163b
Show file tree
Hide file tree
Showing 17 changed files with 306 additions and 119 deletions.
15 changes: 5 additions & 10 deletions backend/gn_module_monitoring/monitoring/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from geonature.utils.env import DB
from geonature.core.gn_commons.models import TModules


class MonitoringModule(MonitoringObject):
def get(self, param_value=None, param_name=None, depth=0):
"""
Expand All @@ -26,12 +25,8 @@ class MonitoringSite(MonitoringObjectGeom):
"""

def preprocess_data(self, data):
type_site_ids = [type_site.id_nomenclature_type_site for type_site in self._model.types_site]
if len(data['types_site']) >0 :
for id_type_site in data['types_site']:
if int(id_type_site) not in type_site_ids:
type_site_ids.append(id_type_site)
#TODO: A enlever une fois qu'on aura enelever le champ "id_nomenclature_type_site" du model et de la bdd
data["id_nomenclature_type_site"]=data["types_site"][0]

data['types_site'] = type_site_ids
if len(data["types_site"]) > 0 and all(isinstance(x, int) for x in data["types_site"]):
data["id_nomenclature_type_site"] = data["types_site"][0]
else:
data["id_nomenclature_type_site"] = data["types_site"][0]["id_nomenclature_type_site"]
# TODO: A enlever une fois qu'on aura enelever le champ "id_nomenclature_type_site" du model et de la bdd
27 changes: 14 additions & 13 deletions backend/gn_module_monitoring/monitoring/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,19 @@ def serialize_geojson(self, obj):
return json.loads(obj.geom_geojson)


class BibTypeSiteSchema(MA.SQLAlchemyAutoSchema):
label = fields.Method("get_label_from_type_site")
# See if useful in the future:
# type_site = fields.Nested(NomenclatureSchema(only=("label_fr",)), dump_only=True)

def get_label_from_type_site(self, obj):
return obj.nomenclature.label_fr

class Meta:
model = BibTypeSite
include_fk = True
load_instance = True


class MonitoringSitesSchema(MA.SQLAlchemyAutoSchema):
class Meta:
Expand All @@ -53,6 +66,7 @@ class Meta:

geometry = fields.Method("serialize_geojson", dump_only=True)
pk = fields.Method("set_pk",dump_only=True)
types_site = MA.Nested(BibTypeSiteSchema, many=True)

def serialize_geojson(self, obj):
if obj.geom is not None:
Expand All @@ -61,19 +75,6 @@ def serialize_geojson(self, obj):
def set_pk(self,obj):
return self.Meta.model.get_id()

class BibTypeSiteSchema(MA.SQLAlchemyAutoSchema):
label = fields.Method("get_label_from_type_site")
# See if useful in the future:
# type_site = fields.Nested(NomenclatureSchema(only=("label_fr",)), dump_only=True)

def get_label_from_type_site(self, obj):
return obj.nomenclature.label_fr

class Meta:
model = BibTypeSite
include_fk = True
load_instance = True

class MonitoringVisitsSchema(MA.SQLAlchemyAutoSchema):
class Meta:
model = TMonitoringVisits
Expand Down
12 changes: 12 additions & 0 deletions backend/gn_module_monitoring/routes/site.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,15 @@ def delete_site(_id):
return {
"success": f"Item with {item.id_g} from table {item.__tablename__} is successfully deleted"
}, 200

@blueprint.route("/sites/<int:_id>", methods=["PATCH"])
def patch_sites(_id):
module_code = "generic"
object_type = "site"
customConfig = dict()
post_data = dict(request.get_json())
for keys in post_data["dataComplement"].keys():
if "config" in post_data["dataComplement"][keys]:
customConfig.update(post_data["dataComplement"][keys]["config"])
get_config(module_code, force=True, customSpecConfig=customConfig)
return create_or_update_object_api_sites_sites_group(module_code, object_type, _id), 201
44 changes: 0 additions & 44 deletions backend/gn_module_monitoring/routes/sites_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,47 +103,3 @@ def handle_validation_error(error):
status_code=422,
payload=error.data,
).to_dict()


# TODO: OPTIMIZE in order to adapt to new monitoring module (entry by sites_groups)


def create_or_update_object_api(module_code, object_type, id=None):
"""
route pour la création ou la modification d'un objet
si id est renseigné, c'est une création (PATCH)
sinon c'est une modification (POST)
:param module_code: reference le module concerne
:param object_type: le type d'object (site, visit, obervation)
:param id : l'identifiant de l'object (de id_base_site pour site)
:type module_code: str
:type object_type: str
:type id: int
:return: renvoie l'object crée ou modifié
:rtype: dict
"""
depth = to_int(request.args.get("depth", 1))

# recupération des données post
post_data = dict(request.get_json())
if module_code != "generic":
module = get_module("module_code", module_code)
else:
module = {"id_module": "generic"}
#TODO : A enlever une fois que le post_data contiendra geometry et type depuis le front
if object_type == "site":
post_data["geometry"]={'type':'Point', 'coordinates':[2.5,50]}
post_data["type"]='Feature'
# on rajoute id_module s'il n'est pas renseigné par défaut ??
if "id_module" not in post_data["properties"]:
module["id_module"] = "generic"
post_data["properties"]["id_module"] = module["id_module"]
else:
post_data["properties"]["id_module"] = module["id_module"]

return (
monitoring_definitions.monitoring_object_instance(module_code, object_type, id)
.create_or_update(post_data)
.serialize(depth)
)
3 changes: 2 additions & 1 deletion frontend/app/components/btn-select/btn-select.component.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<mat-form-field class="example-chip-list" appearance="fill">
<mat-label>{{ titleBtn }}</mat-label>
<mat-chip-list #chipList aria-label="option selection">
<mat-chip-list #chipList aria-label="option selection" [formControl]="listOpNeeded">
<mat-chip
*ngFor="let optionSelected of listOptionChosen"
[selectable]="selectable"
Expand Down Expand Up @@ -28,4 +28,5 @@
</mat-option>
</ng-container>
</mat-autocomplete>
<mat-error matErrorMessages></mat-error>
</mat-form-field>
35 changes: 33 additions & 2 deletions frontend/app/components/btn-select/btn-select.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ import {
Output,
ViewChild,
} from '@angular/core';
import { FormControl } from '@angular/forms';
import { FormControl, Validators } from '@angular/forms';
import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
import { Observable, iif, of } from 'rxjs';
import { debounceTime, distinctUntilChanged, map, startWith, switchMap } from 'rxjs/operators';

import { JsonData } from '../../types/jsondata';
import { FormService } from '../../services/form.service';

export interface EmptyObject {
name: string;
Expand All @@ -27,29 +28,41 @@ export interface EmptyObject {
export class BtnSelectComponent implements OnInit {
selectable = true;
removable = true;
isInit = false;
separatorKeysCodes: number[] = [ENTER, COMMA];
myControl = new FormControl();
listOpNeeded = new FormControl([],[Validators.required, Validators.minLength(1)])
@Input() placeholderText: string = 'Selectionnez vos options dans la liste';
@Input() titleBtn: string = 'Choix des options';

filteredOptions: Observable<any>;
listOptionChosen: string[] = [];
configObjAdded: JsonData = {};
genericResponse: JsonData = {};
objToEdit: JsonData;

@Input() bEdit: boolean;
@Input() isInitialValues:boolean;
@Input() paramToFilt: string;
@Input() callBackFunction: (
pageNumber: number,
limit: number,
valueToFilter: string
) => Observable<any>;
@Input() initValueFunction : ()=> JsonData;
@ViewChild('optionInput') optionInput: ElementRef<HTMLInputElement>;

@Output() public sendobject = new EventEmitter<JsonData>();

constructor() {}
constructor(private _formService: FormService) { }

ngOnInit() {

if(this.isInitialValues && !this.isInit){
this.initFromExistingObj(this.paramToFilt)
this.objToEdit.map(val => this.addObject(val))
this.isInit = true
}
this.filteredOptions = this.myControl.valueChanges.pipe(
startWith(''),
debounceTime(400),
Expand All @@ -63,6 +76,8 @@ export class BtnSelectComponent implements OnInit {
}),
map((res) => (res.length > 0 ? res : [{ name: 'Pas de résultats' }]))
);
this.listOpNeeded.setValue(this.listOptionChosen)
this._formService.changeExtraFormControl(this.listOpNeeded,"listOptBtnSelect")
}

remove(option: string): void {
Expand All @@ -76,6 +91,8 @@ export class BtnSelectComponent implements OnInit {
delete this.configObjAdded[option];
}
this.sendobject.emit(this.configObjAdded);
this.listOpNeeded.setValue(this.listOptionChosen)
this._formService.changeExtraFormControl(this.listOpNeeded,"listOptBtnSelect")
}

selected(event: MatAutocompleteSelectedEvent): void {
Expand All @@ -85,6 +102,8 @@ export class BtnSelectComponent implements OnInit {
: null;
this.optionInput.nativeElement.value = '';
this.myControl.setValue(null);
this.listOpNeeded.setValue(this.listOptionChosen)
this._formService.changeExtraFormControl(this.listOpNeeded,"listOptBtnSelect")
}

filterOnRequest(val: string, keyToFilt: string): Observable<any> {
Expand Down Expand Up @@ -120,4 +139,16 @@ export class BtnSelectComponent implements OnInit {
this.configObjAdded[name] = configAndId;
this.sendobject.emit(this.configObjAdded);
}

initFromExistingObj(keyToFilt: string){
const objInput = this.initValueFunction()
this.objToEdit = objInput .filter((obj) => {
Object.assign(obj, { name: obj[keyToFilt] })[keyToFilt];
delete obj[keyToFilt];
return obj;
})
this.objToEdit.map(obj => this.listOptionChosen.push(obj.name))

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ <h2>Attention</h2>
</pnx-modal-msg>

<div>
<div id="properties-form" class="cadre">
<div id="properties-form" class="cadre" *ngIf="!hideForm">
<!-- TODO: voir pour intiialisation si nécessaire à remettre dans la div du dessus -->
<!-- *ngIf="obj.bIsInitialized && objFormsDefinition" -->

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { IDataForm } from '../../interfaces/form';
import { ApiGeomService } from '../../services/api-geom.service';
import { ConfigJsonService } from '../../services/config-json.service';
import { FormService } from '../../services/form.service';
import { ObjectService } from '../../services/object.service';
import { IExtraForm } from '../../interfaces/object';

@Component({
selector: 'pnx-monitoring-form-g',
Expand All @@ -34,6 +34,10 @@ export class MonitoringFormComponentG implements OnInit {

@Input() sites: {};
@Input() apiService: ApiGeomService;
@Input() isExtraForm:boolean = false;

extraForm: IExtraForm;
hideForm: boolean = false;
dataForm: IDataForm;
searchSite = '';

Expand Down Expand Up @@ -63,17 +67,21 @@ export class MonitoringFormComponentG implements OnInit {
) {}

ngOnInit() {
// TODO: Avoid two subscribes one inside other (code test above doesn't work. When add type site the observable currentdata is not recall)
this._formService.currentData
.pipe(
tap((data) => {
this.obj = data;
this.obj.bIsInitialized = true;
this.apiService.init(this.obj.endPoint, this.obj.objSelected);
this.obj.id = this.obj[this.obj.pk]
}),
mergeMap((data: any) => this._configService.init(data.moduleCode))
mergeMap((data: any) => this._configService.init(data.moduleCode)),
mergeMap(() => this._formService.currentExtraFormCtrl )
)
.subscribe(() => {
.subscribe((frmCtrl) => {

this.isExtraForm ? this.addExtraFormCtrl(frmCtrl) : null;
this.isExtraForm ? this.checkValidExtraFormCtrl() : null;


this.queryParams = this._route.snapshot.queryParams || {};
this.bChainInput = this._configService.frontendParams()['bChainInput'];
Expand Down Expand Up @@ -294,7 +302,6 @@ export class MonitoringFormComponentG implements OnInit {
onSubmit() {
const { patch_update, ...sendValue } = this.dataForm;
const objToUpdateOrCreate = this._formService.postData(sendValue, this.obj);
console.log(objToUpdateOrCreate);
const action = this.obj.id
? this.apiService.patch(this.obj.id, objToUpdateOrCreate)
: this.apiService.create(objToUpdateOrCreate);
Expand Down Expand Up @@ -382,6 +389,25 @@ export class MonitoringFormComponentG implements OnInit {
this.procesPatchUpdateForm();
}

addExtraFormCtrl(frmCtrl: IExtraForm){
if (frmCtrl.frmName in this.objForm.controls){
this.objForm.setControl(frmCtrl.frmName,frmCtrl.frmCtrl)
} else{
this.objForm.addControl(frmCtrl.frmName,frmCtrl.frmCtrl)
}

this.extraForm = frmCtrl
}

checkValidExtraFormCtrl(){
if (this.extraForm.frmName in this.objForm.controls && this.objForm.get(this.extraForm.frmName).value != null && this.objForm.get(this.extraForm.frmName).value.length != 0 ){
this.hideForm = false
this.objForm.valid
} else {
this.hideForm = true
}
}

getConfigFromBtnSelect(event) {
// this.obj.specific == undefined ? (this.obj.specific = {}) : null;
// TODO: Ajout de tous les id_parents ["id_sites_groups" etc ] dans l'objet obj.dataComplement
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ export class MonitoringPropertiesGComponent implements OnInit {
}

onEditClick() {
this.bEditChange.emit(true);
this.selectedObj['id'] = this.selectedObj[this.selectedObj.pk];
this._formService.changeDataSub(
this.selectedObj,
this.objectType.objectType,
this.objectType.endPoint
);
this.bEditChange.emit(true);
}

ngOnChanges(changes: SimpleChanges): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<div>
<pnx-monitoring-form-g
[apiService]="siteService"
[isExtraForm]="true"
[objForm]="form"
#subscritionObjConfig
></pnx-monitoring-form-g>
Expand Down
Loading

0 comments on commit cf3163b

Please sign in to comment.