From 093ca41b277f462f8c09361073d40a33ed88f252 Mon Sep 17 00:00:00 2001 From: Maxime Vergez <85738261+mvergez@users.noreply.github.com> Date: Fri, 14 Apr 2023 14:19:10 +0200 Subject: [PATCH] Feat/dynamic form/site (#42) * refactor: object.service with observable obj Change the objectType string to objectType obj in order to subscribe to multilple properties link to this object Reviewed-by: andriacap [Refs_ticket]: #40 * feat: adapt service to get config json Get fieldsName and fieldsLabel for display properties (properties component) Add logic to setItem in LocalStorage to keepLast Value of observable on reload page TODO: - [ ] see if Localstorage is really necessary with the configService used inside api-geom.service ) - [ ] adapt monitoring-form-g.component with the new service Reviewed-by: andriacap [Refs ticket]: #4 * feat: column datatable from config json Add logic into sitegroups service in order to use config json to diplay column datatable (called "display_list") Review-by: andriac [Refs ticket]: #4 * feat: adjust backend to load config json Adjust backend code to use existing code in order to load config from file json and by starting with "sites_group" Fix Media load and upload for site_group TODO: - [ ] check if config should be find from file or backend - [ ] Optimize logic backend (use generic model with class method ?) Reviewed-by: andriacap [Refs ticket]: #4 * feat: add button multiselect with filter on backend filter with params backend (new route -> see if it's possible to change that) Add button multiselect above form type site TODO: - improve Input / condition of use case of btn multiselect Reviewed-by: andriac * feat: btn multiselect option -Add @Input fn , placeholder, title, paramsToFilt -Remove empty option -prevent adding from keyboard input or not including in list -Store config json into object Reviewed-by: @andriac [Refs-ticket]: #4 * refactor: change form-service and object-service refactor form-service add observable into object-service (WIP: futur use for refresh page ?) Rieviewed-by: andriac [Refs_ticket]: #40 * refactor: test refresh page and comportment obs refresh page seems to works with localstorage of different obj in object_service Reviewed-by: andriac * feat: dynamic form - Add: - pass config json to form.component-g.ts - add config json to this.obj and refresh form into form.component-g.ts - add css for form component to deal when long form selected -fix : - refresh page form component (this._configService.init is necessary ...) - comportment different between add or edit into form component and form service Reviewed-by: andriac [Refs_ticket]: #4 * feat: dynamic form - Correction PR Remove unused console.log Rxjs : use concatMap to avoid subscribe inside subscribe Apply: prettier and sort prettier for import ts file Reviewed-by: @andriac [Refs_PR]: #42 * feat: dynamic create site - Add change current-object when click "Add " from datatable component - api-geom.service: change the way to init the api-geom - WIP: two subscribes in one .. (the subscription is call only once ..) - WIP : get config json from backend Reviewed-by: andriac * feat: add relationship id into sendData form site Add type_site and id_site_group to the form site Reviewed-by: andriac [Refs_ticket]: #5 et #6 * feat(back): add custom config when post site Change backend files in order to choose specific config when site is created. Reviewed-by: andriac [Refs_ticket]: #5 , #6 * fix: problem of type object when loading form Add endPoint and objectType to the observable using by the formservice in order to use _apiGeomService with good context (endPoint) [Refs_ticket]: #5 et #6 * fix: todo comments about refactoring code Add todo comment in order to don't forget what is to improve inside the code * chore(front): add comment and remove console.log * chore(api): put back old formatting * chore(api): remove useless comment * refactor(api): move and rename create_update fct * fix: put back inventor/digitiser & fix typo * chore: remove useless files Since columns are now loaded from json, they are not needed anymore in separate typescript files * chore: remove definition from sites_group.json * fix: column problem on sites * chore: remove useless comment * refactor(front): remove comment and use rxjs * chore(front): remove useless file Since class BtnMultiSelectChipClass is not used anymore * chore(front): remove useless comments/imports * style(front): applied prettier * chore(front): remove useless code * refactor(front): regroup types into an interface * style(front): applied prettier * refactor(front): inherit config-json from config --------- Co-authored-by: Andria Capai --- .../config/generic/site.json | 41 +-- .../config/generic/sites_group.json | 5 + .../config/repositories.py | 47 +-- .../gn_module_monitoring/monitoring/base.py | 2 +- .../monitoring/definitions.py | 25 +- .../monitoring/objects.py | 13 +- .../monitoring/schemas.py | 2 +- .../monitoring/serializer.py | 30 +- backend/gn_module_monitoring/routes/site.py | 41 ++- .../routes/sites_groups.py | 39 ++- backend/gn_module_monitoring/utils/routes.py | 46 ++- frontend/app/class/monitoring-site.ts | 13 - frontend/app/class/monitoring-sites-group.ts | 12 - .../btn-select/btn-select.component.css | 5 + .../btn-select/btn-select.component.html | 31 ++ .../btn-select/btn-select.component.ts | 123 ++++++++ .../monitoring-datatable-g.component.css | 37 ++- .../monitoring-datatable-g.component.html | 28 +- .../monitoring-datatable-g.component.spec.ts | 7 +- .../monitoring-datatable-g.component.ts | 66 ++-- .../monitoring-form.component-g.css | 21 +- .../monitoring-form.component-g.html | 59 ++-- .../monitoring-form.component-g.spec.ts | 7 +- .../monitoring-form.component-g.ts | 289 +++++++++--------- .../monitoring-properties-g.component.html | 50 ++- .../monitoring-properties-g.component.ts | 42 +-- .../monitoring-sites-create.component.css | 0 .../monitoring-sites-create.component.html | 13 + .../monitoring-sites-create.component.ts | 82 +++++ .../monitoring-sites.component.html | 3 +- .../monitoring-sites.component.ts | 17 +- ...monitoring-sitesgroups-create.component.ts | 12 +- .../monitoring-sitesgroups.component.ts | 22 +- frontend/app/enum/endpoints.ts | 5 + frontend/app/gnModule.module.ts | 27 +- frontend/app/interfaces/geom.ts | 33 +- frontend/app/interfaces/objObs.ts | 24 ++ frontend/app/services/api-geom.service.ts | 239 +++++++++++---- frontend/app/services/config-json.service.ts | 60 ++++ frontend/app/services/config.service.ts | 28 +- frontend/app/services/data-table.service.ts | 11 +- frontend/app/services/edit-object.service.ts | 58 ---- frontend/app/services/form.service.ts | 105 +++++++ frontend/app/services/object.service.ts | 52 +++- frontend/app/utils/utils.ts | 8 + 45 files changed, 1265 insertions(+), 615 deletions(-) delete mode 100644 frontend/app/class/monitoring-site.ts delete mode 100644 frontend/app/class/monitoring-sites-group.ts create mode 100644 frontend/app/components/btn-select/btn-select.component.css create mode 100644 frontend/app/components/btn-select/btn-select.component.html create mode 100644 frontend/app/components/btn-select/btn-select.component.ts create mode 100644 frontend/app/components/monitoring-sites-create/monitoring-sites-create.component.css create mode 100644 frontend/app/components/monitoring-sites-create/monitoring-sites-create.component.html create mode 100644 frontend/app/components/monitoring-sites-create/monitoring-sites-create.component.ts create mode 100644 frontend/app/enum/endpoints.ts create mode 100644 frontend/app/interfaces/objObs.ts create mode 100644 frontend/app/services/config-json.service.ts delete mode 100644 frontend/app/services/edit-object.service.ts create mode 100644 frontend/app/services/form.service.ts diff --git a/backend/gn_module_monitoring/config/generic/site.json b/backend/gn_module_monitoring/config/generic/site.json index 2264755b2..65fe26895 100644 --- a/backend/gn_module_monitoring/config/generic/site.json +++ b/backend/gn_module_monitoring/config/generic/site.json @@ -12,7 +12,6 @@ "base_site_name", "base_site_code", "base_site_description", - "id_nomenclature_type_site", "id_inventor", "first_use_date", "last_visit", @@ -36,11 +35,6 @@ "attribut_label": "Id site", "hidden": true }, - "id_module": { - "type_widget": "text", - "attribut_label": "ID Module", - "hidden": true - }, "base_site_code": { "type_widget": "text", "attribut_label": "Code", @@ -55,29 +49,6 @@ "type_widget": "textarea", "attribut_label": "Description" }, - - "id_sites_group": { - "type_widget": "datalist", - "attribut_label": "Groupe de sites", - "type_util": "sites_group", - "keyValue": "id_sites_group", - "keyLabel": "sites_group_name", - "api": "__MONITORINGS_PATH/list/__MODULE.MODULE_CODE/sites_group?id_module=__MODULE.ID_MODULE&fields=id_sites_group&fields=sites_group_name", - "application": "GeoNature", - "required": false, - "hidden": true - }, - "id_nomenclature_type_site": { - "type_widget": "datalist", - "attribut_label": "Type site", - "api": "nomenclatures/nomenclature/TYPE_SITE", - "application": "GeoNature", - "keyValue": "id_nomenclature", - "keyLabel": "label_fr", - "data_path": "values", - "type_util": "nomenclature", - "required": true - }, "id_inventor": { "type_widget": "datalist", "attribut_label": "Descripteur", @@ -122,6 +93,18 @@ "altitude_max": { "type_widget": "integer", "attribut_label": "Altitude (max)" + }, + "id_sites_group": { + "type_widget": "integer", + "attribut_label": "ID Sites Groups", + "hidden": true, + "schema_dot_table": "gn_monitoring.t_base_sites" + }, + "types_site": { + "type_widget": "datalist", + "attribut_label": "ID Type sites", + "hidden": true, + "schema_dot_table": "gn_monitoring.t_base_sites" } } } diff --git a/backend/gn_module_monitoring/config/generic/sites_group.json b/backend/gn_module_monitoring/config/generic/sites_group.json index 8512fdb0d..23549f389 100644 --- a/backend/gn_module_monitoring/config/generic/sites_group.json +++ b/backend/gn_module_monitoring/config/generic/sites_group.json @@ -44,6 +44,11 @@ }, "nb_visits": { "attribut_label": "Nombre de visites" + }, + "medias": { + "type_widget": "medias", + "attribut_label": "Médias", + "schema_dot_table": "gn_monitoring.t_sites_groups" } } } diff --git a/backend/gn_module_monitoring/config/repositories.py b/backend/gn_module_monitoring/config/repositories.py index b7526848d..8886ff3ac 100644 --- a/backend/gn_module_monitoring/config/repositories.py +++ b/backend/gn_module_monitoring/config/repositories.py @@ -25,10 +25,10 @@ config_cache_name = "MONITORINGS_CONFIG" -def get_config_objects(module_code, config, tree=None, parent_type=None): - """ - recupere la config de chaque object present dans tree pour le module - """ +def get_config_objects(module_code, config, tree=None, parent_type=None, customSpecConfig=None): + ''' + recupere la config de chaque object present dans tree pour le module + ''' if not tree: # initial tree tree = config["tree"] @@ -36,7 +36,10 @@ def get_config_objects(module_code, config, tree=None, parent_type=None): for object_type in tree: # config object if not object_type in config: - config[object_type] = config_object_from_files(module_code, object_type) + if (object_type=="site"): + config[object_type] = config_object_from_files(module_code, object_type,customSpecConfig) + else: + config[object_type] = config_object_from_files(module_code, object_type) # tree children_types = tree[object_type] and list(tree[object_type].keys()) or [] @@ -77,25 +80,25 @@ def get_config_objects(module_code, config, tree=None, parent_type=None): # recursif if tree[object_type]: - get_config_objects(module_code, config, tree[object_type], object_type) + get_config_objects(module_code, config, tree[object_type], object_type,customSpecConfig) -def config_object_from_files(module_code, object_type): - """ - recupere la configuration d'un object de type pour le module - """ - generic_config_object = json_config_from_file("generic", object_type) - specific_config_object = ( - {} if module_code == "generic" else json_config_from_file(module_code, object_type) - ) +def config_object_from_files(module_code, object_type,custom=None): + ''' + recupere la configuration d'un object de type pour le module + ''' + generic_config_object = json_config_from_file('generic', object_type) + specific_config_object = {} if module_code == 'generic' else json_config_from_file(module_code, object_type) + if module_code == 'generic' and object_type == 'site' and custom is not None: + specific_config_object = custom config_object = generic_config_object config_object.update(specific_config_object) return config_object -def get_config(module_code=None, force=False): +def get_config(module_code=None, force=False,customSpecConfig=None): """ recupere la configuration pour le module monitoring @@ -133,8 +136,8 @@ def get_config(module_code=None, force=False): # if config and config.get('last_modif', 0) >= last_modif: # return config - config = config_from_files("config", module_code) - get_config_objects(module_code, config) + config = config_from_files('config', module_code) + get_config_objects(module_code, config,customSpecConfig=customSpecConfig) # customize config if module: @@ -243,3 +246,13 @@ def config_schema(module_code, object_type, type_schema="all"): def get_config_frontend(module_code=None, force=True): config = dict(get_config(module_code, force)) return config + + + +# def get_config_from_backend(module_code=None, force=False): + +# module_code = 'generic' +# #TODO: voir la sortie de cette fonction +# config = config_from_backend('config', module_code) +# #TODO: voir également à quoi sert cette fonction +# get_config_objects(module_code, config) diff --git a/backend/gn_module_monitoring/monitoring/base.py b/backend/gn_module_monitoring/monitoring/base.py index ab331e005..e4a263c87 100644 --- a/backend/gn_module_monitoring/monitoring/base.py +++ b/backend/gn_module_monitoring/monitoring/base.py @@ -54,7 +54,7 @@ def MonitoringModel(self, object_type): monitoring_definitions = MonitoringDefinitions() - +monitoring_g_definitions = MonitoringDefinitions() class MonitoringObjectBase: _object_type = None diff --git a/backend/gn_module_monitoring/monitoring/definitions.py b/backend/gn_module_monitoring/monitoring/definitions.py index da018295d..a642846b5 100644 --- a/backend/gn_module_monitoring/monitoring/definitions.py +++ b/backend/gn_module_monitoring/monitoring/definitions.py @@ -8,7 +8,7 @@ ) from .objects import MonitoringModule, MonitoringSite -from .base import monitoring_definitions +from .base import monitoring_definitions, monitoring_g_definitions from .repositories import MonitoringObject from .geom import MonitoringObjectGeom @@ -20,12 +20,12 @@ """ MonitoringModels_dict = { - "module": TMonitoringModules, - "site": TMonitoringSites, - "visit": TMonitoringVisits, - "observation": TMonitoringObservations, - "observation_detail": TMonitoringObservationDetails, - "sites_group": TMonitoringSitesGroups, + 'module': TMonitoringModules, + 'site': TMonitoringSites, + 'visit': TMonitoringVisits, + 'observation': TMonitoringObservations, + 'observation_detail': TMonitoringObservationDetails, + 'sites_group': TMonitoringSitesGroups, } MonitoringObjects_dict = { @@ -56,3 +56,14 @@ monitoring_definitions.set(MonitoringObjects_dict, MonitoringModels_dict) + +# #####################"" +MonitoringModelsG_dict = { + x: MonitoringModels_dict[x] for x in MonitoringModels_dict if x not in "module" +} + +MonitoringObjectsG_dict = { + x: MonitoringObjects_dict[x] for x in MonitoringObjects_dict if x not in "module" +} + +monitoring_g_definitions.set(MonitoringObjectsG_dict, MonitoringModelsG_dict) diff --git a/backend/gn_module_monitoring/monitoring/objects.py b/backend/gn_module_monitoring/monitoring/objects.py index edd51870e..4b49f4932 100644 --- a/backend/gn_module_monitoring/monitoring/objects.py +++ b/backend/gn_module_monitoring/monitoring/objects.py @@ -26,9 +26,12 @@ class MonitoringSite(MonitoringObjectGeom): """ def preprocess_data(self, data): - module_ids = [module.id_module for module in self._model.modules] - id_module = int(data["id_module"]) - if id_module not in module_ids: - module_ids.append(id_module) + 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["modules"] = module_ids + data['types_site'] = type_site_ids diff --git a/backend/gn_module_monitoring/monitoring/schemas.py b/backend/gn_module_monitoring/monitoring/schemas.py index 1816d677e..fcbbc76d3 100644 --- a/backend/gn_module_monitoring/monitoring/schemas.py +++ b/backend/gn_module_monitoring/monitoring/schemas.py @@ -32,7 +32,7 @@ class Meta: exclude = ("geom_geojson",) load_instance = True - medias = MA.Nested(MediaSchema) + medias = MA.Nested(MediaSchema,many=True) pk = fields.Method("set_pk",dump_only=True) geometry = fields.Method("serialize_geojson", dump_only=True) diff --git a/backend/gn_module_monitoring/monitoring/serializer.py b/backend/gn_module_monitoring/monitoring/serializer.py index 75bb82758..c474846a0 100644 --- a/backend/gn_module_monitoring/monitoring/serializer.py +++ b/backend/gn_module_monitoring/monitoring/serializer.py @@ -4,7 +4,7 @@ import datetime import uuid from flask import current_app -from .base import MonitoringObjectBase, monitoring_definitions +from .base import MonitoringObjectBase, monitoring_definitions, monitoring_g_definitions from ..utils.utils import to_int from ..routes.data_utils import id_field_name_dict from geonature.utils.env import DB @@ -12,15 +12,24 @@ class MonitoringObjectSerializer(MonitoringObjectBase): + + def get_parent(self): + monitoring_def = monitoring_g_definitions if self._module_code == "generic" else monitoring_definitions parent_type = self.parent_type() if not parent_type: return if not self._parent: - self._parent = monitoring_definitions.monitoring_object_instance( - self._module_code, parent_type, self.id_parent() - ).get() + self._parent = ( + monitoring_def + .monitoring_object_instance( + self._module_code, + parent_type, + self.id_parent() + ) + .get() + ) return self._parent @@ -57,7 +66,8 @@ def unflatten_specific_properties(self, properties): properties["data"] = data def serialize_children(self, depth): - children_types = self.config_param("children_types") + monitoring_def = monitoring_g_definitions if self._module_code == "generic" else monitoring_definitions + children_types = self.config_param('children_types') if not children_types: return @@ -74,8 +84,9 @@ def serialize_children(self, depth): children_of_type = [] for child_model in getattr(self._model, relation_name): - child = monitoring_definitions.monitoring_object_instance( - self._module_code, children_type, model=child_model + child = ( + monitoring_def + .monitoring_object_instance(self._module_code, children_type, model=child_model) ) children_of_type.append(child.serialize(depth)) @@ -169,7 +180,10 @@ def populate(self, post_data): self.preprocess_data(properties) # ajout des données en base - if hasattr(self._model, "from_geofeature"): + if hasattr(self._model, 'from_geofeature'): + for key in list(post_data): + if key not in ("properties","geometry","type"): + post_data.pop(key) self._model.from_geofeature(post_data, True) else: self._model.from_dict(properties, True) diff --git a/backend/gn_module_monitoring/routes/site.py b/backend/gn_module_monitoring/routes/site.py index d4ee778aa..1bc413785 100644 --- a/backend/gn_module_monitoring/routes/site.py +++ b/backend/gn_module_monitoring/routes/site.py @@ -3,9 +3,11 @@ from werkzeug.datastructures import MultiDict from gn_module_monitoring.blueprint import blueprint -from gn_module_monitoring.monitoring.models import BibTypeSite, TMonitoringSites +from gn_module_monitoring.config.repositories import get_config +from gn_module_monitoring.monitoring.models import BibTypeSite, TMonitoringSites, TNomenclatures from gn_module_monitoring.monitoring.schemas import BibTypeSiteSchema, MonitoringSitesSchema from gn_module_monitoring.utils.routes import ( + create_or_update_object_api_sites_sites_group, filter_params, geojson_query, get_limit_page, @@ -34,6 +36,30 @@ def get_types_site(): ) +@blueprint.route("/sites/types/label", methods=["GET"]) +def get_types_site_by_label(): + params = MultiDict(request.args) + limit, page = get_limit_page(params=params) + sort_label, sort_dir = get_sort( + params=params, default_sort="label_fr", default_direction="desc" + ) + joinquery = BibTypeSite.query.join(BibTypeSite.nomenclature).filter( + TNomenclatures.label_fr.ilike(f"%{params['label_fr']}%") + ) + if sort_dir == "asc": + joinquery = joinquery.order_by(TNomenclatures.label_fr.asc()) + + # See if there are not too much labels since they are used + # in select in the frontend side. And an infinite select is not + # implemented + return paginate( + query=joinquery, + schema=BibTypeSiteSchema, + limit=limit, + page=page, + ) + + @blueprint.route("/sites/types/", methods=["GET"]) def get_type_site_by_id(id_type_site): res = BibTypeSite.find_by_id(id_type_site) @@ -83,3 +109,16 @@ def get_all_site_geometries(): def get_module_sites(module_code: str): # TODO: load with site_categories.json API return jsonify({"module_code": module_code}) + + +@blueprint.route("/sites", methods=["POST"]) +def post_sites(): + 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), 201 diff --git a/backend/gn_module_monitoring/routes/sites_groups.py b/backend/gn_module_monitoring/routes/sites_groups.py index 8ebb8d3fd..28888ef30 100644 --- a/backend/gn_module_monitoring/routes/sites_groups.py +++ b/backend/gn_module_monitoring/routes/sites_groups.py @@ -5,9 +5,14 @@ from werkzeug.datastructures import MultiDict from gn_module_monitoring.blueprint import blueprint +from gn_module_monitoring.config.repositories import get_config +from gn_module_monitoring.modules.repositories import get_module +from gn_module_monitoring.monitoring.definitions import monitoring_g_definitions from gn_module_monitoring.monitoring.models import TMonitoringSites, TMonitoringSitesGroups from gn_module_monitoring.monitoring.schemas import MonitoringSitesGroupsSchema +from gn_module_monitoring.utils.errors.errorHandler import InvalidUsage from gn_module_monitoring.utils.routes import ( + create_or_update_object_api_sites_sites_group, filter_params, geojson_query, get_limit_page, @@ -15,7 +20,7 @@ paginate, sort, ) -from gn_module_monitoring.utils.errors.errorHandler import InvalidUsage +from gn_module_monitoring.utils.utils import to_int @blueprint.route("/sites_groups", methods=["GET"]) @@ -66,18 +71,12 @@ def get_sites_group_geometries(): @blueprint.route("/sites_groups/", methods=["PATCH"]) def patch(_id): - item_schema = MonitoringSitesGroupsSchema() - item_json = request.get_json() - item = TMonitoringSitesGroups.find_by_id(_id) - fields = TMonitoringSitesGroups.attribute_names() - for field in item_json: - if field in fields: - setattr(item, field, item_json[field]) - item_schema.load(item_json) - db.session.add(item) - - db.session.commit() - return item_schema.dump(item), 201 + # ###############################"" + # FROM route/monitorings + module_code = "generic" + object_type = "sites_group" + get_config(module_code, force=True) + return create_or_update_object_api_sites_sites_group(module_code, object_type, _id), 201 @blueprint.route("/sites_groups/", methods=["DELETE"]) @@ -91,16 +90,16 @@ def delete(_id): @blueprint.route("/sites_groups", methods=["POST"]) def post(): - item_schema = MonitoringSitesGroupsSchema() - item_json = request.get_json() - item = item_schema.load(item_json) - db.session.add(item) - db.session.commit() - return item_schema.dump(item), 201 + module_code = "generic" + object_type = "sites_group" + get_config(module_code, force=True) + return create_or_update_object_api_sites_sites_group(module_code, object_type), 201 @blueprint.errorhandler(ValidationError) def handle_validation_error(error): return InvalidUsage( - "Fields cannot be validated, message : {}".format(error.messages), status_code=422, payload=error.data + "Fields cannot be validated, message : {}".format(error.messages), + status_code=422, + payload=error.data, ).to_dict() diff --git a/backend/gn_module_monitoring/utils/routes.py b/backend/gn_module_monitoring/utils/routes.py index 2871d86dd..cbd0e0b95 100644 --- a/backend/gn_module_monitoring/utils/routes.py +++ b/backend/gn_module_monitoring/utils/routes.py @@ -1,8 +1,10 @@ from typing import Tuple -from flask import Response +from flask import Response, request from flask.json import jsonify from geonature.utils.env import DB +from gn_module_monitoring.modules.repositories import get_module +from gn_module_monitoring.utils.utils import to_int from marshmallow import Schema from sqlalchemy import cast, func, text from sqlalchemy.dialects.postgresql import JSON @@ -11,6 +13,7 @@ from gn_module_monitoring.monitoring.queries import Query as MonitoringQuery from gn_module_monitoring.monitoring.schemas import paginate_schema +from gn_module_monitoring.monitoring.definitions import monitoring_g_definitions def get_limit_page(params: MultiDict) -> Tuple[int]: @@ -57,3 +60,44 @@ def geojson_query(subquery) -> bytes: if len(result) > 0: return result[0] return b"" + + +def create_or_update_object_api_sites_sites_group(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_g_definitions.monitoring_object_instance(module_code, object_type, id) + .create_or_update(post_data) + .serialize(depth) + ) diff --git a/frontend/app/class/monitoring-site.ts b/frontend/app/class/monitoring-site.ts deleted file mode 100644 index d33650386..000000000 --- a/frontend/app/class/monitoring-site.ts +++ /dev/null @@ -1,13 +0,0 @@ -export enum columnNameSite { - base_site_name = "Nom", - last_visit = "Dernière visite", - nb_visits = "Nb. visites", - base_site_code = "Code", - altitude_max = "Alt.max", - altitude_min = "Alt.min", -} - -export const extendedDetailsSite = { - ...columnNameSite, - base_site_description: "Description", -}; diff --git a/frontend/app/class/monitoring-sites-group.ts b/frontend/app/class/monitoring-sites-group.ts deleted file mode 100644 index 96fab297d..000000000 --- a/frontend/app/class/monitoring-sites-group.ts +++ /dev/null @@ -1,12 +0,0 @@ -export enum columnNameSiteGroup { - sites_group_name = "Nom", - nb_sites = "Nb. sites", - nb_visits = "Nb. visites", - sites_group_code = "Code", -} - -export const extendedDetailsSiteGroup = { - ...columnNameSiteGroup, - comments: "Commentaires", - sites_group_description: "Description", -}; diff --git a/frontend/app/components/btn-select/btn-select.component.css b/frontend/app/components/btn-select/btn-select.component.css new file mode 100644 index 000000000..025878545 --- /dev/null +++ b/frontend/app/components/btn-select/btn-select.component.css @@ -0,0 +1,5 @@ +.example-chip-list { + width: 100%; + background-color: white; + border-radius: 5px; +} diff --git a/frontend/app/components/btn-select/btn-select.component.html b/frontend/app/components/btn-select/btn-select.component.html new file mode 100644 index 000000000..c852dfbd1 --- /dev/null +++ b/frontend/app/components/btn-select/btn-select.component.html @@ -0,0 +1,31 @@ + + {{ titleBtn }} + + + {{ optionSelected }} + + + + + + + + {{ option.name }} + + + + diff --git a/frontend/app/components/btn-select/btn-select.component.ts b/frontend/app/components/btn-select/btn-select.component.ts new file mode 100644 index 000000000..345a4ab6e --- /dev/null +++ b/frontend/app/components/btn-select/btn-select.component.ts @@ -0,0 +1,123 @@ +import { COMMA, ENTER } from '@angular/cdk/keycodes'; +import { + Component, + ElementRef, + EventEmitter, + Input, + OnInit, + Output, + ViewChild, +} from '@angular/core'; +import { FormControl } 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'; + +export interface EmptyObject { + name: string; +} + +@Component({ + selector: 'btn-select', + templateUrl: './btn-select.component.html', + styleUrls: ['./btn-select.component.css'], +}) +export class BtnSelectComponent implements OnInit { + selectable = true; + removable = true; + separatorKeysCodes: number[] = [ENTER, COMMA]; + myControl = new FormControl(); + @Input() placeholderText: string = 'Selectionnez vos options dans la liste'; + @Input() titleBtn: string = 'Choix des options'; + + filteredOptions: Observable; + listOptionChosen: string[] = []; + configObjAdded: JsonData = {}; + genericResponse: JsonData = {}; + + @Input() paramToFilt: string; + @Input() callBackFunction: ( + pageNumber: number, + limit: number, + valueToFilter: string + ) => Observable; + @ViewChild('optionInput') optionInput: ElementRef; + + @Output() public sendobject = new EventEmitter(); + + constructor() {} + + ngOnInit() { + this.filteredOptions = this.myControl.valueChanges.pipe( + startWith(''), + debounceTime(400), + distinctUntilChanged(), + switchMap((val: string) => { + return iif( + () => val == '', + of([{ name: val }]), + this.filterOnRequest(val, this.paramToFilt) + ); + }), + map((res) => (res.length > 0 ? res : [{ name: 'Pas de résultats' }])) + ); + } + + remove(option: string): void { + const index = this.listOptionChosen.indexOf(option); + + if (index >= 0) { + this.listOptionChosen.splice(index, 1); + } + + if (this.configObjAdded && this.configObjAdded[option] !== undefined) { + delete this.configObjAdded[option]; + } + this.sendobject.emit(this.configObjAdded); + } + + selected(event: MatAutocompleteSelectedEvent): void { + const shouldAddValue = this.checkBeforeAdding(event.option.viewValue); + shouldAddValue + ? this.listOptionChosen.push(event.option.viewValue) && this.addObject(event.option.value) + : null; + this.optionInput.nativeElement.value = ''; + this.myControl.setValue(null); + } + + filterOnRequest(val: string, keyToFilt: string): Observable { + return this.callBackFunction(1, 100, val).pipe( + // Ici on map pour créer une liste d'objet contenant la valeur entré + map((response) => + response.items.filter((option) => { + return option[keyToFilt].toLowerCase().includes(val.toLowerCase()); + }) + ), + // Ici on map pour uniformiser la "key" utilisé pour afficher les options (default Key : 'name') + map((response) => + response.filter((obj) => { + Object.assign(obj, { name: obj[keyToFilt] })[keyToFilt]; + delete obj[keyToFilt]; + return obj; + }) + ) + ); + } + + checkBeforeAdding(valToAdd: string) { + const noValidInput = [null, '', 'Pas de résultats']; + if (noValidInput.includes(valToAdd) || this.listOptionChosen.includes(valToAdd)) { + return false; + } else { + return true; + } + } + + addObject(obj: JsonData) { + const { name, ...configAndId } = obj; + this.configObjAdded[name] = configAndId; + this.sendobject.emit(this.configObjAdded); + } +} diff --git a/frontend/app/components/monitoring-datatable-g/monitoring-datatable-g.component.css b/frontend/app/components/monitoring-datatable-g/monitoring-datatable-g.component.css index 6017b44ab..11176aee6 100644 --- a/frontend/app/components/monitoring-datatable-g/monitoring-datatable-g.component.css +++ b/frontend/app/components/monitoring-datatable-g/monitoring-datatable-g.component.css @@ -1,48 +1,47 @@ .cell-link { - cursor: pointer; + cursor: pointer; } :host::ng-deep .datatable-body-row.active .datatable-row-group { - background-color: rgb(117, 227, 118) !important; + background-color: rgb(117, 227, 118) !important; } .link:hover { - background-color: rgba(0, 0, 0, 0.2) !important; - transition: background-color 0.5; + background-color: rgba(0, 0, 0, 0.2) !important; + transition: background-color 0.5; } .link { - display: inline; - transition: background-color 0.5s; - border-radius: 5px; + display: inline; + transition: background-color 0.5s; + border-radius: 5px; } .header-filter-span > input { - width: 100%; + width: 100%; } .header-sort-span { - /* width: 100%; */ - cursor: pointer; - text-overflow: ellipsis; - overflow: hidden; - white-space:nowrap + /* width: 100%; */ + cursor: pointer; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; } - .header-sort-span:hover { - background-color: rgb(245, 245, 245); + background-color: rgb(245, 245, 245); } .icon-sort { - font-size: 1.2em; - float: right; + font-size: 1.2em; + float: right; } :host::ng-deep .sort-btn { - display: none !important; + display: none !important; } .custom-dt { - box-shadow: none !important; + box-shadow: none !important; } diff --git a/frontend/app/components/monitoring-datatable-g/monitoring-datatable-g.component.html b/frontend/app/components/monitoring-datatable-g/monitoring-datatable-g.component.html index 17e0a03ed..7db5849a0 100644 --- a/frontend/app/components/monitoring-datatable-g/monitoring-datatable-g.component.html +++ b/frontend/app/components/monitoring-datatable-g/monitoring-datatable-g.component.html @@ -17,11 +17,8 @@ - - + - +
help - - {{ column.name }} + {{ column.name }}
{ beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ MonitoringDatatableComponent ] - }) - .compileComponents(); + declarations: [MonitoringDatatableComponent], + }).compileComponents(); })); beforeEach(() => { diff --git a/frontend/app/components/monitoring-datatable-g/monitoring-datatable-g.component.ts b/frontend/app/components/monitoring-datatable-g/monitoring-datatable-g.component.ts index b152c85cd..73bb836d8 100644 --- a/frontend/app/components/monitoring-datatable-g/monitoring-datatable-g.component.ts +++ b/frontend/app/components/monitoring-datatable-g/monitoring-datatable-g.component.ts @@ -1,21 +1,23 @@ -import { DatatableComponent } from "@swimlane/ngx-datatable"; import { Component, - OnInit, + EventEmitter, Input, + OnInit, Output, - EventEmitter, - ViewChild, SimpleChanges, TemplateRef, -} from "@angular/core"; -import { Router, ActivatedRoute } from "@angular/router"; -import { Subject } from "rxjs"; -import { debounceTime } from "rxjs/operators"; -import { DataTableService } from "../../services/data-table.service"; -import { IColumn } from "../../interfaces/column"; -import { IPage } from "../../interfaces/page"; -import { ObjectService } from "../../services/object.service"; + ViewChild, +} from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { DatatableComponent } from '@swimlane/ngx-datatable'; +import { Subject } from 'rxjs'; +import { debounceTime } from 'rxjs/operators'; + +import { IColumn } from '../../interfaces/column'; +import { IobjObs, ObjDataType } from '../../interfaces/objObs'; +import { IPage } from '../../interfaces/page'; +import { DataTableService } from '../../services/data-table.service'; +import { ObjectService } from '../../services/object.service'; interface ItemObjectTable { id: number | null; @@ -26,9 +28,9 @@ interface ItemObjectTable { type ItemsObjectTable = { [key: string]: ItemObjectTable }; @Component({ - selector: "pnx-monitoring-datatable-g", - templateUrl: "./monitoring-datatable-g.component.html", - styleUrls: ["./monitoring-datatable-g.component.css"], + selector: 'pnx-monitoring-datatable-g', + templateUrl: './monitoring-datatable-g.component.html', + styleUrls: ['./monitoring-datatable-g.component.css'], }) export class MonitoringDatatableGComponent implements OnInit { @Input() rows; @@ -53,15 +55,15 @@ export class MonitoringDatatableGComponent implements OnInit { displayFilter: boolean = false; objectsStatus: ItemsObjectTable; - objectType: string = ""; + objectType: IobjObs; columns; row_save; selected = []; filters = {}; @ViewChild(DatatableComponent) table: DatatableComponent; - @ViewChild("actionsTemplate") actionsTemplate: TemplateRef; - @ViewChild("hdrTpl") hdrTpl: TemplateRef; + @ViewChild('actionsTemplate') actionsTemplate: TemplateRef; + @ViewChild('hdrTpl') hdrTpl: TemplateRef; constructor( private _dataTableService: DataTableService, @@ -108,7 +110,7 @@ export class MonitoringDatatableGComponent implements OnInit { // filter all const oldFilters = this.filters; this.filters = Object.keys(oldFilters).reduce(function (r, e) { - if (![undefined, "", null].includes(oldFilters[e])) r[e] = oldFilters[e]; + if (![undefined, '', null].includes(oldFilters[e])) r[e] = oldFilters[e]; return r; }, {}); this.onFilter.emit(this.filters); @@ -123,7 +125,7 @@ export class MonitoringDatatableGComponent implements OnInit { this.rowStatus.forEach((status) => { const bCond = status.id === id; - status["selected"] = bCond && !status["selected"]; + status['selected'] = bCond && !status['selected']; }); this.setSelected(); @@ -132,7 +134,6 @@ export class MonitoringDatatableGComponent implements OnInit { setSelected() { // this.table._internalRows permet d'avoir les ligne triées et d'avoir les bons index - if (!this.rowStatus) { return; } @@ -165,27 +166,21 @@ export class MonitoringDatatableGComponent implements OnInit { ngOnChanges(changes: SimpleChanges) { // IF prefered ngOnChanges compare to observable uncomment this: - if (changes["rows"] && this.rows && this.rows.length > 0) { - this.columns = this._dataTableService.colsTable( - this.colsname, - this.rows[0] - ); + if (changes['rows'] && this.rows && this.rows.length > 0) { + this.columns = this._dataTableService.colsTable(this.colsname, this.rows[0]); } - if (changes["colsname"]) { + if (changes['colsname']) { this.filters = {}; } - if (changes["obj"] && this.obj) { + if (changes['obj'] && this.obj) { this.objectsStatus, - (this.rowStatus = this._dataTableService.initObjectsStatus( - this.obj, - "sites_groups" - )); + (this.rowStatus = this._dataTableService.initObjectsStatus(this.obj, 'sites_groups')); } for (const propName of Object.keys(changes)) { switch (propName) { - case "rowStatus": + case 'rowStatus': this.setSelected(); break; } @@ -193,12 +188,13 @@ export class MonitoringDatatableGComponent implements OnInit { } navigateToAddChildren(_, rowId) { this.addEvent.emit(rowId); - this.router.navigate(["create"], { + this._objService.changeObjectType(this.objectType); + this.router.navigate(['create'], { relativeTo: this._Activatedroute, }); } navigateToDetail(row) { - row["id"] = row.pk; + row['id'] = row.pk; this.onDetailsRow.emit(row); } } diff --git a/frontend/app/components/monitoring-form-g/monitoring-form.component-g.css b/frontend/app/components/monitoring-form-g/monitoring-form.component-g.css index a5c26b9ca..d4ac1536b 100644 --- a/frontend/app/components/monitoring-form-g/monitoring-form.component-g.css +++ b/frontend/app/components/monitoring-form-g/monitoring-form.component-g.css @@ -13,10 +13,9 @@ } .float-right { -margin-left: 5px; + margin-left: 5px; } - .float-left { margin-right: 10px; float: left; @@ -28,4 +27,20 @@ form:invalid { form.ng-invalid { border: 0px !important; -} \ No newline at end of file +} + +#form-scroll { + overflow-y: auto; + max-height: 70vh; +} + +.btn-child { + border: 0px solid #202020; + padding-top: 2px; + padding-bottom: auto; + -webkit-box-shadow: 0px -2px 2px rgba(50, 50, 50, 0.3); + -moz-box-shadow: 0px -2px 2px rgba(50, 50, 50, 0.3); + box-shadow: 0px -2px 2px rgba(50, 50, 50, 0.3); + overflow: hidden; + height: fit-content; +} diff --git a/frontend/app/components/monitoring-form-g/monitoring-form.component-g.html b/frontend/app/components/monitoring-form-g/monitoring-form.component-g.html index 389e9284b..7f4f5f46e 100644 --- a/frontend/app/components/monitoring-form-g/monitoring-form.component-g.html +++ b/frontend/app/components/monitoring-form-g/monitoring-form.component-g.html @@ -1,6 +1,6 @@

Attention

-

+

Vous êtes sur le point de supprimer le groupe de site Description du groupe de site @@ -14,22 +14,16 @@

Attention

> Confirmer la suppression - +
-
- - - +
+ + - - +
- - - -
+
+ +
+ +
- Valider - - - - +
diff --git a/frontend/app/components/monitoring-form-g/monitoring-form.component-g.spec.ts b/frontend/app/components/monitoring-form-g/monitoring-form.component-g.spec.ts index 1cfc81be0..be4c9c70d 100644 --- a/frontend/app/components/monitoring-form-g/monitoring-form.component-g.spec.ts +++ b/frontend/app/components/monitoring-form-g/monitoring-form.component-g.spec.ts @@ -1,4 +1,4 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; import { MonitoringFormComponent } from './monitoring-form.component'; @@ -8,9 +8,8 @@ describe('MonitoringFormComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ MonitoringFormComponent ] - }) - .compileComponents(); + declarations: [MonitoringFormComponent], + }).compileComponents(); })); beforeEach(() => { diff --git a/frontend/app/components/monitoring-form-g/monitoring-form.component-g.ts b/frontend/app/components/monitoring-form-g/monitoring-form.component-g.ts index c993c5026..683fbe72f 100644 --- a/frontend/app/components/monitoring-form-g/monitoring-form.component-g.ts +++ b/frontend/app/components/monitoring-form-g/monitoring-form.component-g.ts @@ -1,25 +1,22 @@ -import { - Component, - OnInit, - Input, - Output, - EventEmitter, - SimpleChanges, -} from "@angular/core"; -import { FormGroup, FormBuilder } from "@angular/forms"; -import { MonitoringObject } from "../../class/monitoring-object"; -import { ConfigService } from "../../services/config.service"; -import { CommonService } from "@geonature_common/service/common.service"; -import { DynamicFormService } from "@geonature_common/form/dynamic-form-generator/dynamic-form.service"; -import { ActivatedRoute } from "@angular/router"; -import { EditObjectService } from "../../services/edit-object.service"; -import { Router } from "@angular/router"; -import { IDataForm } from "../../interfaces/form"; -import { ApiGeomService } from "../../services/api-geom.service"; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { tap, mergeMap } from 'rxjs/operators'; +import { ActivatedRoute } from '@angular/router'; +import { Router } from '@angular/router'; +import { DynamicFormService } from '@geonature_common/form/dynamic-form-generator/dynamic-form.service'; +import { CommonService } from '@geonature_common/service/common.service'; + +import { MonitoringObject } from '../../class/monitoring-object'; +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'; + @Component({ - selector: "pnx-monitoring-form-g", - templateUrl: "./monitoring-form.component-g.html", - styleUrls: ["./monitoring-form.component-g.css"], + selector: 'pnx-monitoring-form-g', + templateUrl: './monitoring-form.component-g.html', + styleUrls: ['./monitoring-form.component-g.css'], }) export class MonitoringFormComponentG implements OnInit { @Input() currentUser; @@ -37,7 +34,7 @@ export class MonitoringFormComponentG implements OnInit { @Input() sites: {}; dataForm: IDataForm; - searchSite = ""; + searchSite = ''; obj: any; objFormsDefinition; @@ -57,108 +54,103 @@ export class MonitoringFormComponentG implements OnInit { constructor( private _formBuilder: FormBuilder, private _route: ActivatedRoute, - private _configService: ConfigService, + private _configService: ConfigJsonService, private _commonService: CommonService, private _dynformService: DynamicFormService, - private _editService: EditObjectService, + private _formService: FormService, private _apiGeomService: ApiGeomService, - private _router: Router + private _router: Router, + private _objService: ObjectService ) {} ngOnInit() { - this._editService.currentData.subscribe((dataToEdit) => { - this.obj = dataToEdit; - this.obj.bIsInitialized = true; - this._configService - .init(this.obj.moduleCode) - .pipe() - .subscribe(() => { - // return this._route.queryParamMap; - // }) - // .subscribe((queryParams) => { - this.queryParams = this._route.snapshot.queryParams || {}; - this.bChainInput = - this._configService.frontendParams()["bChainInput"]; - - const schema = this._configService.schema( + // 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._apiGeomService.init(this.obj.endPoint, this.obj.objSelected); + }), + mergeMap((data: any) => this._configService.init(data.moduleCode)) + ) + .subscribe(() => { + + this.queryParams = this._route.snapshot.queryParams || {}; + this.bChainInput = this._configService.frontendParams()['bChainInput']; + + const schema = this._configService.schema( + this.obj.moduleCode, + this.obj.objectType + ); + + this.obj[this.obj.moduleCode] = schema; + + this.obj.specific == undefined ? (this.obj.specific = {}) : null; + if (Object.keys(this.obj.specific).length !== 0) { + Object.assign(schema, this.obj.specific); + } + + + + // meta pour les parametres dynamiques + // ici pour avoir acces aux nomenclatures + this.meta = { + // nomenclatures: this._dataUtilsService.getDataUtil('nomenclature'), + // dataset: this._dataUtilsService.getDataUtil('dataset'), + // id_role: this.currentUser.id_role, + bChainInput: this.bChainInput, + parents: this.obj.parents, + }; + + this.objFormsDefinition = this._dynformService + .formDefinitionsdictToArray(schema, this.meta) + .filter((formDef) => formDef.type_widget) + .sort((a, b) => { + // medias à la fin + return a.attribut_name === 'medias' + ? +1 + : b.attribut_name === 'medias' + ? -1 + : 0; + }); + + // display_form pour customiser l'ordre dans le formulaire + // les éléments de display form sont placé en haut dans l'ordre du tableau + // tous les éléments non cachés restent affichés + + let displayProperties = [ + ...(this._configService.configModuleObjectParam( this.obj.moduleCode, - this.obj.objectType - ); - this.obj[this.obj.moduleCode] = schema; - // const schema = this.obj.schema(); - - // init objFormsDefinition - - // meta pour les parametres dynamiques - // ici pour avoir acces aux nomenclatures - this.meta = { - // nomenclatures: this._dataUtilsService.getDataUtil('nomenclature'), - // dataset: this._dataUtilsService.getDataUtil('dataset'), - // id_role: this.currentUser.id_role, - bChainInput: this.bChainInput, - parents: this.obj.parents, - }; - - this.objFormsDefinition = this._dynformService - .formDefinitionsdictToArray(schema, this.meta) - .filter((formDef) => formDef.type_widget) - .sort((a, b) => { - // medias à la fin - return a.attribut_name === "medias" - ? +1 - : b.attribut_name === "medias" - ? -1 - : 0; - }); - - // display_form pour customiser l'ordre dans le formulaire - // les éléments de display form sont placé en haut dans l'ordre du tableau - // tous les éléments non cachés restent affichés - - let displayProperties = [ - ...(this._configService.configModuleObjectParam( - this.obj.moduleCode, - this.obj.objectType, - "display_properties" - ) || []), - ]; - if (displayProperties && displayProperties.length) { - displayProperties.reverse(); - this.objFormsDefinition.sort((a, b) => { - let indexA = displayProperties.findIndex( - (e) => e == a.attribut_name - ); - let indexB = displayProperties.findIndex( - (e) => e == b.attribut_name - ); - return indexB - indexA; - }); - } - - // champs patch pour simuler un changement de valeur et déclencher le recalcul des propriété - // par exemple quand bChainInput change - this.objForm.addControl("patch_update", this._formBuilder.control(0)); - - // this._configService.configModuleObject(this.obj.moduleCode, this.obj.objectType); - // set geometry - // if (this.obj.config["geometry_type"]) { - // this.objForm.addControl( - // "geometry", - // this._formBuilder.control("", Validators.required) - // ); - // } - - // pour donner la valeur de idParent - - this.initForm(); - }); - }); + this.obj.objectType, + 'display_properties' + ) || []), + ]; + if (displayProperties && displayProperties.length) { + displayProperties.reverse(); + this.objFormsDefinition.sort((a, b) => { + let indexA = displayProperties.findIndex( + (e) => e == a.attribut_name + ); + let indexB = displayProperties.findIndex( + (e) => e == b.attribut_name + ); + return indexB - indexA; + }); + } + + // champs patch pour simuler un changement de valeur et déclencher le recalcul des propriété + // par exemple quand bChainInput change + this.objForm.addControl('patch_update', this._formBuilder.control(0)); + + this.initForm(); + }); } /** pour réutiliser des paramètres déjà saisis */ keepDefinitions() { return this.objFormsDefinition.filter((def) => - this.obj.configParam("keep").includes(def.attribut_name) + this.obj.configParam('keep').includes(def.attribut_name) ); } @@ -182,7 +174,7 @@ export class MonitoringFormComponentG implements OnInit { this.setQueryParams(); // pour donner la valeur de l'objet au formulaire - this._editService.formValues(this.obj).subscribe((formValue) => { + this._formService.formValues(this.obj).subscribe((formValue) => { this.objForm.patchValue(formValue); this.setDefaultFormValue(); this.dataForm = formValue; @@ -191,16 +183,14 @@ export class MonitoringFormComponentG implements OnInit { } keepNames() { - return this.obj.configParam("keep") || []; + return this.obj.configParam('keep') || []; } resetObjForm() { // quand on enchaine les relevés - const chainShow = this.obj.configParam("chain_show"); + const chainShow = this.obj.configParam('chain_show'); if (chainShow) { - this.chainShow.push( - chainShow.map((key) => this.obj.resolvedProperties[key]) - ); + this.chainShow.push(chainShow.map((key) => this.obj.resolvedProperties[key])); this.chainShow.push(this.obj.resolvedProperties); } @@ -219,7 +209,7 @@ export class MonitoringFormComponentG implements OnInit { ); this.obj.init({}); - this.obj.properties[this.obj.configParam("id_field_Name")] = null; + this.obj.properties[this.obj.configParam('id_field_Name')] = null; // pq get ????? // this.obj.get(0).subscribe(() => { @@ -231,7 +221,7 @@ export class MonitoringFormComponentG implements OnInit { this.objChanged.emit(this.obj); this.objForm.patchValue({ geometry: null }); this.initForm(); - // }); + // }; } /** Pour donner des valeurs par defaut si la valeur n'est pas définie @@ -245,7 +235,7 @@ export class MonitoringFormComponentG implements OnInit { const defaultValue = { // id_digitiser: value["id_digitiser"] || this.currentUser.id_role, // id_inventor: value["id_inventor"] || this.currentUser.id_role, - first_use_date: value["first_use_date"] || { + first_use_date: value['first_use_date'] || { year: date.getUTCFullYear(), month: date.getUTCMonth() + 1, day: date.getUTCDate(), @@ -272,11 +262,12 @@ export class MonitoringFormComponentG implements OnInit { navigateToDetail(id, objectType, queryParams) { // patch bug navigation this._router.navigate( - ["monitorings", objectType, id].filter((s) => !!s), + ['monitorings', objectType, id].filter((s) => !!s), { queryParams, } ); + this.objChanged.emit(this.obj); this.bEditChange.emit(false); } @@ -285,7 +276,7 @@ export class MonitoringFormComponentG implements OnInit { */ navigateToParent() { this.bEditChange.emit(false); // patch bug navigation - this._router.navigateByUrl("/monitorings/sites_group"); + this._router.navigateByUrl('/monitorings/sites_group'); // this.obj.navigateToParent(); } @@ -298,22 +289,19 @@ export class MonitoringFormComponentG implements OnInit { /** TODO améliorer site etc.. */ onSubmit() { const { patch_update, ...sendValue } = this.dataForm; + const objToUpdateOrCreate = this._formService.postData(sendValue, this.obj); + console.log(objToUpdateOrCreate); const action = this.obj.id - ? // ? this.obj.patch(this.objForm.value) - // : this.obj.post(this.objForm.value); - this._apiGeomService.patch(this.obj.id, sendValue) - : this._apiGeomService.create(sendValue); - const actionLabel = this.obj.id ? "Modification" : "Création"; + ? this._apiGeomService.patch(this.obj.id, objToUpdateOrCreate) + : this._apiGeomService.create(objToUpdateOrCreate); + const actionLabel = this.obj.id ? 'Modification' : 'Création'; action.subscribe((objData) => { - this._commonService.regularToaster( - "success", - this.msgToaster(actionLabel) - ); + this._commonService.regularToaster('success', this.msgToaster(actionLabel)); this.bSaveSpinner = this.bSaveAndAddChildrenSpinner = false; - this.objChanged.emit(this.obj); + // this.objChanged.emit(this.obj); /** si c'est un module : reset de la config */ - if (this.obj.objectType === "module") { + if (this.obj.objectType === 'module') { this._configService.loadConfig(this.obj.moduleCode).subscribe(); } @@ -326,16 +314,12 @@ export class MonitoringFormComponentG implements OnInit { this._configService.configModuleObjectParam( this.obj.moduleCode, this.obj.objectType, - "redirect_to_parent" + 'redirect_to_parent' ) ) { this.navigateToParent(); } else { - this.navigateToDetail( - this.obj.id, - this.obj.objectType, - this.queryParams - ); + this.navigateToDetail(this.obj.id, this.obj.objectType, this.queryParams); } } }); @@ -351,7 +335,7 @@ export class MonitoringFormComponentG implements OnInit { onDelete() { this.bDeleteSpinner = true; - this._commonService.regularToaster("info", this.msgToaster("Suppression")); + this._commonService.regularToaster('info', this.msgToaster('Suppression')); // : this.obj.post(this.objForm.value); this._apiGeomService.delete(this.obj.id).subscribe((del) => { this.bDeleteSpinner = this.bDeleteModal = false; @@ -366,10 +350,7 @@ export class MonitoringFormComponentG implements OnInit { // let {id_module,medias, ...rest} = this.objForm.value; // this.dataForm = rest this.dataForm = this.objForm.value; - const change = this._configService.change( - this.obj.moduleCode, - this.obj.objectType - ); + const change = this._configService.change(this.obj.moduleCode, this.obj.objectType); if (!change) { return; } @@ -389,8 +370,24 @@ export class MonitoringFormComponentG implements OnInit { for (const formDef of this.objFormsDefinition) { formDef.meta.bChainInput = this.bChainInput; } - this._configService.setFrontendParams("bChainInput", this.bChainInput); + this._configService.setFrontendParams('bChainInput', this.bChainInput); // patch pour recalculers this.procesPatchUpdateForm(); } + + 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 + this.obj.specific = {}; + this.obj.dataComplement = {}; + for (const key in event) { + if (event[key].config != undefined) { + if (Object.keys(event[key].config).length !== 0) { + Object.assign(this.obj.specific, event[key].config.specific); + } + } + } + Object.assign(this.obj.dataComplement, event); + this._formService.dataToCreate(this.obj); + } } diff --git a/frontend/app/components/monitoring-properties-g/monitoring-properties-g.component.html b/frontend/app/components/monitoring-properties-g/monitoring-properties-g.component.html index ebab4aca9..e95701d15 100644 --- a/frontend/app/components/monitoring-properties-g/monitoring-properties-g.component.html +++ b/frontend/app/components/monitoring-properties-g/monitoring-properties-g.component.html @@ -13,7 +13,7 @@ >Propriétés
@@ -39,27 +39,20 @@ attr.aria-labelledby="nav-properties-tab" > - + - +
- {{ fieldName.value }} - + {{ fields[fieldName] }} + help {{ selectedObj[fieldName.key] }}{{ selectedObj[fieldName] }}
@@ -68,9 +61,9 @@ id="medias-tab" role="tabpanel" attr.aria-labelledby="nav-medias-tab" - *ngIf="obj.properties['medias'] && obj.properties['medias'].length" + *ngIf="objectType.properties['medias'] && objectType.properties['medias'].length" > - +
{{ media.title_fr }} @@ -83,7 +76,7 @@

{{media.description_fr}}

--> -
diff --git a/frontend/app/components/monitoring-properties-g/monitoring-properties-g.component.ts b/frontend/app/components/monitoring-properties-g/monitoring-properties-g.component.ts index d47a3ef60..0c4cf5456 100644 --- a/frontend/app/components/monitoring-properties-g/monitoring-properties-g.component.ts +++ b/frontend/app/components/monitoring-properties-g/monitoring-properties-g.component.ts @@ -1,16 +1,10 @@ -import { - Component, - OnInit, - Input, - Output, - EventEmitter, - SimpleChanges, -} from "@angular/core"; +import { Component, OnInit, Input, Output, EventEmitter } from "@angular/core"; import { FormControl } from "@angular/forms"; -import { extendedDetailsSiteGroup } from "../../class/monitoring-sites-group"; import { ISitesGroup } from "../../interfaces/geom"; -import { EditObjectService } from "../../services/edit-object.service"; +import { IobjObs, ObjDataType } from "../../interfaces/objObs"; +import { FormService } from "../../services/form.service"; import { ObjectService } from "../../services/object.service"; +import { JsonData } from "../../types/jsondata"; @Component({ selector: "pnx-monitoring-properties-g", @@ -18,32 +12,44 @@ import { ObjectService } from "../../services/object.service"; styleUrls: ["./monitoring-properties-g.component.css"], }) export class MonitoringPropertiesGComponent implements OnInit { - @Input() selectedObj: ISitesGroup; + // selectedObj: ISitesGroup; + @Input() selectedObj: ObjDataType; @Input() bEdit: boolean; @Output() bEditChange = new EventEmitter(); - @Input() objectType: string; + @Input() objectType: IobjObs; - infosColsSiteGroups: typeof extendedDetailsSiteGroup = - extendedDetailsSiteGroup; color: string = "white"; dataDetails: ISitesGroup; - + fields: JsonData; + fieldDefinitions: JsonData; + fieldsNames: string[]; + endPoint:string; datasetForm = new FormControl(); constructor( - private _editService: EditObjectService, - private _objService: ObjectService + private _formService: FormService, + private _objService: ObjectService, ) {} ngOnInit() { this._objService.currentObjectTypeParent.subscribe((newObjType) => { this.objectType = newObjType; + this.fieldsNames = newObjType.template.fieldNames; + this.fields = newObjType.template.fieldLabels; + this.fieldDefinitions = newObjType.template.fieldDefinitions; + this.objectType.properties = this.selectedObj; + this.endPoint = newObjType.endPoint; }); } onEditClick() { this.bEditChange.emit(true); this.selectedObj["id"] = this.selectedObj[this.selectedObj.pk]; - this._editService.changeDataSub(this.selectedObj); + this._formService.changeDataSub( + this.selectedObj, + this.objectType.objectType, + this.objectType.endPoint, + this.objectType + ); } } diff --git a/frontend/app/components/monitoring-sites-create/monitoring-sites-create.component.css b/frontend/app/components/monitoring-sites-create/monitoring-sites-create.component.css new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/app/components/monitoring-sites-create/monitoring-sites-create.component.html b/frontend/app/components/monitoring-sites-create/monitoring-sites-create.component.html new file mode 100644 index 000000000..cc95c530c --- /dev/null +++ b/frontend/app/components/monitoring-sites-create/monitoring-sites-create.component.html @@ -0,0 +1,13 @@ + +
+ +
diff --git a/frontend/app/components/monitoring-sites-create/monitoring-sites-create.component.ts b/frontend/app/components/monitoring-sites-create/monitoring-sites-create.component.ts new file mode 100644 index 000000000..32514d56f --- /dev/null +++ b/frontend/app/components/monitoring-sites-create/monitoring-sites-create.component.ts @@ -0,0 +1,82 @@ +import { Component, OnInit, ViewChild } from '@angular/core'; +import { FormService } from '../../services/form.service'; +import { FormGroup, FormBuilder } from '@angular/forms'; +import { ISite, ISiteType } from '../../interfaces/geom'; +import { SitesService } from '../../services/api-geom.service'; +import { Observable } from 'rxjs'; +import { IobjObs, ObjDataType } from '../../interfaces/objObs'; +import { MonitoringFormComponentG } from '../monitoring-form-g/monitoring-form.component-g'; +import { ObjectService } from '../../services/object.service'; +import { JsonData } from '../../types/jsondata'; +import { endPoints } from '../../enum/endpoints'; +import { IPaginated } from '../../interfaces/page'; + +@Component({ + selector: 'monitoring-sites-create', + templateUrl: './monitoring-sites-create.component.html', + styleUrls: ['./monitoring-sites-create.component.css'], +}) +export class MonitoringSitesCreateComponent implements OnInit { + site: ISite; + form: FormGroup; + paramToFilt: string = 'label'; + funcToFilt: Function; + titleBtn: string = 'Choix des types de sites'; + placeholderText: string = 'Sélectionnez les types de site'; + id_sites_group: number; + types_site: string[]; + @ViewChild('subscritionObjConfig') + monitoringFormComponentG: MonitoringFormComponentG; + objToCreate: IobjObs; + + constructor( + private _formService: FormService, + private _formBuilder: FormBuilder, + private siteService: SitesService, + private _objService: ObjectService + ) {} + + ngOnInit() { + this._objService.currentObjSelected.subscribe((objParent) => { + this.id_sites_group = objParent.id_sites_group; + this._formService.dataToCreate({ + module: 'generic', + objectType: 'site', + id_sites_group: this.id_sites_group, + id_relationship: ['id_sites_group', 'types_site'], + endPoint: endPoints.sites, + objSelected: {}, + }); + this.form = this._formBuilder.group({}); + this.funcToFilt = this.partialfuncToFilt.bind(this); + }); + } + + partialfuncToFilt( + pageNumber: number, + limit: number, + valueToFilter: string + ): Observable> { + return this.siteService.getTypeSites(pageNumber, limit, { + label_fr: valueToFilter, + sort_dir: 'desc', + }); + } + + onSendConfig(config: JsonData): void { + config = this.addTypeSiteListIds(config); + this.monitoringFormComponentG.getConfigFromBtnSelect(config); + } + + addTypeSiteListIds(config: JsonData): JsonData { + if (config && config.length != 0) { + config.types_site = []; + for (const key in config) { + if ('id_nomenclature_type_site' in config[key]) { + config.types_site.push(config[key]['id_nomenclature_type_site']); + } + } + } + return config; + } +} diff --git a/frontend/app/components/monitoring-sites/monitoring-sites.component.html b/frontend/app/components/monitoring-sites/monitoring-sites.component.html index 3294f13b8..0f495dfae 100644 --- a/frontend/app/components/monitoring-sites/monitoring-sites.component.html +++ b/frontend/app/components/monitoring-sites/monitoring-sites.component.html @@ -1,5 +1,4 @@ ; constructor( private _sitesGroupService: SitesGroupService, @@ -53,7 +53,7 @@ export class MonitoringSitesComponent ngOnInit() { this.objForm = this._formBuilder.group({}); - this._objService.changeObjectType(this._siteService.addObjectType()); + this._objService.changeObjectType(this._siteService.objectObs); this.initSite(); } @@ -74,10 +74,10 @@ export class MonitoringSitesComponent id_sites_group: id, }), }) - ) - ) + )) .subscribe( - (data: { sitesGroup: ISitesGroup; sites: IPaginated }) => { + (data: { sitesGroup: ISitesGroup; sites: IPaginated}) => { + this._objService.changeSelectedObj(data.sitesGroup, true); this.sitesGroup = data.sitesGroup; this.sites = data.sites.items; this.page = { @@ -90,6 +90,7 @@ export class MonitoringSitesComponent () => {} ); this.baseFilters = { id_sites_group: this.sitesGroup.id_sites_group }; + this.colsname = this._siteService.objectObs.dataTable.colNameObj; } ); } @@ -126,7 +127,7 @@ export class MonitoringSitesComponent } seeDetails($event) { - this._objService.changeObjectTypeParent(this._siteService.editObjectType()); + this._objService.changeObjectTypeParent(this._siteService.objectObs, true); this.router.navigate([`sites/${$event.id_base_site}`], { relativeTo: this._Activatedroute, }); diff --git a/frontend/app/components/monitoring-sitesgroups-create/monitoring-sitesgroups-create.component.ts b/frontend/app/components/monitoring-sitesgroups-create/monitoring-sitesgroups-create.component.ts index 4138a321b..07c4e379b 100644 --- a/frontend/app/components/monitoring-sitesgroups-create/monitoring-sitesgroups-create.component.ts +++ b/frontend/app/components/monitoring-sitesgroups-create/monitoring-sitesgroups-create.component.ts @@ -1,7 +1,8 @@ import { Component, OnInit } from "@angular/core"; -import { EditObjectService } from "../../services/edit-object.service"; +import { FormService } from "../../services/form.service"; import { FormGroup, FormBuilder } from "@angular/forms"; import { ISitesGroup } from "../../interfaces/geom"; +import { endPoints } from "../../enum/endpoints"; @Component({ selector: "monitoring-sitesgroups-create", @@ -12,12 +13,17 @@ export class MonitoringSitesGroupsCreateComponent implements OnInit { siteGroup: ISitesGroup; form: FormGroup; constructor( - private _editService: EditObjectService, + private _formService: FormService, private _formBuilder: FormBuilder ) {} ngOnInit() { - this._editService.changeDataSub({}); + this._formService.dataToCreate({ + module: "generic", + objectType: "sites_group", + endPoint:endPoints.sites_groups, + objSelected: {} + }); this.form = this._formBuilder.group({}); } } diff --git a/frontend/app/components/monitoring-sitesgroups/monitoring-sitesgroups.component.ts b/frontend/app/components/monitoring-sitesgroups/monitoring-sitesgroups.component.ts index 88473a04f..d7dc6a662 100644 --- a/frontend/app/components/monitoring-sitesgroups/monitoring-sitesgroups.component.ts +++ b/frontend/app/components/monitoring-sitesgroups/monitoring-sitesgroups.component.ts @@ -1,15 +1,15 @@ import { Component, OnInit, Input } from "@angular/core"; import { SitesGroupService } from "../../services/api-geom.service"; -import { columnNameSiteGroup } from "../../class/monitoring-sites-group"; import { IPaginated, IPage } from "../../interfaces/page"; import { Router, ActivatedRoute } from "@angular/router"; -import { columnNameSite } from "../../class/monitoring-site"; import { ISite, ISitesGroup } from "../../interfaces/geom"; import { GeoJSONService } from "../../services/geojson.service"; import { MonitoringGeomComponent } from "../../class/monitoring-geom-component"; import { setPopup } from "../../functions/popup"; import { ObjectService } from "../../services/object.service"; import { FormGroup, FormBuilder } from "@angular/forms"; +import { IobjObs } from "../../interfaces/objObs"; +import { ConfigJsonService } from "../../services/config-json.service"; const LIMIT = 10; @@ -25,15 +25,12 @@ export class MonitoringSitesGroupsComponent @Input() page: IPage; @Input() sitesGroups: ISitesGroup[]; @Input() sitesChild: ISite[]; - @Input() columnNameSiteGroup: typeof columnNameSiteGroup = - columnNameSiteGroup; - @Input() columnNameSite: typeof columnNameSite = columnNameSite; @Input() sitesGroupsSelected: ISitesGroup; // @Input() rows; - @Input() colsname; @Input() obj; - objectType: string; + colsname: {}; + objectType: IobjObs; objForm: FormGroup; objInitForm: Object = {}; // siteGroupEmpty={ @@ -50,6 +47,7 @@ export class MonitoringSitesGroupsComponent private router: Router, private _objService: ObjectService, private _formBuilder: FormBuilder, + private _configJsonService: ConfigJsonService, private _Activatedroute: ActivatedRoute // private _routingService: RoutingService ) { super(); @@ -62,11 +60,12 @@ export class MonitoringSitesGroupsComponent initSiteGroup() { this._objService.changeObjectTypeParent( - this._sites_group_service.editObjectType() + this._sites_group_service.objectObs,true ); this._objService.changeObjectType( - this._sites_group_service.addObjectType() + this._sites_group_service.objectObs,true ); + this.getSitesGroups(1); this.geojsonService.getSitesGroupsGeometries( this.onEachFeatureSiteGroups() @@ -92,6 +91,7 @@ export class MonitoringSitesGroupsComponent } getSitesGroups(page = 1, params = {}) { + this._sites_group_service .get(page, LIMIT, params) .subscribe((data: IPaginated) => { @@ -101,7 +101,7 @@ export class MonitoringSitesGroupsComponent page: data.page - 1, }; this.sitesGroups = data.items; - this.colsname = this.columnNameSiteGroup; + this.colsname = this._sites_group_service.objectObs.dataTable.colNameObj; // IF prefered observable compare to ngOnChanges uncomment this: // this._dataTableService.changeColsTable(this.colsname,this.sitesGroups[0]) }); @@ -110,7 +110,7 @@ export class MonitoringSitesGroupsComponent seeDetails($event) { // TODO: routerLink this._objService.changeObjectTypeParent( - this._sites_group_service.editObjectType() + this._sites_group_service.objectObs,true ); this.router.navigate([$event.id_sites_group], { relativeTo: this._Activatedroute, diff --git a/frontend/app/enum/endpoints.ts b/frontend/app/enum/endpoints.ts new file mode 100644 index 000000000..fc7f634af --- /dev/null +++ b/frontend/app/enum/endpoints.ts @@ -0,0 +1,5 @@ + +export enum endPoints { + sites_groups = "sites_groups", + sites = "sites", + } \ No newline at end of file diff --git a/frontend/app/gnModule.module.ts b/frontend/app/gnModule.module.ts index 69016aefd..bb57b9cbe 100644 --- a/frontend/app/gnModule.module.ts +++ b/frontend/app/gnModule.module.ts @@ -8,11 +8,12 @@ import { HttpClient } from '@angular/common/http'; import { HttpClientXsrfModule } from '@angular/common/http'; // Service -import { DataMonitoringObjectService } from './services/data-monitoring-object.service'; -import { DataUtilsService } from './services/data-utils.service'; -import { CacheService } from './services/cache.service'; -import { MonitoringObjectService } from './services/monitoring-object.service'; -import { ConfigService } from './services/config.service'; +import { DataMonitoringObjectService } from "./services/data-monitoring-object.service"; +import { DataUtilsService } from "./services/data-utils.service"; +import { CacheService } from "./services/cache.service"; +import { MonitoringObjectService } from "./services/monitoring-object.service"; +import { ConfigService } from "./services/config.service"; +import { ConfigJsonService } from "./services/config-json.service"; // Component import { BreadcrumbsComponent } from "./components/breadcrumbs/breadcrumbs.component"; @@ -32,6 +33,7 @@ import { MatFormFieldModule } from "@angular/material/form-field"; import { MatAutocompleteModule } from "@angular/material/autocomplete"; import { MatSelectModule } from "@angular/material/select"; import { MatInputModule } from "@angular/material/input"; +import {MatChipsModule} from '@angular/material/chips'; import { MonitoringSitesGroupsComponent } from "./components/monitoring-sitesgroups/monitoring-sitesgroups.component"; import { DataTableService } from "./services/data-table.service"; import { MonitoringPropertiesGComponent } from "./components/monitoring-properties-g/monitoring-properties-g.component"; @@ -39,7 +41,7 @@ import { GeoJSONService } from "./services/geojson.service"; import { MonitoringSitesComponent } from "./components/monitoring-sites/monitoring-sites.component"; import { MonitoringMapListComponent } from "./components/monitoring-map-list/monitoring-map-list.component"; import { MonitoringFormComponentG } from "./components/monitoring-form-g/monitoring-form.component-g"; -import { EditObjectService } from "./services/edit-object.service"; +import { FormService } from "./services/form.service"; import { ObjectService } from "./services/object.service"; import { SitesGroupService, @@ -47,6 +49,8 @@ import { ApiGeomService, } from "./services/api-geom.service"; import { MonitoringSitesGroupsCreateComponent } from "./components/monitoring-sitesgroups-create/monitoring-sitesgroups-create.component"; +import { MonitoringSitesCreateComponent } from "./components/monitoring-sites-create/monitoring-sites-create.component"; +import { BtnSelectComponent } from "./components/btn-select/btn-select.component"; // my module routing const routes: Routes = [ @@ -79,12 +83,15 @@ const routes: Routes = [ { path: "create", component: MonitoringSitesGroupsCreateComponent }, { path: ":id", - // Add new component here children: [ { path: "", component: MonitoringSitesComponent, }, + { + path: "create", + component: MonitoringSitesCreateComponent, + }, ], }, ], @@ -110,6 +117,8 @@ const routes: Routes = [ MonitoringPropertiesGComponent, MonitoringFormComponentG, MonitoringSitesGroupsCreateComponent, + MonitoringSitesCreateComponent, + BtnSelectComponent ], imports: [ GN2CommonModule, @@ -122,6 +131,7 @@ const routes: Routes = [ MatAutocompleteModule, MatSelectModule, MatInputModule, + MatChipsModule, HttpClientXsrfModule.withOptions({ headerName: 'token', }), @@ -132,12 +142,13 @@ const routes: Routes = [ DataMonitoringObjectService, DataUtilsService, ConfigService, + ConfigJsonService, MonitoringObjectService, DataTableService, SitesGroupService, SitesService, GeoJSONService, - EditObjectService, + FormService, ObjectService, ApiGeomService, ], diff --git a/frontend/app/interfaces/geom.ts b/frontend/app/interfaces/geom.ts index 9d43b5cdf..51ac5de25 100644 --- a/frontend/app/interfaces/geom.ts +++ b/frontend/app/interfaces/geom.ts @@ -1,8 +1,8 @@ -import { GeoJSON } from "geojson"; -import { Observable } from "rxjs"; -import { JsonData } from "../types/jsondata"; -import { Resp } from "../types/response"; -import { IPaginated } from "./page"; +import { GeoJSON } from 'geojson'; +import { Observable } from 'rxjs'; +import { JsonData } from '../types/jsondata'; +import { Resp } from '../types/response'; +import { IPaginated } from './page'; export interface IGeomObject { data: JsonData; @@ -22,6 +22,7 @@ export interface ISitesGroup extends IGeomObject { } export interface ISite extends IGeomObject { + pk: number; altitude_max: number; altitude_min: number; base_site_code: string; @@ -37,14 +38,20 @@ export interface ISite extends IGeomObject { uuid_base_site: string; } +interface IGeomObjectProperties { + properties: IGeomObject; +} + export interface IGeomService { - get( - limit: number, - page: number, - params: JsonData - ): Observable>; + get(limit: number, page: number, params: JsonData): Observable>; get_geometries(params: JsonData): Observable; - create(postdata: IGeomObject): Observable; - patch(id: number, updatedData: IGeomObject): Observable; - // delete(obj: IGeomObject) + create(postdata: IGeomObjectProperties): Observable; + patch(id: number, updatedData: IGeomObjectProperties): Observable; + delete(id: number); +} + +export interface ISiteType { + config: JsonData; + id_nomenclature_type_site: number; + label: string; } diff --git a/frontend/app/interfaces/objObs.ts b/frontend/app/interfaces/objObs.ts new file mode 100644 index 000000000..927a65127 --- /dev/null +++ b/frontend/app/interfaces/objObs.ts @@ -0,0 +1,24 @@ +import { endPoints } from "../enum/endpoints"; +import { JsonData } from "../types/jsondata"; +import { ISite, ISitesGroup } from "./geom"; + +export type ObjDataType = ISite | ISitesGroup | JsonData; + +export interface IobjObs { + properties: ObjDataType; + endPoint: endPoints; + objectType: "site" | "sites_group"; + label: string; + addObjLabel: string; + editObjLabel: string; + id: string | null; + moduleCode: string; + schema: JsonData; + template: { + fieldNames: []; + fieldLabels: JsonData; + fieldNamesList: []; + fieldDefinitions: {}; + }; + dataTable: { colNameObj: {} }; +} diff --git a/frontend/app/services/api-geom.service.ts b/frontend/app/services/api-geom.service.ts index 296913ebf..47fbdd4ae 100644 --- a/frontend/app/services/api-geom.service.ts +++ b/frontend/app/services/api-geom.service.ts @@ -1,83 +1,152 @@ -import { Injectable } from "@angular/core"; -import { Observable } from "rxjs"; -import { GeoJSON } from "geojson"; - -import { CacheService } from "./cache.service"; -import { IGeomService, ISitesGroup, ISite } from "../interfaces/geom"; -import { IPaginated } from "../interfaces/page"; -import { JsonData } from "../types/jsondata"; -import { Resp } from "../types/response"; - -export enum endPoints { - sites_groups = "sites_groups", - sites = "sites", -} +import { Injectable } from '@angular/core'; +import { Observable, of } from 'rxjs'; + +import { endPoints } from '../enum/endpoints'; +import { IGeomService, ISite, ISiteType, ISitesGroup } from '../interfaces/geom'; +import { IobjObs, ObjDataType } from '../interfaces/objObs'; +import { IPaginated } from '../interfaces/page'; +import { JsonData } from '../types/jsondata'; +import { Resp } from '../types/response'; +import { Utils } from '../utils/utils'; +import { CacheService } from './cache.service'; +import { ConfigJsonService } from './config-json.service'; @Injectable() export class ApiGeomService implements IGeomService { - public objectType: endPoints = endPoints.sites_groups; + public endPoint: endPoints; + public objectObs: IobjObs; - constructor(protected _cacheService: CacheService) { - this.init(); + constructor( + protected _cacheService: CacheService, + protected _configJsonService: ConfigJsonService + ) { + this.init(this.endPoint, this.objectObs); } - init() { - this.objectType = endPoints.sites_groups; + init(endPoint, objectObjs) { + this.endPoint = endPoint; + this.objectObs = objectObjs; + // this.endPoint = endPoints.sites_groups; + // this.objectObs = { + // properties: {}, + // endPoint: endPoints.sites_groups, + // objectType: 'sites_group', + // label: 'groupe de site', + // addObjLabel: 'Ajouter', + // editObjLabel: 'Editer', + // id: null, + // moduleCode: 'generic', + // schema: {}, + // template: { + // fieldNames: [], + // fieldLabels: {}, + // fieldNamesList: [], + // fieldDefinitions: {}, + // }, + // dataTable: { colNameObj: {} }, + // }; } get( page: number = 1, limit: number = 10, params: JsonData = {} ): Observable> { - return this._cacheService.request< - Observable> - >("get", this.objectType, { - queryParams: { page, limit, ...params }, - }); + return this._cacheService.request>>( + 'get', + this.endPoint, + { + queryParams: { page, limit, ...params }, + } + ); } getById(id: number): Observable { return this._cacheService.request>( - "get", - `${this.objectType}/${id}` + 'get', + `${this.endPoint}/${id}` ); } get_geometries(params: JsonData = {}): Observable { return this._cacheService.request>( - "get", - `${this.objectType}/geometries`, + 'get', + `${this.endPoint}/geometries`, { queryParams: { ...params }, } ); } - patch(id: number, updatedData: ISitesGroup | ISite): Observable { - return this._cacheService.request("patch", `${this.objectType}/${id}`, { + patch(id: number, updatedData: { properties: ISitesGroup | ISite }): Observable { + return this._cacheService.request('patch', `${this.endPoint}/${id}`, { postData: updatedData, }); } - create( postData: ISitesGroup | ISite): Observable { - return this._cacheService.request("post", `${this.objectType}`, { + create(postData: { properties: ISitesGroup | ISite }): Observable { + return this._cacheService.request('post', `${this.endPoint}`, { postData: postData, }); } delete(id: number): Observable { - return this._cacheService.request("delete", `${this.objectType}/${id}`); + return this._cacheService.request('delete', `${this.endPoint}/${id}`); } - } @Injectable() export class SitesGroupService extends ApiGeomService { - constructor(_cacheService: CacheService) { - super(_cacheService); + constructor(_cacheService: CacheService, _configJsonService: ConfigJsonService) { + super(_cacheService, _configJsonService); } init(): void { - this.objectType = endPoints.sites_groups; + this.endPoint = endPoints.sites_groups; + this.objectObs = { + properties: {}, + endPoint: endPoints.sites_groups, + objectType: 'sites_group', + label: 'groupe de site', + addObjLabel: 'Ajouter un nouveau groupe de site', + editObjLabel: 'Editer le groupe de site', + id: null, + moduleCode: 'generic', + schema: {}, + template: { + fieldNames: [], + fieldLabels: {}, + fieldNamesList: [], + fieldDefinitions: {}, + }, + dataTable: { colNameObj: {} }, + }; + this._configJsonService + .init(this.objectObs.moduleCode) + .pipe() + .subscribe(() => { + const fieldNames = this._configJsonService.configModuleObjectParam( + this.objectObs.moduleCode, + this.objectObs.objectType, + 'display_properties' + ); + const fieldNamesList = this._configJsonService.configModuleObjectParam( + this.objectObs.moduleCode, + this.objectObs.objectType, + 'display_list' + ); + const schema = this._configJsonService.schema( + this.objectObs.moduleCode, + this.objectObs.objectType + ); + const fieldLabels = this._configJsonService.fieldLabels(schema); + const fieldDefinitions = this._configJsonService.fieldDefinitions(schema); + this.objectObs.template.fieldNames = fieldNames; + this.objectObs.template.fieldNamesList = fieldNamesList; + this.objectObs.schema = schema; + this.objectObs.template.fieldLabels = fieldLabels; + this.objectObs.template.fieldDefinitions = fieldDefinitions; + this.objectObs.template.fieldNamesList = fieldNamesList; + this.objectObs.dataTable.colNameObj = Utils.toObject(fieldNamesList, fieldLabels); + }); } getSitesChild( @@ -85,37 +154,105 @@ export class SitesGroupService extends ApiGeomService { limit: number = 10, params: JsonData = {} ): Observable> { - return this._cacheService.request>>( - "get", - `sites`, - { - queryParams: { page, limit, ...params }, - } - ); + return this._cacheService.request>>('get', `sites`, { + queryParams: { page, limit, ...params }, + }); } addObjectType(): string { - return "un nouveau groupe de site"; + return 'un nouveau groupe de site'; } editObjectType(): string { - return "le groupe de site"; + return 'le groupe de site'; } } @Injectable() export class SitesService extends ApiGeomService { - constructor(_cacheService: CacheService) { - super(_cacheService); + constructor(_cacheService: CacheService, _configJsonService: ConfigJsonService) { + super(_cacheService, _configJsonService); } + opts = []; + init(): void { - this.objectType = endPoints.sites; + this.endPoint = endPoints.sites; + this.objectObs = { + properties: {}, + endPoint: endPoints.sites, + objectType: 'site', + label: 'site', + addObjLabel: 'Ajouter un nouveau site', + editObjLabel: 'Editer le site', + id: null, + moduleCode: 'generic', + schema: {}, + template: { + fieldNames: [], + fieldLabels: {}, + fieldNamesList: [], + fieldDefinitions: {}, + }, + dataTable: { colNameObj: {} }, + }; + this._configJsonService + .init(this.objectObs.moduleCode) + .pipe() + .subscribe(() => { + const fieldNames = this._configJsonService.configModuleObjectParam( + this.objectObs.moduleCode, + this.objectObs.objectType, + 'display_properties' + ); + //FIXME: same as site group: to refact + const fieldNamesList = this._configJsonService.configModuleObjectParam( + this.objectObs.moduleCode, + this.objectObs.objectType, + 'display_list' + ); + const schema = this._configJsonService.schema( + this.objectObs.moduleCode, + this.objectObs.objectType + ); + const fieldLabels = this._configJsonService.fieldLabels(schema); + const fieldDefinitions = this._configJsonService.fieldDefinitions(schema); + this.objectObs.template.fieldNames = fieldNames; + this.objectObs.template.fieldNamesList = fieldNamesList; + this.objectObs.schema = schema; + this.objectObs.template.fieldLabels = fieldLabels; + this.objectObs.template.fieldDefinitions = fieldDefinitions; + this.objectObs.template.fieldNamesList = fieldNamesList; + this.objectObs.dataTable.colNameObj = Utils.toObject(fieldNamesList, fieldLabels); + }); } + + // getTypeSites( + // ): Observable> { + // return this._cacheService.request>>( + // "get", + // "sites/types" + // ); + // } + + getTypeSites( + page: number = 1, + limit: number = 10, + params: JsonData = {} + ): Observable> { + return this._cacheService.request>>( + 'get', + 'sites/types/label', + { + queryParams: { page, limit, ...params }, + } + ); + } + addObjectType(): string { - return " un nouveau site"; + return ' un nouveau site'; } editObjectType(): string { - return "le site"; + return 'le site'; } } diff --git a/frontend/app/services/config-json.service.ts b/frontend/app/services/config-json.service.ts new file mode 100644 index 000000000..282910bd6 --- /dev/null +++ b/frontend/app/services/config-json.service.ts @@ -0,0 +1,60 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { ModuleService } from '@geonature/services/module.service'; +import { AppConfig } from '@geonature_config/app.config'; +import { of } from 'rxjs'; +import { ConfigService } from './config.service'; + + +@Injectable() +export class ConfigJsonService extends ConfigService { + + constructor(_http: HttpClient, _moduleService: ModuleService) { + super(_http, _moduleService) + } + + /** Configuration */ + + init(moduleCode: string) { + if (this._config && this._config[moduleCode]) { + return of(true); + } else { + return this.loadConfig(moduleCode); + } + } + + /** Backend Module Url */ + backendModuleUrl() { + // Test if api endpoint have a final slash + let api_url = AppConfig.API_ENDPOINT; + if (api_url.substring(api_url.length - 1, 1) !== '/') { + api_url = api_url + '/'; + } + return `${api_url}${this._moduleService.currentModule.module_path}`; + } + + fieldLabels(schema) { + const fieldLabels = {}; + for (const key of Object.keys(schema)) { + fieldLabels[key] = schema[key]['attribut_label']; + } + return fieldLabels; + } + + fieldNames(moduleCode, objectType, typeDisplay = '') { + if (['display_properties', 'display_list'].includes(typeDisplay)) { + return this.configModuleObjectParam(moduleCode, objectType, typeDisplay); + } + if (typeDisplay === 'schema') { + return Object.keys(this.schema(moduleCode, objectType)); + } + } + + fieldDefinitions(schema) { + const fieldDefinitions = {}; + for (const key of Object.keys(schema)) { + fieldDefinitions[key] = schema[key]['definition']; + } + return fieldDefinitions; + } +} diff --git a/frontend/app/services/config.service.ts b/frontend/app/services/config.service.ts index d010c95b1..985ec29df 100644 --- a/frontend/app/services/config.service.ts +++ b/frontend/app/services/config.service.ts @@ -7,17 +7,13 @@ import { ConfigService as GnConfigService } from '@geonature/services/config.ser @Injectable() export class ConfigService { - private _config; + protected _config; - constructor( - private _http: HttpClient, - private _moduleService: ModuleService, - public appConfig: GnConfigService - ) {} + constructor(protected _http: HttpClient, protected _moduleService: ModuleService, public appConfig: GnConfigService) {} /** Configuration */ - init(moduleCode = null) { + init(moduleCode: null | string = null) { // a definir ailleurs moduleCode = moduleCode || 'generic'; @@ -148,17 +144,17 @@ export class ConfigService { /** Config Object Schema */ schema(moduleCode, objectType, typeSchema = 'all'): Object { moduleCode = moduleCode || 'generic'; - const configObject = this._config[moduleCode][objectType]; // gerer quand les paramètres ont un fonction comme valeur - - for (const typeSchema of ['generic', 'specific']) { - for (const keyDef of Object.keys(configObject[typeSchema])) { - const formDef = configObject[typeSchema][keyDef]; - for (const keyParam of Object.keys(formDef)) { - const func = this.toFunction(formDef[keyParam]); - if (func) { - formDef[keyParam] = func; + if (configObject) { + for (const typeSchema of ['generic', 'specific']) { + for (const keyDef of Object.keys(configObject[typeSchema])) { + const formDef = configObject[typeSchema][keyDef]; + for (const keyParam of Object.keys(formDef)) { + const func = this.toFunction(formDef[keyParam]); + if (func) { + formDef[keyParam] = func; + } } } } diff --git a/frontend/app/services/data-table.service.ts b/frontend/app/services/data-table.service.ts index 8a76099ee..f4e28d72e 100644 --- a/frontend/app/services/data-table.service.ts +++ b/frontend/app/services/data-table.service.ts @@ -1,6 +1,7 @@ -import { Injectable } from "@angular/core"; -import { IColumn } from "../interfaces/column"; -import { BehaviorSubject} from "rxjs"; +import { Injectable } from '@angular/core'; + +import { IColumn } from '../interfaces/column'; + interface ItemObjectTable { id: number | null; selected: boolean; @@ -17,13 +18,11 @@ export class DataTableService { rowStatus: ItemObjectTable; idObj: number; - // IF prefered observable compare to ngOnChanges uncomment this: // dataCol:IColumn[] =[{prop:"",name:"",description:""}] // private dataCols = new BehaviorSubject(this.dataCol); // currentCols = this.dataCols.asObservable(); - constructor() {} // IF prefered observable compare to ngOnChanges uncomment this: @@ -39,7 +38,7 @@ export class DataTableService { // this.dataCols.next(allColumn) // } - colsTable(colName:IColumn[], dataTable): IColumn[] { + colsTable(colName: {}, dataTable): IColumn[] { const arr = Object.keys(colName); const allColumn: IColumn[] = arr .filter((item) => Object.keys(dataTable).includes(item)) diff --git a/frontend/app/services/edit-object.service.ts b/frontend/app/services/edit-object.service.ts deleted file mode 100644 index fc106678c..000000000 --- a/frontend/app/services/edit-object.service.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Injectable } from "@angular/core"; -import { BehaviorSubject, Observable, of, forkJoin } from "rxjs"; -import { concatMap } from "rxjs/operators"; - -import { JsonData } from "../types/jsondata"; - -import { Utils } from "../utils/utils"; -import { MonitoringObjectService } from "./monitoring-object.service"; - -@Injectable() -export class EditObjectService { - data: JsonData = {}; - private dataSub = new BehaviorSubject(this.data); - currentData = this.dataSub.asObservable(); - properties: JsonData; - moduleCode:string; - objecType:string; - - constructor( - private _objService:MonitoringObjectService - ) {} - - changeDataSub(newDat: JsonData) { - this.properties = newDat; - newDat.moduleCode = "generic"; - newDat.objectType = "sites_group"; - this.moduleCode= "generic"; - this.objecType= "sites_group" - this.dataSub.next(newDat) - - } - - - - formValues(obj): Observable { - const properties = Utils.copy(this.properties); - const observables = {}; - const schema = obj[this.moduleCode]; - for (const attribut_name of Object.keys(schema)) { - const elem = schema[attribut_name]; - if (!elem.type_widget) { - continue; - } - observables[attribut_name] = this._objService.toForm(elem, properties[attribut_name]); - } - - return forkJoin(observables).pipe( - concatMap((formValues_in) => { - const formValues = Utils.copy(formValues_in); - // geometry - // if (this.config["geometry_type"]) { - // formValues["geometry"] = this.geometry; // copy??? - // } - return of(formValues); - }) - ); - } -} diff --git a/frontend/app/services/form.service.ts b/frontend/app/services/form.service.ts new file mode 100644 index 000000000..0499fccad --- /dev/null +++ b/frontend/app/services/form.service.ts @@ -0,0 +1,105 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, Observable, forkJoin, of } from 'rxjs'; +import { concatMap } from 'rxjs/operators'; + +import { IobjObs, ObjDataType } from '../interfaces/objObs'; +import { ISite, ISitesGroup } from '../interfaces/geom'; +import { JsonData } from '../types/jsondata'; +import { Utils } from '../utils/utils'; +import { MonitoringObjectService } from './monitoring-object.service'; + +@Injectable() +export class FormService { + data: JsonData = {}; + private dataSub = new BehaviorSubject(this.data); + currentData = this.dataSub.asObservable(); + properties: JsonData = {}; + moduleCode: string; + objecType: string; + + constructor(private _objService: MonitoringObjectService) {} + + // TODO: voir si nécessaire de garder ça (objService permet d'avoir le bon objet ? et sinon modifier pour obtenir ce qu'il faut en formulaire) + changeDataSub(newDat: JsonData, objectType: string,endPoint:string,objSelected:IobjObs, moduleCode: string = 'generic') { + this.properties = newDat; + newDat.moduleCode = moduleCode; + newDat.objectType = objectType; + newDat.endPoint = endPoint; + newDat.objSelect = objSelected + this.dataSub.next(newDat); + } + + dataToCreate(newDat: JsonData, moduleCode: string = 'generic') { + newDat[moduleCode] = {}; + newDat.moduleCode = moduleCode; + this.dataSub.next(newDat); + } + + formValues(obj): Observable { + const properties = Utils.copy(this.properties); + const observables = {}; + const schema = obj[obj.moduleCode]; + for (const attribut_name of Object.keys(schema)) { + const elem = schema[attribut_name]; + if (!elem.type_widget) { + continue; + } + observables[attribut_name] = this._objService.toForm(elem, properties[attribut_name]); + } + + return forkJoin(observables).pipe( + concatMap((formValues_in) => { + const formValues = Utils.copy(formValues_in); + // geometry + // if (this.config["geometry_type"]) { + // formValues["geometry"] = this.geometry; // copy??? + // } + return of(formValues); + }) + ); + } + + // TODO: A voir si nécessaire d'utiliser le formatage des post et update data avant éxécution route coté backend + postData(formValue, obj): { properties: ISitesGroup | ISite | any } { + const propertiesData = {}; + const schema = obj[obj.moduleCode]; + for (const attribut_name of Object.keys(schema)) { + const elem = schema[attribut_name]; + if (!elem.type_widget) { + continue; + } + propertiesData[attribut_name] = this._objService.fromForm(elem, formValue[attribut_name]); + } + const postData = { properties: {} }; + if (obj.dataComplement == undefined) { + postData['properties'] = propertiesData; + } else { + postData['properties'] = propertiesData; + postData['dataComplement'] = obj.dataComplement; + } + + // Ajout des id relationship + if (obj.id_relationship != undefined) { + for (const [key, value] of Object.entries(obj.id_relationship)) { + if (typeof value == 'string') { + if (obj[value] != undefined) { + postData['properties'][value] = obj[value]; + } else if (Object.keys(obj.dataComplement).includes(value)) { + postData['properties'][value] = obj.dataComplement[value]; + } + } + } + } + + // properties: propertiesData, + // // id_parent: this.parentId + // }; + + // TODO: A voir q'il faut remettre + // if (this.config["geometry_type"]) { + // postData["geometry"] = formValue["geometry"]; + // postData["type"] = "Feature"; + // } + return postData; + } +} diff --git a/frontend/app/services/object.service.ts b/frontend/app/services/object.service.ts index c570f506c..58b183f7b 100644 --- a/frontend/app/services/object.service.ts +++ b/frontend/app/services/object.service.ts @@ -1,23 +1,53 @@ import { Injectable } from "@angular/core"; -import { BehaviorSubject } from "rxjs"; +import { BehaviorSubject,ReplaySubject } from "rxjs"; +import { endPoints } from "../enum/endpoints"; +import { ISitesGroup, ISiteType } from "../interfaces/geom"; +import { IobjObs, ObjDataType } from "../interfaces/objObs"; +import { JsonData } from "../types/jsondata"; + @Injectable() export class ObjectService { - objectType: string = ""; - private dataObjType = new BehaviorSubject(this.objectType); + objObs: IobjObs; + private objSelected = new ReplaySubject(1); + currentObjSelected = this.objSelected.asObservable(); + + private dataObjType = new ReplaySubject>(1); currentObjectType = this.dataObjType.asObservable(); - - objectTypeParent: string = ""; - private dataObjTypeParent = new BehaviorSubject(this.objectTypeParent); + + private dataObjTypeParent = new ReplaySubject>(1); currentObjectTypeParent = this.dataObjTypeParent.asObservable(); - constructor() {} + constructor() { + let storedObjectType = localStorage.getItem('storedObjectType'); + let storedObjectTypeParent = localStorage.getItem('storedObjectTypeParent'); + let storedObjectSelected= localStorage.getItem('storedObjectSelected'); + if (storedObjectType) + this.changeObjectType(JSON.parse(storedObjectType), false); + + if (storedObjectTypeParent) + this.changeObjectTypeParent(JSON.parse(storedObjectTypeParent), false); + + if (storedObjectSelected) + this.changeSelectedObj(JSON.parse(storedObjectSelected), false); +} + + + changeObjectType(newObjType: IobjObs,storeObjectType: boolean = false) { + if (storeObjectType) + localStorage.setItem('storedObjectType', JSON.stringify(newObjType)); + this.dataObjType.next(newObjType); + } - changeObjectType(newObjType: string) { - this.dataObjType.next(newObjType); + changeObjectTypeParent(newObjType: IobjObs,storeObjectTypeParent: boolean = false) { + if (storeObjectTypeParent) + localStorage.setItem('storedObjectTypeParent', JSON.stringify(newObjType)); + this.dataObjTypeParent.next(newObjType); } - changeObjectTypeParent(newObjType: string) { - this.dataObjTypeParent.next(newObjType); + changeSelectedObj(newObjSelected:ObjDataType , storeObjectTypeSelected: boolean = false ){ + if (storeObjectTypeSelected) + localStorage.setItem('storedObjectSelected', JSON.stringify(newObjSelected)); + this.objSelected.next(newObjSelected); } } diff --git a/frontend/app/utils/utils.ts b/frontend/app/utils/utils.ts index ef5e976b0..f0eb95d69 100644 --- a/frontend/app/utils/utils.ts +++ b/frontend/app/utils/utils.ts @@ -58,4 +58,12 @@ export class Utils { }); return dictOut; } + + static toObject(keys,values) { + const obj = keys.reduce((accumulator, key, index) => { + return {...accumulator, [key]: values[key]}; + }, {}); + + return obj; + } }