fix(jira,tests): send real datetime to RT/BT date fields, resolve assignee usernames for operators
Aegis CI / lint-and-test (push) Has been cancelled
Snyk Security Scan / Python vulnerabilities (backend) (push) Has been cancelled
Snyk Security Scan / npm vulnerabilities (frontend) (push) Has been cancelled
Snyk Security Scan / Docker image vulnerabilities (backend) (push) Has been cancelled

- RT/BT Start/End Date are genuine Jira "datetime" custom fields (confirmed
  via issue_editmeta), not plain dates. Pushing a bare "YYYY-MM-DD" string
  made Jira default the time-of-day to midnight, so RT Start Date and RT
  End Date ended up showing the same meaningless midnight timestamp instead
  of the actual execution window. Now sends a full ISO datetime.
- The test detail page showed "RT: Unassigned" for the operator who WAS
  correctly assigned, because GET /users/operators (the only source
  AssigneeControl used to resolve an assignee ID into a username) is
  restricted to leads/managers — a plain operator has no other way to
  resolve their own ID. TestOut now resolves and includes the assignee's
  username directly (red/blue tech + reviewer), so the badge no longer
  depends on a permission-gated list the viewer might not have access to.
This commit is contained in:
kitos
2026-07-13 16:53:31 +02:00
parent 4221d2858b
commit 6d6f87b968
8 changed files with 128 additions and 9 deletions
@@ -15,6 +15,12 @@ interface Props {
* techs+leads. "reviewer" = red_reviewer_assignee/blue_reviewer_assignee,
* picking from leads only — for handing a review off to a peer lead. */
kind?: "operator" | "reviewer";
/** Resolved username from the API. `operators` is only fetched for
* leads/managers (GET /users/operators is permission-gated), so a plain
* operator viewing their own test can't resolve assigneeId -> name from
* that list — this is the fallback so the badge doesn't misreport
* "Unassigned" just because the picker data isn't available to them. */
assigneeUsername?: string | null;
}
const SIDE_STYLE = {
@@ -41,10 +47,11 @@ const LABEL_PREFIX: Record<"operator" | "reviewer", Record<"red" | "blue", strin
/** Lead/manager picker for operator assignment or reviewer hand-off. */
export default function AssigneeControl({
side, assigneeId, operators, canEdit, isSaving, onAssign, size = "sm", kind = "operator",
assigneeUsername,
}: Props) {
const [expanded, setExpanded] = useState(false);
const current = operators.find((o) => o.id === assigneeId);
const label = current ? current.username : "Unassigned";
const label = current?.username ?? (assigneeId ? assigneeUsername ?? "Unassigned" : "Unassigned");
const eligible = operators.filter((o) => ELIGIBLE_ROLES[kind][side].includes(o.role));
const sideLabel = LABEL_PREFIX[kind][side];
@@ -559,6 +559,7 @@ export default function TestDetailHeader({
side="red"
kind="reviewer"
assigneeId={test.red_reviewer_assignee}
assigneeUsername={test.red_reviewer_assignee_username}
operators={operators}
canEdit={role === "red_lead" || role === "manager"}
isSaving={isAssigningOperator}
@@ -571,6 +572,7 @@ export default function TestDetailHeader({
side="blue"
kind="reviewer"
assigneeId={test.blue_reviewer_assignee}
assigneeUsername={test.blue_reviewer_assignee_username}
operators={operators}
canEdit={role === "blue_lead" || role === "manager"}
isSaving={isAssigningOperator}
@@ -581,6 +583,7 @@ export default function TestDetailHeader({
<AssigneeControl
side="red"
assigneeId={test.red_tech_assignee}
assigneeUsername={test.red_tech_assignee_username}
operators={operators}
canEdit={role === "red_lead" || role === "manager"}
isSaving={isAssigningOperator}
@@ -590,6 +593,7 @@ export default function TestDetailHeader({
<AssigneeControl
side="blue"
assigneeId={test.blue_tech_assignee}
assigneeUsername={test.blue_tech_assignee_username}
operators={operators}
canEdit={role === "blue_lead" || role === "manager"}
isSaving={isAssigningOperator}
+4
View File
@@ -134,6 +134,8 @@ export interface Test {
// Assignment fields
red_tech_assignee: string | null;
blue_tech_assignee: string | null;
red_tech_assignee_username: string | null;
blue_tech_assignee_username: string | null;
// Red Team review fields
red_reviewer_assignee: string | null;
@@ -146,6 +148,8 @@ export interface Test {
blue_review_by: string | null;
blue_review_at: string | null;
blue_review_notes: string | null;
red_reviewer_assignee_username: string | null;
blue_reviewer_assignee_username: string | null;
system_gaps: string | null;
// On-hold fields