From 82e99ba71744f3dbb6db1042bf3d490df1f627c6 Mon Sep 17 00:00:00 2001 From: jeisenma Date: Mon, 16 Sep 2024 18:34:04 -0600 Subject: [PATCH 1/6] initial changes --- calliope_app/api/models/configuration.py | 21 ++- calliope_app/client/static/js/main.js | 135 ++++++++++-------- .../templates/technology_parameters.html | 21 ++- postgres/.gitkeep | 0 4 files changed, 114 insertions(+), 63 deletions(-) delete mode 100644 postgres/.gitkeep diff --git a/calliope_app/api/models/configuration.py b/calliope_app/api/models/configuration.py index bfee4a0e..884f7bf2 100644 --- a/calliope_app/api/models/configuration.py +++ b/calliope_app/api/models/configuration.py @@ -830,11 +830,30 @@ def duplicate(self, model_id, pretty_name): def update(self, form_data): """ Update the Technology parameters stored in Tech_Param """ + print("Update Data", form_data) METHODS = ['essentials', 'add', 'edit', 'delete'] for method in METHODS: if method in form_data.keys(): data = form_data[method] - getattr(Tech_Param, '_' + method)(self, data) + if method == 'essentials': + self._update_essentials(data) + elif method == 'add': + self._add_parameters(data) + elif method == 'edit': + if 'parameter_instance' in data: + for param_id, param_data in data['parameter_instance'].items(): + tech_param = Tech_Param.objects.get(id=param_id, technology=self) + if 'build_year_offset' in param_data: + tech_param.build_year_offset = param_data['build_year_offset'] + if 'year' in param_data: + tech_param.year = param_data['year'] + if 'value' in param_data: + tech_param.value = param_data['value'] + tech_param.save() + else: + self._edit_parameters(data) + elif method == 'delete': + self._delete_parameters(data) class Tech_Param(models.Model): diff --git a/calliope_app/client/static/js/main.js b/calliope_app/client/static/js/main.js index 82e27754..c388f96a 100644 --- a/calliope_app/client/static/js/main.js +++ b/calliope_app/client/static/js/main.js @@ -13,67 +13,76 @@ $(function() { $(this).slideUp(500); }); }); - function activate_table() { + $('.parameter-value.float-value').each(function() { + autocomplete_units(this); + }); + + // Detection of unsaved changes + $('.parameter-value-new, .parameter-value-existing, .parameter-year-existing, .parameter-build-year-offset-existing').unbind(); + $('.parameter-value-new, .parameter-value-existing, .parameter-year-existing, .parameter-build-year-offset-existing').on('focusout', function() { + if ($(this).val() == '') { $(this).val( $(this).data('value') ) }; + }); + $('.parameter-value-new, .parameter-value-existing, .parameter-year-existing, .parameter-build-year-offset-existing').on('change keyup paste', function() { + var row = $(this).parents('tr'), + year = row.find('.parameter-year').val(), + old_year = row.find('.parameter-year').data('value'), + build_year_offset = row.find('.parameter-build-year-offset').val(), + old_build_year_offset = row.find('.parameter-build-year-offset').data('value'), + value = row.find('.parameter-value').val(), + old_value = row.find('.parameter-value').data('value'), + param_id = $(this).parents('tr').data('param_id'), + ts_id = row.find('.parameter-value.timeseries').val(); + + // Convert to number if possible + if (+value) { value = +value }; + if (+old_value) { old_value = +old_value }; + if (+build_year_offset) { build_year_offset = +build_year_offset }; + if (+old_build_year_offset) { old_build_year_offset = +old_build_year_offset }; + + // If it is a timeseries: render the charts + if (ts_id) { + activate_charts(param_id, ts_id) + }; + + // Reset the formatting of row + row.find('.parameter-reset').addClass('hide') + row.find('.parameter-delete, .parameter-value-delete').removeClass('hide') + row.removeClass('table-warning'); + $(this).removeClass('invalid-value'); + + // Update Row based on Input + var update_val = (value != '') && (value != old_value), + update_year = (year != '') && (year != old_year), + update_build_year_offset = (build_year_offset != '') && (build_year_offset != old_build_year_offset); + + if (update_val && ($(this).hasClass('float-value') == true)) { + var units = row.find('.parameter-units').attr('data-value'), + val = convert_units(value, units); + if (typeof(val) == 'number') { + $(this).attr('data-target_value', formatNumber(val, false)); + row.find('.parameter-target-value').html(formatNumber(val, true)); + row.find('.parameter-reset').removeClass('hide') + row.find('.parameter-delete, .parameter-value-delete').addClass('hide') + row.addClass('table-warning'); + } else { + $(this).addClass('invalid-value'); + row.find('.parameter-target-value').html(row.find('.parameter-target-value').data('value')); + } + } else if (update_val || update_year || update_build_year_offset) { + row.find('.parameter-reset').removeClass('hide') + row.find('.parameter-delete, .parameter-value-delete').addClass('hide') + row.addClass('table-warning'); + } else { + row.find('.parameter-target-value').html(row.find('.parameter-target-value').data('value')); + } + check_unsaved(); + }); - $('.parameter-value.float-value').each(function() { - autocomplete_units(this); - }); - - // Detection of unsaved changes - $('.parameter-value-new, .parameter-value-existing, .parameter-year-existing').unbind(); - $('.parameter-value-new, .parameter-value-existing, .parameter-year-existing').on('focusout', function() { - if ($(this).val() == '') { $(this).val( $(this).data('value') ) }; - }); - $('.parameter-value-new, .parameter-value-existing, .parameter-year-existing').on('change keyup paste', function() { - var row = $(this).parents('tr'), - year = row.find('.parameter-year').val(), - old_year = row.find('.parameter-year').data('value'), - value = row.find('.parameter-value').val(), - old_value = row.find('.parameter-value').data('value'), - param_id = $(this).parents('tr').data('param_id'), - ts_id = row.find('.parameter-value.timeseries').val(); - // Convert to number if possible - if (+value) { value = +value }; - if (+old_value) { old_value = +old_value }; - // If it is a timeseries: render the charts - if (ts_id) { - activate_charts(param_id, ts_id) - }; - // Reset the formatting of row - row.find('.parameter-reset').addClass('hide') - row.find('.parameter-delete, .parameter-value-delete').removeClass('hide') - row.removeClass('table-warning'); - $(this).removeClass('invalid-value'); - - // Update Row based on Input - var update_val = (value != '') & (value != old_value), - update_year = (year != '') & (year != old_year); - if (update_val & ($(this).hasClass('float-value') == true)) { - var units = row.find('.parameter-units').attr('data-value'), - val = convert_units(value, units); - if (typeof(val) == 'number') { - $(this).attr('data-target_value', formatNumber(val, false)); - row.find('.parameter-target-value').html(formatNumber(val, true)); - row.find('.parameter-reset').removeClass('hide') - row.find('.parameter-delete, .parameter-value-delete').addClass('hide') - row.addClass('table-warning'); - } else { - $(this).addClass('invalid-value'); - row.find('.parameter-target-value').html(row.find('.parameter-target-value').data('value')); - } - } else if (update_val || update_year) { - row.find('.parameter-reset').removeClass('hide') - row.find('.parameter-delete, .parameter-value-delete').addClass('hide') - row.addClass('table-warning'); - } else { - row.find('.parameter-target-value').html(row.find('.parameter-target-value').data('value')); - } - check_unsaved(); - }); // Paste multiple values - activate_paste('.dynamic_value_input'); - activate_paste('.dynamic_year_input'); + activate_paste('.dynamic_value_input'); + activate_paste('.dynamic_year_input'); + activate_paste('.dynamic_build_year_offset_input'); // Reset parameter to saved value in database $('.parameter-reset').unbind(); @@ -168,9 +177,10 @@ function activate_table() { }); // Allow 'return' key to tab through input cells - activate_return('.static_inputs'); - activate_return('.dynamic_year_input'); - activate_return('.dynamic_value_input'); + activate_return('.static_inputs'); + activate_return('.dynamic_year_input'); + activate_return('.dynamic_build_year_offset_input'); + activate_return('.dynamic_value_input'); // Show and Hide the parameter rows $('.param_row_toggle').unbind(); @@ -1143,6 +1153,7 @@ function reconvert_all(load_flg){ } function activate_paste(class_name) { + console.log(class_name); $(class_name).bind('paste', null, function(e) { var values = e.originalEvent.clipboardData.getData('Text').split(/\s+/), $txt = $(this), @@ -1206,6 +1217,8 @@ function add_row($this) { row.find('.param_row_toggle').find('.view_rows').addClass('hide'); var add_row = $('.add_param_row_'+param_id).last().clone(); add_row.find('.parameter-value-new').addClass('dynamic_value_input'); + add_row.find('.parameter-build-year-offset-new').addClass('dynamic_build_year_offset_input'); + add_row.find('.parameter-year-new').addClass('dynamic_year_input'); add_row.removeClass('add_param_row_min').addClass('table-warning'); add_row.insertBefore($('.add_param_row_'+param_id).last()); diff --git a/calliope_app/client/templates/technology_parameters.html b/calliope_app/client/templates/technology_parameters.html index 26fd6b59..526a59b5 100644 --- a/calliope_app/client/templates/technology_parameters.html +++ b/calliope_app/client/templates/technology_parameters.html @@ -140,6 +140,7 @@ {% trans "This parameter is configured to evolve over multiple years" %}. {% trans "Year" %}: + {% trans "Build Offset Year" %}: {% trans "Value" %}: @@ -161,7 +162,19 @@ - + + + + {% if param.choices or param.parameter_is_carrier %} + + + {% if param.choices or param.parameter_is_carrier %} @@ -166,15 +167,14 @@ - - + {% if param.choices or param.parameter_is_carrier %} From f8c0d570d8f61bbadea5de98f2999d1e975e284c Mon Sep 17 00:00:00 2001 From: jeisenma Date: Wed, 18 Sep 2024 17:06:33 -0600 Subject: [PATCH 4/6] fixing comment --- calliope_app/api/models/configuration.py | 5 +-- calliope_app/api/views/configuration.py | 41 +++++++++++++++---- .../client/component_views/configuration.py | 3 -- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/calliope_app/api/models/configuration.py b/calliope_app/api/models/configuration.py index f8bcf600..dcfe7c3f 100644 --- a/calliope_app/api/models/configuration.py +++ b/calliope_app/api/models/configuration.py @@ -984,7 +984,6 @@ def _edit(cls, technology, data): timeseries=True) if 'parameter_instance' in data: instance_items = data['parameter_instance'].items() - print("instance_items ", instance_items) for key, value_dict in instance_items: parameter_instance = cls.objects.filter( model_id=technology.model_id, @@ -1125,7 +1124,6 @@ def _add(cls, loc_tech, data): clean_value, raw_value = value.split('||') else: clean_value = raw_value = value - new_objects.append(cls( model_id=loc_tech.model.id, loc_tech=loc_tech, @@ -1444,7 +1442,7 @@ def get_tech_params_dict(level, id, excl_ids=None, systemwide=True): if level in ['1_tech', '2_loc_tech']: values += ["year", "timeseries", "timeseries_meta_id", - "raw_value", "value"] + "raw_value", "value", "build_year_offset"] # System-Wide Handling if systemwide is False: @@ -1460,6 +1458,7 @@ def get_tech_params_dict(level, id, excl_ids=None, systemwide=True): 'id': param["id"] if 'id' in param.keys() else 0, 'level': level, 'year': param["year"] if 'year' in param.keys() else 0, + 'build_year_offset': param["build_year_offset"] if "build_year_offset" in param.keys() else 0, 'technology_id': technology.id, 'parameter_root': param["parameter__root"], 'parameter_category': param[parameter__category], diff --git a/calliope_app/api/views/configuration.py b/calliope_app/api/views/configuration.py index 53172c7a..781da48d 100644 --- a/calliope_app/api/views/configuration.py +++ b/calliope_app/api/views/configuration.py @@ -586,6 +586,35 @@ def delete_technology(request): return HttpResponse(json.dumps(payload), content_type="application/json") +def format_comment(full_name, data): + actions = [] + + # Process 'add' actions + if 'add' in data: + for key, value in data['add'].items(): + years = value['year'] + build_year_offsets = value['build_year_offset'] + values = value['value'] + for year, offset, val in zip(years, build_year_offsets, values): + formatted_val = val.replace("||", " or ") + actions.append(f"Added technology with build_year_offset {offset}, value {formatted_val}, year {year}") + if 'edit' in data: + if 'parameter_instance' in data['edit']: + edit_count = len(data['edit']['parameter_instance']) + if edit_count > 0: + actions.append(f"Edited {edit_count} parameter instance{'s' if edit_count > 1 else ''}") + if 'delete' in data: + if 'parameter_instance' in data['delete']: + delete_count = len(data['delete']['parameter_instance']) + if delete_count > 0: + actions.append(f"Deleted {delete_count} parameter instance{'s' if delete_count > 1 else ''}") + result = f"{full_name} performed the following actions:\n" + for action in actions: + result += f"* {action}\n" + + return result.strip() + + @csrf_protect def update_tech_params(request): """ @@ -607,19 +636,15 @@ def update_tech_params(request): technology_id = escape(request.POST["technology_id"]) form_data = json.loads(request.POST["form_data"]) escaped_form_data = recursive_escape(form_data) - + print("Escaped form data", escaped_form_data) model = Model.by_uuid(model_uuid) model.handle_edit_access(request.user) technology = model.technologies.filter(id=technology_id) - if len(technology) > 0: technology.first().update(escaped_form_data) - # Log Activity - comment = "{} updated the technology: {}.".format( - request.user.get_full_name(), - technology.first().pretty_name, - ) + comment = format_comment(request.user.get_full_name(), escaped_form_data) + # Change this: from what params to this... Move to _add request.user Model_Comment.objects.create(model=model, comment=comment, type="edit") model.notify_collaborators(request.user) model.deprecate_runs(technology_id=technology_id) @@ -862,6 +887,8 @@ def update_loc_tech_params(request): if len(loc_tech) > 0: loc_tech.first().update(form_data) # Log Activity + comment = format_comment(request.user.get_full_name(), form_data) + print(comment) comment = "{} updated the node: {} ({}) @ {}.".format( request.user.get_full_name(), loc_tech.first().technology.pretty_name, diff --git a/calliope_app/client/component_views/configuration.py b/calliope_app/client/component_views/configuration.py index 649f2b10..f650c6b9 100644 --- a/calliope_app/client/component_views/configuration.py +++ b/calliope_app/client/component_views/configuration.py @@ -158,9 +158,6 @@ def all_tech_params(request): for param in parameters: param['raw_units'] = param['units'] - tech_param = Tech_Param.objects.filter(id=param['id']).first() - build_year_offset = tech_param.build_year_offset if tech_param else None - param['build_year_offset'] = build_year_offset timeseries = Timeseries_Meta.objects.filter(model=model, failure=False, is_uploading=False) From 4953d9f5b634d12048895294976d3199ef93c96b Mon Sep 17 00:00:00 2001 From: jeisenma Date: Wed, 18 Sep 2024 17:07:50 -0600 Subject: [PATCH 5/6] removing print statements --- calliope_app/api/models/configuration.py | 1 - calliope_app/api/views/configuration.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/calliope_app/api/models/configuration.py b/calliope_app/api/models/configuration.py index dcfe7c3f..288b6ded 100644 --- a/calliope_app/api/models/configuration.py +++ b/calliope_app/api/models/configuration.py @@ -831,7 +831,6 @@ def duplicate(self, model_id, pretty_name): def update(self, form_data): """ Update the Technology parameters stored in Tech_Param """ METHODS = ['essentials', 'add', 'edit', 'delete'] - print(form_data) for method in METHODS: if method in form_data.keys(): data = form_data[method] diff --git a/calliope_app/api/views/configuration.py b/calliope_app/api/views/configuration.py index 781da48d..ce8425fe 100644 --- a/calliope_app/api/views/configuration.py +++ b/calliope_app/api/views/configuration.py @@ -636,7 +636,6 @@ def update_tech_params(request): technology_id = escape(request.POST["technology_id"]) form_data = json.loads(request.POST["form_data"]) escaped_form_data = recursive_escape(form_data) - print("Escaped form data", escaped_form_data) model = Model.by_uuid(model_uuid) model.handle_edit_access(request.user) @@ -888,7 +887,6 @@ def update_loc_tech_params(request): loc_tech.first().update(form_data) # Log Activity comment = format_comment(request.user.get_full_name(), form_data) - print(comment) comment = "{} updated the node: {} ({}) @ {}.".format( request.user.get_full_name(), loc_tech.first().technology.pretty_name, From 6d1c28351a2de3837330d494a539dbf00d64e0dc Mon Sep 17 00:00:00 2001 From: jeisenma Date: Wed, 23 Oct 2024 13:51:18 -0600 Subject: [PATCH 6/6] remove log statement --- calliope_app/client/static/js/main.js | 1 - 1 file changed, 1 deletion(-) diff --git a/calliope_app/client/static/js/main.js b/calliope_app/client/static/js/main.js index 27050e75..1f2ec73a 100644 --- a/calliope_app/client/static/js/main.js +++ b/calliope_app/client/static/js/main.js @@ -1164,7 +1164,6 @@ function reconvert_all(load_flg){ } function activate_paste(class_name) { - console.log(class_name); $(class_name).bind('paste', null, function(e) { var values = e.originalEvent.clipboardData.getData('Text').split(/\s+/), $txt = $(this),