From 7733c07430f6f2089d6d2cf226b407f85b80f8bd Mon Sep 17 00:00:00 2001 From: Leo Scholl Date: Mon, 27 Jul 2026 14:11:24 -0700 Subject: [PATCH] fix disable behavior --- db/tracker/ajax.py | 35 ++++++++++++++++++------ db/tracker/templates/setup_base.html | 2 +- db/tracker/templates/setup_features.html | 15 ++++++---- db/tracker/views.py | 5 ++-- 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/db/tracker/ajax.py b/db/tracker/ajax.py index 51ecd156e..928bcd6ac 100644 --- a/db/tracker/ajax.py +++ b/db/tracker/ajax.py @@ -572,15 +572,22 @@ def toggle_features(request): from . import models name = request.POST.get('name') - + # check if the feature is already installed - existing_features = Feature.objects.filter(name=name) + existing_features = Feature.objects.filter(name=name).order_by('id') if len(existing_features) > 0: - # disable the feature - Feature.objects.filter(name=name).delete() - msg = "Disabled feature: %s" % str(name) - return _respond(dict(msg=msg, status="success")) + if existing_features.filter(visible=True).exists(): + # Soft-disable the feature so historical task links remain intact. + existing_features.filter(visible=True).update(visible=False) + msg = "Disabled feature: %s" % str(name) + return _respond(dict(msg=msg, status="success")) + + # Re-enable an existing hidden feature instead of creating a new row. + existing_features.update(visible=True) + feat = existing_features[0] + msg = "Enabled feature: %s" % str(feat.name) + return _respond(dict(msg=msg, status="success", id=feat.id)) elif name in built_in_features: import_path = built_in_features[name].__module__ + '.' + built_in_features[name].__qualname__ feat = Feature(name=name, import_path=import_path) @@ -604,11 +611,21 @@ def add_new_feature(request): traceback.print_exc() return _respond(dict(msg="import path invalid!", status="error")) - feat = Feature(name=name, import_path=import_path) - feat.save() + existing_feature = Feature.objects.filter(name=name).order_by('id').first() + if existing_feature is not None: + # Re-use an existing row to avoid duplicate feature names. + existing_feature.import_path = import_path + existing_feature.visible = True + existing_feature.save() + feat = existing_feature + msg = "Updated existing feature: %s" % feat.name + else: + feat = Feature(name=name, import_path=import_path) + feat.save() + msg = "Added new feature: %s" % feat.name feature_data = dict(id=feat.id, name=feat.name, import_path=feat.import_path) - return _respond(dict(msg="Added new feature: %s" % feat.name, status="success", data=feature_data)) + return _respond(dict(msg=msg, status="success", data=feature_data)) @csrf_exempt def setup_run_upkeep(request): diff --git a/db/tracker/templates/setup_base.html b/db/tracker/templates/setup_base.html index dcbdf137c..dd1b4a821 100644 --- a/db/tracker/templates/setup_base.html +++ b/db/tracker/templates/setup_base.html @@ -191,7 +191,7 @@ // add new row to table tr = $(document.createElement("tr")); tr.html("" + resp["data"].id + "" + "" + resp["data"].name + "" + "" + - "" + ""); + "" + ""); $('#new-feature-row').after(tr); } }) diff --git a/db/tracker/templates/setup_features.html b/db/tracker/templates/setup_features.html index 34da12f35..550711053 100644 --- a/db/tracker/templates/setup_features.html +++ b/db/tracker/templates/setup_features.html @@ -22,11 +22,16 @@

Features

{{feature.id}} {{feature.name}} - {% if not feature.name in built_in_feature_names %} - - {% else %} - - {% endif %} + + + {% endfor %} + + + {% for feature in hidden_custom_features %} + + {{feature.id}} + {{feature.name}} + {% endfor %} diff --git a/db/tracker/views.py b/db/tracker/views.py index 5cc7c7b2a..4f0ac91f6 100644 --- a/db/tracker/views.py +++ b/db/tracker/views.py @@ -221,15 +221,16 @@ def setup_features(request): from . import models from .models import TaskEntry, Task, Subject, Feature, Generator - features = models.Feature.objects.all() - # populate the list of built-in features which could be added from features import built_in_features built_in_feature_names = list(built_in_features.keys()) + features = models.Feature.objects.filter(visible=True).order_by("name") + hidden_custom_features = models.Feature.objects.filter(visible=False).exclude(name__in=built_in_feature_names).order_by("name") return render(request, "setup_features.html", dict(active_features=features, active_feature_names=[feature.name for feature in features], + hidden_custom_features=hidden_custom_features, built_in_feature_names=built_in_feature_names, test_db=os.environ.get('BMI3D_TEST_DATABASE')))