diff --git a/tcms/rpc/api/testcase.py b/tcms/rpc/api/testcase.py
index b1a6f4ea26..2eb3849880 100644
--- a/tcms/rpc/api/testcase.py
+++ b/tcms/rpc/api/testcase.py
@@ -3,6 +3,7 @@
from datetime import timedelta
from django.contrib.auth import get_user_model
+from django.db.models import OuterRef, Subquery
from django.db.models.functions import Coalesce
from django.forms import EmailField, ValidationError
from django.forms.models import model_to_dict
@@ -271,12 +272,18 @@ def filter(query=None): # pylint: disable=redefined-builtin
qs = (
TestCase.objects.annotate(
expected_duration=Coalesce("setup_duration", timedelta(0))
- + Coalesce("testing_duration", timedelta(0))
+ + Coalesce("testing_duration", timedelta(0)),
+ last_modified=Subquery(
+ TestCase.history.model.objects.filter(id=OuterRef("pk"))
+ .order_by("-history_date")
+ .values("history_date")[:1]
+ ),
)
.filter(**query)
.values(
"id",
"create_date",
+ "last_modified",
"is_automated",
"script",
"arguments",
diff --git a/tcms/rpc/api/testplan.py b/tcms/rpc/api/testplan.py
index 512169d71d..fc512fe907 100644
--- a/tcms/rpc/api/testplan.py
+++ b/tcms/rpc/api/testplan.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-from django.db.models import Count
+from django.db.models import Count, OuterRef, Subquery
from django.forms.models import model_to_dict
from modernrpc.core import REQUEST_KEY, rpc_method
@@ -88,12 +88,20 @@ def filter(query=None): # pylint: disable=redefined-builtin
query = {}
return list(
- TestPlan.objects.filter(**query)
+ TestPlan.objects.annotate(
+ last_modified=Subquery(
+ TestPlan.history.model.objects.filter(id=OuterRef("pk"))
+ .order_by("-history_date")
+ .values("history_date")[:1]
+ ),
+ )
+ .filter(**query)
.values(
"id",
"name",
"text",
"create_date",
+ "last_modified",
"is_active",
"extra_link",
"product_version",
diff --git a/tcms/testcases/static/testcases/js/search.js b/tcms/testcases/static/testcases/js/search.js
index 010b392a3d..eb2c5eb93c 100644
--- a/tcms/testcases/static/testcases/js/search.js
+++ b/tcms/testcases/static/testcases/js/search.js
@@ -157,6 +157,7 @@ export function pageTestcasesSearchReadyHandler () {
}
},
{ data: 'create_date' },
+ { data: 'last_modified' },
{ data: 'category__name' },
{ data: 'component_names' },
{ data: 'priority__value' },
diff --git a/tcms/testcases/templates/testcases/get.html b/tcms/testcases/templates/testcases/get.html
index 8665371a95..250ba6ef21 100644
--- a/tcms/testcases/templates/testcases/get.html
+++ b/tcms/testcases/templates/testcases/get.html
@@ -69,6 +69,11 @@
{{ object.create_date }}
+
+ {% trans 'Last modified' %}:
+ {{ last_modified }}
+
+
{% trans 'Setup duration' %}:
{{ object.setup_duration|default:"-" }}
diff --git a/tcms/testcases/templates/testcases/search.html b/tcms/testcases/templates/testcases/search.html
index 1cf000552b..085e8605c7 100644
--- a/tcms/testcases/templates/testcases/search.html
+++ b/tcms/testcases/templates/testcases/search.html
@@ -165,6 +165,7 @@
| {% trans "ID" %} |
{% trans "Summary" %} |
{% trans "Created on" %} |
+ {% trans "Last modified" %} |
{% trans "Category" %} |
{% trans "Component" %} |
{% trans "Priority" %} |
diff --git a/tcms/testcases/views.py b/tcms/testcases/views.py
index 64c26365ed..28e32eed68 100644
--- a/tcms/testcases/views.py
+++ b/tcms/testcases/views.py
@@ -125,6 +125,11 @@ def get_context_data(self, **kwargs):
context["executions"] = self.object.executions.select_related(
"run", "tested_by", "assignee", "case", "status"
).order_by("run__plan", "run")
+ context["last_modified"] = (
+ self.object.history.latest().history_date
+ if self.object.history.exists()
+ else self.object.create_date
+ )
context["OBJECT_MENU_ITEMS"] = [
(
"...",
diff --git a/tcms/testplans/static/testplans/js/search.js b/tcms/testplans/static/testplans/js/search.js
index e3e9270889..50caf05ff1 100644
--- a/tcms/testplans/static/testplans/js/search.js
+++ b/tcms/testplans/static/testplans/js/search.js
@@ -117,6 +117,7 @@ export function pageTestplansSearchReadyHandler () {
}
},
{ data: 'create_date' },
+ { data: 'last_modified' },
{ data: 'product__name' },
{ data: 'product_version__value' },
{ data: 'type__name' },
diff --git a/tcms/testplans/templates/testplans/get.html b/tcms/testplans/templates/testplans/get.html
index a994e89dd7..8a890fad7a 100644
--- a/tcms/testplans/templates/testplans/get.html
+++ b/tcms/testplans/templates/testplans/get.html
@@ -59,6 +59,11 @@
{{ object.create_date }}
+
+ {% trans 'Last modified' %}:
+ {{ last_modified }}
+
+
{% trans 'Product' %}:
diff --git a/tcms/testplans/templates/testplans/search.html b/tcms/testplans/templates/testplans/search.html
index 2766146842..443693e37f 100644
--- a/tcms/testplans/templates/testplans/search.html
+++ b/tcms/testplans/templates/testplans/search.html
@@ -116,6 +116,7 @@
| {% trans "ID" %} |
{% trans "Test plan" %} |
{% trans "Created on" %} |
+ {% trans "Last modified" %} |
{% trans "Product" %} |
{% trans "Version" %} |
{% trans "Type" %} |
diff --git a/tcms/testplans/views.py b/tcms/testplans/views.py
index 10e66a703a..a676a69066 100644
--- a/tcms/testplans/views.py
+++ b/tcms/testplans/views.py
@@ -136,6 +136,11 @@ def get_context_data(self, **kwargs):
context["test_runs"] = TestRun.objects.filter(
plan_id=self.object.pk, stop_date__isnull=True
).order_by("-id")[:5]
+ context["last_modified"] = (
+ self.object.history.latest().history_date
+ if self.object.history.exists()
+ else self.object.create_date
+ )
context["OBJECT_MENU_ITEMS"] = [
(
"...",