From 69280984e22d6e7a9793db4223141f3726236d12 Mon Sep 17 00:00:00 2001 From: amandine-sahl Date: Mon, 11 Dec 2023 17:06:39 +0100 Subject: [PATCH] [MONITORING - site] - db and model evolution to make site cross module - some fixes on GN2CommonModule forms --- .../geonature/core/gn_monitoring/models.py | 98 +++++++++++-- .../geonature/core/gn_monitoring/routes.py | 12 +- ..._add_sensitivity_filter_export_synthese.py | 2 +- ...ring_add_id_digitizer_to_t_observations.py | 67 +++++++++ ...g_add_observers_txt_column_t_base_visit.py | 38 +++++ ...9c1298_monitoring_create_t_observations.py | 55 ++++++++ ...13ce8_monitoring_create_cor_module_type.py | 64 +++++++++ ...fb13ce8_monitoring_create_bib_type_site.py | 77 +++++++++++ ...a49ce5c_monitoring_create_cor_site_type.py | 130 ++++++++++++++++++ .../form/datalist/datalist.component.ts | 58 +++++--- .../dynamic-form/dynamic-form.component.html | 9 +- .../form/observers/observers.component.ts | 2 +- 12 files changed, 566 insertions(+), 46 deletions(-) create mode 100644 backend/geonature/migrations/versions/6734d8f7eb2a_monitoring_add_id_digitizer_to_t_observations.py create mode 100644 backend/geonature/migrations/versions/8309591841f3_monitoring_add_observers_txt_column_t_base_visit.py create mode 100644 backend/geonature/migrations/versions/9b88459c1298_monitoring_create_t_observations.py create mode 100644 backend/geonature/migrations/versions/a54bafb13ce8_monitoring_create_cor_module_type.py create mode 100644 backend/geonature/migrations/versions/b53bafb13ce8_monitoring_create_bib_type_site.py create mode 100644 backend/geonature/migrations/versions/ce54ba49ce5c_monitoring_create_cor_site_type.py diff --git a/backend/geonature/core/gn_monitoring/models.py b/backend/geonature/core/gn_monitoring/models.py index b764fa6a00..6ba3a45ca7 100644 --- a/backend/geonature/core/gn_monitoring/models.py +++ b/backend/geonature/core/gn_monitoring/models.py @@ -7,7 +7,7 @@ from geoalchemy2 import Geometry from sqlalchemy import ForeignKey from sqlalchemy.orm import relationship -from sqlalchemy.dialects.postgresql import UUID +from sqlalchemy.dialects.postgresql import UUID, JSONB from sqlalchemy.sql import select, func @@ -16,12 +16,13 @@ from utils_flask_sqla.serializers import serializable from utils_flask_sqla_geo.serializers import geoserializable +from pypnnomenclature.models import TNomenclatures from geonature.core.gn_commons.models import TModules from geonature.core.gn_meta.models import TDatasets from geonature.utils.env import DB -corVisitObserver = DB.Table( +cor_visit_observer = DB.Table( "cor_visit_observer", DB.Column( "id_base_visit", @@ -39,7 +40,7 @@ ) -corSiteModule = DB.Table( +cor_site_module = DB.Table( "cor_site_module", DB.Column( "id_base_site", @@ -56,7 +57,7 @@ schema="gn_monitoring", ) -corSiteArea = DB.Table( +cor_site_area = DB.Table( "cor_site_area", DB.Column( "id_base_site", @@ -68,6 +69,58 @@ schema="gn_monitoring", ) +cor_module_type = DB.Table( + "cor_module_type", + DB.Column( + "id_module", + DB.Integer, + DB.ForeignKey("gn_commons.t_modules.id_module"), + primary_key=True, + ), + DB.Column( + "id_type_site", + DB.Integer, + DB.ForeignKey("gn_monitoring.bib_type_site.id_nomenclature_type_site"), + primary_key=True, + ), + schema="gn_monitoring", +) + +cor_site_type = DB.Table( + "cor_site_type", + DB.Column( + "id_base_site", + DB.Integer, + DB.ForeignKey("gn_monitoring.t_base_sites.id_base_site"), + primary_key=True, + ), + DB.Column( + "id_type_site", + DB.Integer, + DB.ForeignKey("gn_monitoring.bib_type_site.id_nomenclature_type_site"), + primary_key=True, + ), + schema="gn_monitoring", +) + + +@serializable +class BibTypeSite(DB.Model): + __tablename__ = "bib_type_site" + __table_args__ = {"schema": "gn_monitoring"} + + id_nomenclature_type_site = DB.Column( + DB.ForeignKey("ref_nomenclatures.t_nomenclatures.id_nomenclature"), + nullable=False, + primary_key=True, + ) + config = DB.Column(JSONB) + nomenclature = DB.relationship( + TNomenclatures, uselist=False, backref=DB.backref("bib_type_site", uselist=False) + ) + + sites = DB.relationship("TBaseSites", secondary=cor_site_type, lazy="noload") + @serializable class TBaseVisits(DB.Model): @@ -84,7 +137,7 @@ class TBaseVisits(DB.Model): # Pour le moment non défini comme une clé étrangère # pour les questions de perfs # a voir en fonction des usage - id_module = DB.Column(DB.Integer) + id_module = DB.Column(DB.Integer, ForeignKey("gn_commons.t_modules.id_module")) visit_date_min = DB.Column(DB.DateTime) visit_date_max = DB.Column(DB.DateTime) @@ -102,15 +155,16 @@ class TBaseVisits(DB.Model): observers = DB.relationship( User, - secondary=corVisitObserver, - primaryjoin=(corVisitObserver.c.id_base_visit == id_base_visit), - secondaryjoin=(corVisitObserver.c.id_role == User.id_role), - foreign_keys=[corVisitObserver.c.id_base_visit, corVisitObserver.c.id_role], + secondary=cor_visit_observer, + primaryjoin=(cor_visit_observer.c.id_base_visit == id_base_visit), + secondaryjoin=(cor_visit_observer.c.id_role == User.id_role), + foreign_keys=[cor_visit_observer.c.id_base_visit, cor_visit_observer.c.id_role], ) + observers_txt = DB.Column(DB.Unicode) + dataset = relationship( TDatasets, - lazy="joined", primaryjoin=(TDatasets.id_dataset == id_dataset), foreign_keys=[id_dataset], ) @@ -128,7 +182,6 @@ class TBaseSites(DB.Model): id_base_site = DB.Column(DB.Integer, primary_key=True) id_inventor = DB.Column(DB.Integer, ForeignKey("utilisateurs.t_roles.id_role")) id_digitiser = DB.Column(DB.Integer, ForeignKey("utilisateurs.t_roles.id_role")) - id_nomenclature_type_site = DB.Column(DB.Integer) base_site_name = DB.Column(DB.Unicode) base_site_description = DB.Column(DB.Unicode) base_site_code = DB.Column(DB.Unicode) @@ -153,8 +206,23 @@ class TBaseSites(DB.Model): "TModules", lazy="select", enable_typechecks=False, - secondary=corSiteModule, - primaryjoin=(corSiteModule.c.id_base_site == id_base_site), - secondaryjoin=(corSiteModule.c.id_module == TModules.id_module), - foreign_keys=[corSiteModule.c.id_base_site, corSiteModule.c.id_module], + secondary=cor_site_module, + primaryjoin=(cor_site_module.c.id_base_site == id_base_site), + secondaryjoin=(cor_site_module.c.id_module == TModules.id_module), + foreign_keys=[cor_site_module.c.id_base_site, cor_site_module.c.id_module], + ) + + +@serializable +class TObservations(DB.Model): + __tablename__ = "t_observations" + __table_args__ = {"schema": "gn_monitoring"} + id_observation = DB.Column(DB.Integer, primary_key=True, nullable=False, unique=True) + id_base_visit = DB.Column(DB.ForeignKey("gn_monitoring.t_base_visits.id_base_visit")) + id_digitiser = DB.Column(DB.Integer, DB.ForeignKey("utilisateurs.t_roles.id_role")) + digitiser = DB.relationship( + User, primaryjoin=(User.id_role == id_digitiser), foreign_keys=[id_digitiser] ) + cd_nom = DB.Column(DB.Integer) + comments = DB.Column(DB.String) + uuid_observation = DB.Column(UUID(as_uuid=True), default=select(func.uuid_generate_v4())) diff --git a/backend/geonature/core/gn_monitoring/routes.py b/backend/geonature/core/gn_monitoring/routes.py index 3eaac25be8..245ed06047 100644 --- a/backend/geonature/core/gn_monitoring/routes.py +++ b/backend/geonature/core/gn_monitoring/routes.py @@ -1,6 +1,6 @@ from flask import Blueprint, request from geojson import FeatureCollection -from geonature.core.gn_monitoring.models import TBaseSites, corSiteArea, corSiteModule +from geonature.core.gn_monitoring.models import TBaseSites, cor_site_area, cor_site_module from geonature.utils.env import DB from ref_geo.models import LAreas from sqlalchemy import select @@ -79,16 +79,16 @@ def get_site_areas(id_site): params = request.args query = ( - select(corSiteArea, func.ST_Transform(LAreas.geom, 4326)) - .join(LAreas, LAreas.id_area == corSiteArea.c.id_area) - .where(corSiteArea.c.id_base_site == id_site) + select(cor_site_area, func.ST_Transform(LAreas.geom, 4326)) + .join(LAreas, LAreas.id_area == cor_site_area.c.id_area) + .where(cor_site_area.c.id_base_site == id_site) ) if "id_area_type" in params: query = query.where(LAreas.id_type == params["id_area_type"]) if "id_module" in params: - query = query.join(corSiteModule, corSiteModule.c.id_base_site == id_site).where( - corSiteModule.c.id_module == params["id_module"] + query = query.join(cor_site_module, cor_site_module.c.id_base_site == id_site).where( + cor_site_module.c.id_module == params["id_module"] ) data = DB.session.scalars(query).all() diff --git a/backend/geonature/migrations/versions/5a2c9c65129f_add_sensitivity_filter_export_synthese.py b/backend/geonature/migrations/versions/5a2c9c65129f_add_sensitivity_filter_export_synthese.py index e8ab60fd7a..018aa19125 100644 --- a/backend/geonature/migrations/versions/5a2c9c65129f_add_sensitivity_filter_export_synthese.py +++ b/backend/geonature/migrations/versions/5a2c9c65129f_add_sensitivity_filter_export_synthese.py @@ -1,7 +1,7 @@ """add sensitivity filter export synthese Revision ID: 5a2c9c65129f -Revises: 446e902a14e7 +Revises: d99a7c22cc3c Create Date: 2023-08-08 16:23:53.059110 """ diff --git a/backend/geonature/migrations/versions/6734d8f7eb2a_monitoring_add_id_digitizer_to_t_observations.py b/backend/geonature/migrations/versions/6734d8f7eb2a_monitoring_add_id_digitizer_to_t_observations.py new file mode 100644 index 0000000000..f17add3506 --- /dev/null +++ b/backend/geonature/migrations/versions/6734d8f7eb2a_monitoring_add_id_digitizer_to_t_observations.py @@ -0,0 +1,67 @@ +"""[monitoring] add id_digitizer to t_observations + +Revision ID: 6734d8f7eb2a +Revises: 9b88459c1298 +Create Date: 2024-01-16 15:50:30.308266 + +""" + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = "6734d8f7eb2a" +down_revision = "9b88459c1298" +branch_labels = None +depends_on = None + + +monitorings_schema = "gn_monitoring" +table = "t_observations" +column = "id_digitiser" + +foreign_schema = "utilisateurs" +table_foreign = "t_roles" +foreign_key = "id_role" + + +def upgrade(): + op.add_column( + table, + sa.Column( + column, + sa.Integer(), + sa.ForeignKey( + f"{foreign_schema}.{table_foreign}.{foreign_key}", + name=f"fk_{table}_{column}", + onupdate="CASCADE", + ), + ), + schema=monitorings_schema, + ) + op.execute( + """ + UPDATE gn_monitoring.t_observations o SET id_digitiser = tbv.id_digitiser + FROM gn_monitoring.t_base_visits AS tbv + WHERE tbv.id_base_visit = o.id_base_visit; + """ + ) + # Set not null constraint + op.alter_column( + table_name=table, + column_name=column, + existing_type=sa.Integer(), + nullable=False, + schema=monitorings_schema, + ) + + +def downgrade(): + statement = sa.text( + f""" + ALTER TABLE {monitorings_schema}.{table} DROP CONSTRAINT fk_{table}_{column}; + """ + ) + op.execute(statement) + op.drop_column(table, column, schema=monitorings_schema) diff --git a/backend/geonature/migrations/versions/8309591841f3_monitoring_add_observers_txt_column_t_base_visit.py b/backend/geonature/migrations/versions/8309591841f3_monitoring_add_observers_txt_column_t_base_visit.py new file mode 100644 index 0000000000..09c839ea76 --- /dev/null +++ b/backend/geonature/migrations/versions/8309591841f3_monitoring_add_observers_txt_column_t_base_visit.py @@ -0,0 +1,38 @@ +"""[monitoring] add_observers_txt_column_t_base_visit + +Revision ID: 8309591841f3 +Revises: 5a2c9c65129f +Create Date: 2023-10-06 11:07:43.532623 + +""" + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = "8309591841f3" +down_revision = "ebbe0f7ed866" +branch_labels = None +depends_on = None + + +monitorings_schema = "gn_monitoring" +table = "t_base_visits" +column = "observers_txt" + + +def upgrade(): + op.add_column( + table, + sa.Column( + column, + sa.Text(), + nullable=True, + ), + schema=monitorings_schema, + ) + + +def downgrade(): + op.drop_column(table, column, schema=monitorings_schema) diff --git a/backend/geonature/migrations/versions/9b88459c1298_monitoring_create_t_observations.py b/backend/geonature/migrations/versions/9b88459c1298_monitoring_create_t_observations.py new file mode 100644 index 0000000000..7e5b55d11b --- /dev/null +++ b/backend/geonature/migrations/versions/9b88459c1298_monitoring_create_t_observations.py @@ -0,0 +1,55 @@ +"""[monitoring] create t_observations + +Revision ID: 9b88459c1298 +Revises: a54bafb13ce8 +Create Date: 2024-01-16 15:41:13.331912 + +""" + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = "9b88459c1298" +down_revision = "a54bafb13ce8" +branch_labels = None +depends_on = None + + +def upgrade(): + op.execute( + """ + CREATE TABLE IF NOT EXISTS gn_monitoring.t_observations ( + id_observation SERIAL NOT NULL, + id_base_visit INTEGER NOT NULL, + cd_nom INTEGER NOT NULL, + comments TEXT, + uuid_observation UUID DEFAULT uuid_generate_v4() NOT NULL, + + + CONSTRAINT pk_t_observations PRIMARY KEY (id_observation), + CONSTRAINT fk_t_observations_id_base_visit FOREIGN KEY (id_base_visit) + REFERENCES gn_monitoring.t_base_visits (id_base_visit) MATCH SIMPLE + ON UPDATE CASCADE ON DELETE CASCADE + ); + """ + ) + op.execute( + """ + INSERT INTO gn_commons.bib_tables_location(table_desc, schema_name, table_name, pk_field, uuid_field_name) + VALUES + ('Table centralisant les observations réalisées lors d''une visite sur un site', 'gn_monitoring', 't_observations', 'id_observation', 'uuid_observation') + ON CONFLICT(schema_name, table_name) DO NOTHING; + """ + ) + + +def downgrade(): + op.execute( + """ + DELETE FROM gn_commons.bib_tables_location + WHERE schema_name = 'gn_monitoring' AND table_name = 't_observations'; + """ + ) + op.drop_table("t_observations", schema="gn_monitoring") diff --git a/backend/geonature/migrations/versions/a54bafb13ce8_monitoring_create_cor_module_type.py b/backend/geonature/migrations/versions/a54bafb13ce8_monitoring_create_cor_module_type.py new file mode 100644 index 0000000000..3c867d9526 --- /dev/null +++ b/backend/geonature/migrations/versions/a54bafb13ce8_monitoring_create_cor_module_type.py @@ -0,0 +1,64 @@ +""" [monitoring] create_cor_module_type + +Revision ID: a54bafb13ce8 +Revises: ce54ba49ce5c +Create Date: 2022-12-06 16:18:24.512562 + +""" + +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = "a54bafb13ce8" +down_revision = "ce54ba49ce5c" +branch_labels = None +depends_on = None + +monitorings_schema = "gn_monitoring" +referent_schema = "gn_commons" + + +def upgrade(): + op.create_table( + "cor_module_type", + sa.Column( + "id_type_site", + sa.Integer(), + sa.ForeignKey( + f"{monitorings_schema}.bib_type_site.id_nomenclature_type_site", + name="fk_cor_module_type_id_nomenclature", + ondelete="CASCADE", + onupdate="CASCADE", + ), + nullable=False, + ), + sa.Column( + "id_module", + sa.Integer(), + sa.ForeignKey( + f"{referent_schema}.t_modules.id_module", + name="fk_cor_module_type_id_module", + ondelete="CASCADE", + onupdate="CASCADE", + ), + nullable=False, + ), + sa.PrimaryKeyConstraint("id_type_site", "id_module", name="pk_cor_module_type"), + schema=monitorings_schema, + ) + + # Insertion des données a partir de cor_site_module + op.execute( + """ + INSERT INTO gn_monitoring.cor_module_type (id_module, id_type_site ) + SELECT DISTINCT csm.id_module, cts.id_type_site + FROM gn_monitoring.cor_site_module AS csm + JOIN gn_monitoring.cor_site_type AS cts + ON Cts.id_base_site = csm.id_base_site ; + """ + ) + + +def downgrade(): + op.drop_table("cor_module_type", schema=monitorings_schema) diff --git a/backend/geonature/migrations/versions/b53bafb13ce8_monitoring_create_bib_type_site.py b/backend/geonature/migrations/versions/b53bafb13ce8_monitoring_create_bib_type_site.py new file mode 100644 index 0000000000..0c66d8ece2 --- /dev/null +++ b/backend/geonature/migrations/versions/b53bafb13ce8_monitoring_create_bib_type_site.py @@ -0,0 +1,77 @@ +"""[monitoring] create_bib_type_site + +Revision ID: b53bafb13ce8 +Revises: 8309591841f3 +Create Date: 2022-12-06 16:18:24.512562 + +""" + +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = "b53bafb13ce8" +down_revision = "8309591841f3" +branch_labels = None +depends_on = None + +monitorings_schema = "gn_monitoring" +nomenclature_schema = "ref_nomenclatures" + + +def upgrade(): + op.create_table( + "bib_type_site", + sa.Column( + "id_nomenclature_type_site", + sa.Integer(), + sa.ForeignKey( + f"{nomenclature_schema}.t_nomenclatures.id_nomenclature", + name="fk_t_nomenclatures_id_nomenclature_type_site", + ), + nullable=False, + unique=True, + ), + sa.PrimaryKeyConstraint("id_nomenclature_type_site"), + sa.Column("config", sa.JSON(), nullable=True), + schema=monitorings_schema, + ) + + # FIXME: if sqlalchemy >= 1.4.32, it should work with postgresql_not_valid=True: cleaner + # op.create_check_constraint( + # "ck_bib_type_site_id_nomenclature_type_site", + # "bib_type_site", + # f"{nomenclature_schema}.check_nomenclature_type_by_mnemonique(id_nomenclature_type_site,'TYPE_SITE')", + # schema=monitorings_schema, + # postgresql_not_valid=True + # ) + statement = sa.text( + f""" + ALTER TABLE {monitorings_schema}.bib_type_site + ADD + CONSTRAINT ck_bib_type_site_id_nomenclature_type_site CHECK ( + {nomenclature_schema}.check_nomenclature_type_by_mnemonique( + id_nomenclature_type_site, 'TYPE_SITE' :: character varying + ) + ) NOT VALID + """ + ) + op.execute(statement) + op.create_table_comment( + "bib_type_site", + "Table de définition des champs associés aux types de sites", + schema=monitorings_schema, + ) + + # Récupération de la liste des types de site avec ceux déja présents dans la table t_base_site + op.execute( + """ + INSERT INTO gn_monitoring.bib_type_site AS bts (id_nomenclature_type_site) + SELECT DISTINCT id_nomenclature_type_site + FROM gn_monitoring.t_base_sites AS tbs ; + """ + ) + + +def downgrade(): + op.drop_table("bib_type_site", schema=monitorings_schema) diff --git a/backend/geonature/migrations/versions/ce54ba49ce5c_monitoring_create_cor_site_type.py b/backend/geonature/migrations/versions/ce54ba49ce5c_monitoring_create_cor_site_type.py new file mode 100644 index 0000000000..d1a4296713 --- /dev/null +++ b/backend/geonature/migrations/versions/ce54ba49ce5c_monitoring_create_cor_site_type.py @@ -0,0 +1,130 @@ +"""[monitoring] create_cor_site_type + +Revision ID: ce54ba49ce5c +Revises: b53bafb13ce8 +Create Date: 2022-12-06 16:18:24.512562 + +""" + +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = "ce54ba49ce5c" +down_revision = "b53bafb13ce8" +branch_labels = None +depends_on = None + +monitorings_schema = "gn_monitoring" + + +def upgrade(): + op.create_table( + "cor_site_type", + sa.Column( + "id_type_site", + sa.Integer(), + sa.ForeignKey( + f"{monitorings_schema}.bib_type_site.id_nomenclature_type_site", + name="fk_cor_site_type_id_nomenclature_type_site", + ondelete="CASCADE", + onupdate="CASCADE", + ), + nullable=False, + ), + sa.Column( + "id_base_site", + sa.Integer(), + sa.ForeignKey( + f"{monitorings_schema}.t_base_sites.id_base_site", + name="fk_cor_site_type_id_base_site", + ondelete="CASCADE", + onupdate="CASCADE", + ), + nullable=False, + ), + sa.PrimaryKeyConstraint("id_type_site", "id_base_site", name="pk_cor_site_type"), + schema=monitorings_schema, + ) + op.create_table_comment( + "cor_site_type", + "Table d'association entre les sites et les types de sites", + schema=monitorings_schema, + ) + + op.execute( + """ + INSERT INTO gn_monitoring.cor_site_type + SELECT id_nomenclature_type_site , id_base_site d + FROM gn_monitoring.t_base_sites ; + """ + ) + + op.execute( + """ + ALTER TABLE gn_monitoring.t_base_sites + DROP CONSTRAINT check_t_base_sites_type_site; + """ + ) + op.execute( + """ + DROP INDEX gn_monitoring.idx_t_base_sites_type_site; + """ + ) + op.drop_column( + table_name="t_base_sites", + column_name="id_nomenclature_type_site", + schema=monitorings_schema, + ) + + +def downgrade(): + op.add_column( + table_name="t_base_sites", + column=sa.Column( + "id_nomenclature_type_site", + sa.Integer(), + sa.ForeignKey( + "ref_nomenclatures.t_nomenclatures.id_nomenclature", + name="fk_t_base_sites_type_site", + onupdate="CASCADE", + ), + ), + schema=monitorings_schema, + ) + + op.execute( + """ + WITH ts AS ( + SELECT DISTINCT ON (id_base_site) id_base_site, id_type_site + FROM gn_monitoring.cor_site_type AS cts + ORDER BY id_base_site, id_type_site + ) + UPDATE gn_monitoring.t_base_sites tbs + SET id_nomenclature_type_site = id_type_site + FROM ts + WHERE ts.id_base_site = tbs.id_base_site; + """ + ) + + op.execute( + """ + ALTER TABLE gn_monitoring.t_base_sites + ADD CONSTRAINT check_t_base_sites_type_site + CHECK (ref_nomenclatures.check_nomenclature_type_by_mnemonique(id_nomenclature_type_site,'TYPE_SITE')) + NOT VALID; + """ + ) + + op.execute( + """ + CREATE INDEX idx_t_base_sites_type_site ON gn_monitoring.t_base_sites USING btree (id_nomenclature_type_site); + """ + ) + op.execute( + """ + ALTER TABLE gn_monitoring.t_base_sites ALTER COLUMN id_nomenclature_type_site SET NOT NULL; + """ + ) + + op.drop_table("cor_site_type", schema=monitorings_schema) diff --git a/frontend/src/app/GN2CommonModule/form/datalist/datalist.component.ts b/frontend/src/app/GN2CommonModule/form/datalist/datalist.component.ts index 317a8e2cb3..0a2c830a29 100644 --- a/frontend/src/app/GN2CommonModule/form/datalist/datalist.component.ts +++ b/frontend/src/app/GN2CommonModule/form/datalist/datalist.component.ts @@ -1,13 +1,4 @@ -import { filter } from 'rxjs/operators'; -import { - Component, - OnInit, - Input, - OnChanges, - DoCheck, - IterableDiffers, - IterableDiffer, -} from '@angular/core'; +import { Component, OnInit, Input } from '@angular/core'; import { DataFormService } from '../data-form.service'; import { GenericFormComponent } from '@geonature_common/form/genericForm.component'; import { CommonService } from '../../service/common.service'; @@ -37,6 +28,7 @@ export class DatalistComponent extends GenericFormComponent implements OnInit { @Input() filters = {}; // help @Input() default; + @Input() nullDefault; @Input() dataPath: string; // pour atteindre la liste si elle n'est pas à la racine de la réponse de l'api. // si on a 'data/liste' on mettra dataPath='data' @@ -70,7 +62,15 @@ export class DatalistComponent extends GenericFormComponent implements OnInit { getFilteredValues() { let values = this.values || []; - + // if(this.nullDefault){ + // values.push() + // } + if (this.nullDefault && !this.required) { + let obj = {}; + obj[this.keyValue] = null; + obj[this.keyLabel] = '-- Aucun --'; + values.unshift(obj); + } values = values // filter search .filter( @@ -133,20 +133,34 @@ export class DatalistComponent extends GenericFormComponent implements OnInit { this.filteredValues.length === 1 && !(this.parentFormControl.value && this.parentFormControl.value.length) ) { - const val = this.values[0][this.keyValue]; - this.parentFormControl.patchValue(this.multiple ? [val] : val); + const val = this.nullDefault ? null : this.values[0][this.keyValue]; + this.parentFormControl.patchValue(this.multiple && !this.nullDefault ? [val] : val); } + // valeur par défaut (depuis input value) - if (!this.parentFormControl.value && this.default) { + if ( + (!this.parentFormControl.value || + (Array.isArray(this.parentFormControl.value) && + this.parentFormControl.value.length == 0)) && + this.default + ) { const value = this.multiple ? this.default : [this.default]; - const res = value.map((val) => - typeof val === 'object' - ? (this.filteredValues.find((v) => - Object.keys(val).every((key) => v[key] === val[key]) - ) || {})[this.keyValue] - : val - ); - this.parentFormControl.patchValue(this.multiple ? res : res[0]); + // check if the default value is in the provided values + const valuesID = this.values.map((el) => el[this.keyValue]); + const defaultValuesID = value.map((el) => el[this.keyValue]); + const defaultValueIsInValues = valuesID.some((el) => defaultValuesID.includes(el)); + + // patch value only if default value is in values + if (defaultValueIsInValues) { + const res = value.map((val) => + typeof val === 'object' + ? (this.filteredValues.find((v) => + Object.keys(val).every((key) => v[key] === val[key]) + ) || {})[this.keyValue] + : val + ); + this.parentFormControl.patchValue(this.multiple ? res : res[0]); + } } this.parentFormControl.markAsTouched(); } diff --git a/frontend/src/app/GN2CommonModule/form/dynamic-form/dynamic-form.component.html b/frontend/src/app/GN2CommonModule/form/dynamic-form/dynamic-form.component.html index 88d1ec825e..dba185bd67 100644 --- a/frontend/src/app/GN2CommonModule/form/dynamic-form/dynamic-form.component.html +++ b/frontend/src/app/GN2CommonModule/form/dynamic-form/dynamic-form.component.html @@ -311,8 +311,15 @@ [idMenu]="formDefComp['id_menu']" [idList]="formDefComp['id_list']" [codeList]="formDefComp['code_list']" + [multiSelect]="formDefComp['multi_select']" > + + {{ formDefComp['help'] }} diff --git a/frontend/src/app/GN2CommonModule/form/observers/observers.component.ts b/frontend/src/app/GN2CommonModule/form/observers/observers.component.ts index 66e62bd5d6..9d02c18025 100644 --- a/frontend/src/app/GN2CommonModule/form/observers/observers.component.ts +++ b/frontend/src/app/GN2CommonModule/form/observers/observers.component.ts @@ -43,7 +43,7 @@ export class ObserversComponent extends GenericFormComponent { ngOnInit() { super.ngOnInit(); this.bindValue = this.bindAllItem ? null : this.bindValue; - this.multiSelect = this.multiSelect || true; + this.multiSelect = this.multiSelect ? true : this.multiSelect; // uniformise as IdList the id of list // retrocompat: keep idMenu if (this.idList) {