@@ -868,10 +868,67 @@
868 868 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
869 869 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return redirect("fossil:tickets", slug=slug)
870 870 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
871 871 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return render(request, "fossil/ticket_form.html", {"project": project, "active_tab": "tickets", "title": "New Ticket"})
872 872 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
873 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
874 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @login_required
875 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def ticket_edit(request, slug, ticket_uuid):
876 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ P.PROJECT_CHANGE.check(request.user)
877 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ project, fossil_repo, reader = _get_repo_and_reader(slug)
878 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
879 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with reader:
880 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ticket = reader.get_ticket_detail(ticket_uuid)
881 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if not ticket:
882 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ raise Http404("Ticket not found")
883 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
884 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if request.method == "POST":
885 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from fossil.cli import FossilCLI
886 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
887 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ cli = FossilCLI()
888 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ fields = {}
889 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ for field in ["title", "status", "type", "severity", "priority", "resolution", "subsystem"]:
890 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ val = request.POST.get(field, "").strip()
891 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if val:
892 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ fields[field] = val
893 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if fields:
894 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ success = cli.ticket_change(fossil_repo.full_path, ticket.uuid, fields)
895 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if success:
896 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from django.contrib import messages
897 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
898 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ messages.success(request, f'Ticket "{ticket.title}" updated.')
899 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from django.shortcuts import redirect
900 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
901 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ return redirect("fossil:ticket_detail", slug=slug, ticket_uuid=ticket.uuid)
902 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
903 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ return render(
904 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ request,
905 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "fossil/ticket_edit.html",
906 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ {"project": project, "ticket": ticket, "active_tab": "tickets"},
907 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ )
908 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
909 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
910 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @login_required
911 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def ticket_comment(request, slug, ticket_uuid):
912 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ P.PROJECT_CHANGE.check(request.user)
913 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ project, fossil_repo, reader = _get_repo_and_reader(slug)
914 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
915 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if request.method == "POST":
916 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ comment = request.POST.get("comment", "").strip()
917 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if comment:
918 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from fossil.cli import FossilCLI
919 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
920 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ cli = FossilCLI()
921 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ success = cli.ticket_change(fossil_repo.full_path, ticket_uuid, {"icomment": comment})
922 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if success:
923 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from django.contrib import messages
924 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
925 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ messages.success(request, "Comment added.")
926 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from django.shortcuts import redirect
927 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
928 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ return redirect("fossil:ticket_detail", slug=slug, ticket_uuid=ticket_uuid)
929 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
873 930 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
874 931 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# --- User Activity ---
875 932 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
876 933 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
877 934 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
@login_required
@@ -1479,10 +1536,28 @@
1479 1536 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
parent_idx = rid_to_idx[entry.parent_rid]
1480 1537 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
if parent_idx > i:
1481 1538 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
rail = max(entry.rail, 0)
1482 1539 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
active_spans.append((rail, i, parent_idx))
1483 1540 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
1541 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # Precompute connectors: for each row, collect all horizontal connections
1542 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # A connector appears when a child on one rail connects to a parent on a different rail
1543 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # We draw the connector at BOTH the child row (fork out) and on every row where
1544 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # a branch line needs to cross from one rail to another
1545 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ row_connectors: dict[int, list[dict]] = {}
1546 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ for entry in entries:
1547 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if entry.event_type != "ci" or entry.parent_rid not in rid_to_idx:
1548 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ continue
1549 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ parent_idx = rid_to_idx[entry.parent_rid]
1550 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ child_rail = max(entry.rail, 0)
1551 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ parent_rail = rid_to_rail.get(entry.parent_rid, 0)
1552 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if child_rail != parent_rail:
1553 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ child_x = rail_offset + child_rail * rail_pitch
1554 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ parent_x = rail_offset + parent_rail * rail_pitch
1555 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ conn = {"left": min(child_x, parent_x), "width": abs(child_x - parent_x)}
1556 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # Draw at the parent's row (where branch meets trunk)
1557 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ row_connectors.setdefault(parent_idx, []).append(conn)
1558 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
1484 1559 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
result = []
1485 1560 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
for i, entry in enumerate(entries):
1486 1561 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
rail = max(entry.rail, 0) if entry.rail >= 0 else 0
1487 1562 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
node_x = rail_offset + rail * rail_pitch
1488 1563 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
@@ -1491,31 +1566,18 @@
1491 1566 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
for span_rail, span_start, span_end in active_spans:
1492 1567 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
if span_start <= i <= span_end:
1493 1568 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
active_rails.add(span_rail)
1494 1569 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
1495 1570 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
lines = [{"x": rail_offset + r * rail_pitch} for r in sorted(active_rails)]
1496 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
1497 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- # Fork/merge connector: if this entry's parent is on a different rail,
1498 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- # draw a horizontal connector at the parent's row (where the line joins)
1499 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- connector = None
1500 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- if entry.event_type == "ci" and entry.parent_rid in rid_to_idx:
1501 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- parent_idx = rid_to_idx[entry.parent_rid]
1502 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- parent_rail = rid_to_rail.get(entry.parent_rid, 0)
1503 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- if parent_rail != rail and parent_idx == i + 1:
1504 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- # Connector at this row going to parent's rail
1505 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- parent_x = rail_offset + parent_rail * rail_pitch
1506 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- connector = {
1507 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- "left": min(node_x, parent_x),
1508 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- "width": abs(node_x - parent_x),
1509 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- }
1571 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ connectors = row_connectors.get(i, [])
1510 1572 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
1511 1573 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
result.append(
1512 1574 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
{
1513 1575 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
"entry": entry,
1514 1576 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
"node_x": node_x,
1515 1577 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
"lines": lines,
1516 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- "connector": connector,
1578 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "connectors": connectors,
1517 1579 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
"graph_width": graph_width,
1518 1580 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
1519 1581 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
)
1520 1582 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
1521 1583 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return result
1522 1584 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!