Support multiple merge requests per ticket
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
// @generated by yoi-companion-openapi-typescript@1. Do not edit.
|
||||
// Input: openapi/server-api.json
|
||||
// Input contract: 0.1.0 (sha256:80be292e32441730f7de890e64836f4ca9655576d655e60e6d44daf5227a1b1c)
|
||||
// Input contract: 0.1.0 (sha256:fbaf40391d4ab81b9ffb558ff4c055efb8c58e26b6a88d3eefbbbeefc6ea0822)
|
||||
// Options: companion-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
||||
// Output: web/workspace/src/lib/generated/companion-api.ts
|
||||
// Regenerate/check: cargo run -q -p server-api --example generate_companion_api_types -- --check
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @generated by yoi-repository-openapi-typescript@1. Do not edit.
|
||||
// Input: openapi/server-api.json
|
||||
// Input contract: 0.1.0 (sha256:a92b7346166ec2316878ef38b0426090cb4bdd0d5b96cae3014bef35c60df02a)
|
||||
// Input contract: 0.1.0 (sha256:fbaf40391d4ab81b9ffb558ff4c055efb8c58e26b6a88d3eefbbbeefc6ea0822)
|
||||
// Options: repository-operation-schema-closure,openapi-3.1,format:uint64=safe-number,strict-safe-integers,sorted-output
|
||||
// Output: web/workspace/src/lib/generated/repository-api.ts
|
||||
// Regenerate/check: cargo run -q -p server-api --example generate_repository_openapi_types -- --check
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @generated by yoi-runtime-openapi-typescript@1. Do not edit.
|
||||
// Input: openapi/server-api.json
|
||||
// Input contract: 0.1.0 (sha256:a92b7346166ec2316878ef38b0426090cb4bdd0d5b96cae3014bef35c60df02a)
|
||||
// Input contract: 0.1.0 (sha256:fbaf40391d4ab81b9ffb558ff4c055efb8c58e26b6a88d3eefbbbeefc6ea0822)
|
||||
// Options: runtime-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
||||
// Output: web/workspace/src/lib/generated/runtime-api.ts
|
||||
// Regenerate/check: cargo run -q -p server-api --example generate_runtime_api_types -- --check
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @generated by yoi-ticket-browser-openapi-typescript@1. Do not edit.
|
||||
// Input: openapi/server-api.json
|
||||
// Input contract: 0.1.0 (sha256:80be292e32441730f7de890e64836f4ca9655576d655e60e6d44daf5227a1b1c)
|
||||
// Input contract: 0.1.0 (sha256:fbaf40391d4ab81b9ffb558ff4c055efb8c58e26b6a88d3eefbbbeefc6ea0822)
|
||||
// Options: ticket-objective-merge-request-browser-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
||||
// Output: web/workspace/src/lib/generated/ticket-api.ts
|
||||
// Regenerate/check: cargo run -q -p server-api --example generate_ticket_api_types -- --check
|
||||
@@ -49,7 +49,7 @@ export type MergeRequestRefResponse = { diagnostic?: MergeRequestRefDiagnostic |
|
||||
|
||||
export type MergeRequestState = "open" | "merged" | "closed";
|
||||
|
||||
export type MergeRequestThreadEvent = { created_at: string; event_id: string; kind: "review_requested"; requested_by: MergeRequestWorkerIdentity; reviewer: MergeRequestWorkerIdentity; sequence: number; subject_ref: string; } | { body: string; created_at: string; decision: ReviewDecision; event_id: string; findings: Array<ReviewFinding>; kind: "review"; request_event_id: string; reviewer: MergeRequestWorkerIdentity; sequence: number; subject_ref: string; } | { created_at: string; event_id: string; kind: "review_revoked"; reason: string; review_event_id: string; revoked_by: MergeRequestWorkerIdentity; sequence: number; subject_ref: string; } | { created_at: string; event_id: string; kind: "review_cancelled"; reason: string; request_event_id: string; sequence: number; subject_ref: string; } | { author: MergeRequestWorkerIdentity; body: string; created_at: string; event_id: string; kind: "comment"; sequence: number; } | { approval_event_id: string; approved_source_ref: string; created_at: string; event_id: string; kind: "merge"; merged_by: MergeRequestWorkerIdentity; operation_id: string; resolution: ConflictResolution; sequence: number; strategy: MergeStrategy; target_ref_after: string; target_ref_before: string; };
|
||||
export type MergeRequestThreadEvent = { created_at: string; event_id: string; kind: "review_requested"; requested_by: MergeRequestWorkerIdentity; reviewer: MergeRequestWorkerIdentity; sequence: number; subject_ref: string; ticket_item_revision: string; } | { body: string; created_at: string; decision: ReviewDecision; event_id: string; findings: Array<ReviewFinding>; kind: "review"; request_event_id: string; reviewer: MergeRequestWorkerIdentity; sequence: number; subject_ref: string; ticket_item_revision: string; } | { created_at: string; event_id: string; kind: "review_revoked"; reason: string; review_event_id: string; revoked_by: MergeRequestWorkerIdentity; sequence: number; subject_ref: string; } | { created_at: string; event_id: string; kind: "review_cancelled"; reason: string; request_event_id: string; sequence: number; subject_ref: string; } | { author: MergeRequestWorkerIdentity; body: string; created_at: string; event_id: string; kind: "comment"; sequence: number; } | { approval_event_id: string; approved_source_ref: string; created_at: string; event_id: string; kind: "merge"; merged_by: MergeRequestWorkerIdentity; operation_id: string; resolution: ConflictResolution; sequence: number; strategy: MergeStrategy; target_ref_after: string; target_ref_before: string; };
|
||||
|
||||
export type MergeRequestWorkerIdentity = { runtime_id: string; worker_id: string; };
|
||||
|
||||
@@ -89,7 +89,7 @@ export type TicketAssignmentRole = "orchestrator" | "coder" | "owner" | "contrib
|
||||
|
||||
export type TicketAssignmentSummary = { assignment_id: string; runtime_id: string; worker_id: string; worker_resource_key?: string | null; };
|
||||
|
||||
export type TicketDetail = { action_eligibility: TicketActionEligibility; artifact_count: number; artifacts: Array<string>; assignment_diagnostics: Array<string>; assignments: Array<TicketRoleAssignmentSummary>; body: string; body_truncated: boolean; created_at?: string | null; current_coder?: TicketAssignmentSummary | null; event_count: number; event_page: QueryPage; events: Array<TicketEventDetail>; evidence: TicketEvidenceSummary; id: string; implementation_reports: Array<TicketEvidenceEvent>; item_revision: string; linked_objectives: Array<ObjectiveLinkSummary>; merge_request?: TicketMergeRequestSummary | null; priority: string; queued_at?: string | null; queued_by?: string | null; readiness?: string | null; record_source: string; relations: TicketDetailRelationView; resolution?: string | null; resource_key: string; risk_flags: Array<string>; state: string; targets: Array<TicketTarget>; title: string; updated_at?: string | null; };
|
||||
export type TicketDetail = { action_eligibility: TicketActionEligibility; artifact_count: number; artifacts: Array<string>; assignment_diagnostics: Array<string>; assignments: Array<TicketRoleAssignmentSummary>; body: string; body_truncated: boolean; created_at?: string | null; current_coder?: TicketAssignmentSummary | null; event_count: number; event_page: QueryPage; events: Array<TicketEventDetail>; evidence: TicketEvidenceSummary; id: string; implementation_reports: Array<TicketEvidenceEvent>; item_revision: string; linked_objectives: Array<ObjectiveLinkSummary>; merge_request?: TicketMergeRequestSummary | null; merge_requests: Array<TicketMergeRequestSummary>; priority: string; queued_at?: string | null; queued_by?: string | null; readiness?: string | null; record_source: string; relations: TicketDetailRelationView; resolution?: string | null; resource_key: string; risk_flags: Array<string>; state: string; targets: Array<TicketTarget>; title: string; updated_at?: string | null; };
|
||||
|
||||
export type TicketDetailDerivedRelation = { at: string; author: string; forward_kind: string; inverse_kind: string; note?: string | null; source_resource_key?: string | null; source_ticket: string; };
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @generated by yoi-worker-openapi-typescript@1. Do not edit.
|
||||
// Input: openapi/server-api.json
|
||||
// Input contract: 0.1.0 (sha256:a92b7346166ec2316878ef38b0426090cb4bdd0d5b96cae3014bef35c60df02a)
|
||||
// Input contract: 0.1.0 (sha256:fbaf40391d4ab81b9ffb558ff4c055efb8c58e26b6a88d3eefbbbeefc6ea0822)
|
||||
// Options: worker-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
||||
// Output: web/workspace/src/lib/generated/worker-launch-api.ts
|
||||
// Regenerate/check: cargo run -q -p server-api --example generate_worker_launch_api_types -- --check
|
||||
|
||||
@@ -712,6 +712,7 @@ export function parseTicketDetail(value: unknown): TicketDetail {
|
||||
"item_revision",
|
||||
"linked_objectives",
|
||||
"merge_request",
|
||||
"merge_requests",
|
||||
"priority",
|
||||
"queued_at",
|
||||
"queued_by",
|
||||
@@ -769,6 +770,11 @@ export function parseTicketDetail(value: unknown): TicketDetail {
|
||||
`${label}.linked_objectives`,
|
||||
parseObjectiveLink,
|
||||
),
|
||||
merge_requests: array(
|
||||
item.merge_requests,
|
||||
`${label}.merge_requests`,
|
||||
parseTicketMergeRequestSummary,
|
||||
),
|
||||
merge_request: item.merge_request === undefined
|
||||
? undefined
|
||||
: item.merge_request === null
|
||||
@@ -1082,7 +1088,17 @@ function parseMergeRequestThreadEvent(
|
||||
sequence: integer(item.sequence, `${label}.sequence`),
|
||||
};
|
||||
if (kind === "review_requested") {
|
||||
exact(item, [...base, "requested_by", "reviewer", "subject_ref"], label);
|
||||
exact(
|
||||
item,
|
||||
[
|
||||
...base,
|
||||
"requested_by",
|
||||
"reviewer",
|
||||
"subject_ref",
|
||||
"ticket_item_revision",
|
||||
],
|
||||
label,
|
||||
);
|
||||
return {
|
||||
...eventBase,
|
||||
kind,
|
||||
@@ -1092,6 +1108,10 @@ function parseMergeRequestThreadEvent(
|
||||
),
|
||||
reviewer: parseMergeRequestWorker(item.reviewer, `${label}.reviewer`),
|
||||
subject_ref: string(item.subject_ref, `${label}.subject_ref`),
|
||||
ticket_item_revision: string(
|
||||
item.ticket_item_revision,
|
||||
`${label}.ticket_item_revision`,
|
||||
),
|
||||
};
|
||||
}
|
||||
if (kind === "review") {
|
||||
@@ -1103,6 +1123,7 @@ function parseMergeRequestThreadEvent(
|
||||
"request_event_id",
|
||||
"reviewer",
|
||||
"subject_ref",
|
||||
"ticket_item_revision",
|
||||
], label);
|
||||
const decision = string(item.decision, `${label}.decision`);
|
||||
if (!["approve", "request_changes"].includes(decision)) {
|
||||
@@ -1120,6 +1141,10 @@ function parseMergeRequestThreadEvent(
|
||||
),
|
||||
reviewer: parseMergeRequestWorker(item.reviewer, `${label}.reviewer`),
|
||||
subject_ref: string(item.subject_ref, `${label}.subject_ref`),
|
||||
ticket_item_revision: string(
|
||||
item.ticket_item_revision,
|
||||
`${label}.ticket_item_revision`,
|
||||
),
|
||||
};
|
||||
}
|
||||
if (kind === "review_revoked") {
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
const loadedRepositories = $derived(data.repositories.data);
|
||||
|
||||
let ticket = $state<TicketDetail>(loadedTicket);
|
||||
const mergeRequest = $derived(ticket.merge_request);
|
||||
const mergeRequests = $derived(ticket.merge_requests);
|
||||
let editing = $state(false);
|
||||
let editTitle = $state(loadedTicket.title);
|
||||
let editBody = $state(loadedTicket.body);
|
||||
@@ -682,28 +682,32 @@
|
||||
</details>
|
||||
|
||||
<section class="ticket-control-card">
|
||||
<header><h2>Merge Request</h2></header>
|
||||
{#if mergeRequest}
|
||||
<p><strong>{mergeRequest.state}</strong></p>
|
||||
<p>
|
||||
From <code>{mergeRequest.selector_from ?? "requires repair"}</code>
|
||||
to <code>{mergeRequest.selector_to}</code>
|
||||
</p>
|
||||
{#if mergeRequest.current_subject_ref && mergeRequest.review_subject_ref === mergeRequest.current_subject_ref}
|
||||
<p><strong>Source review:</strong> {mergeRequest.review_status} for exact ref <code>{mergeRequest.current_subject_ref}</code></p>
|
||||
{:else if mergeRequest.current_subject_ref && mergeRequest.review_subject_ref}
|
||||
<p><strong>Fresh source review required:</strong> selector_from moved from <code>{mergeRequest.review_subject_ref}</code> to <code>{mergeRequest.current_subject_ref}</code>.</p>
|
||||
{:else if mergeRequest.current_subject_ref}
|
||||
<p><strong>Fresh source review required:</strong> no effective verdict exists for <code>{mergeRequest.current_subject_ref}</code>.</p>
|
||||
{:else}
|
||||
<p><strong>Source review unavailable:</strong> selector_from is unresolved.</p>
|
||||
{/if}
|
||||
<p><strong>Target integration:</strong> {mergeRequest.state === "merged" ? "recorded" : `awaiting Orchestrator integration into ${mergeRequest.selector_to}`}.</p>
|
||||
<p class="workspace-empty-copy">Target-only movement refreshes integration evidence; it does not invalidate approval for an unchanged source.</p>
|
||||
<a
|
||||
class="workspace-secondary-button"
|
||||
href={mergeRequestPagePath(data.workspaceId, mergeRequest.merge_request_id)}
|
||||
>Open Merge Request</a>
|
||||
<header><h2>Merge Requests</h2></header>
|
||||
{#if mergeRequests.length > 0}
|
||||
{#each mergeRequests as mergeRequest (mergeRequest.merge_request_id)}
|
||||
<article class="ticket-control-card">
|
||||
<p><strong>{mergeRequest.repository_key}: {mergeRequest.state}</strong></p>
|
||||
<p>
|
||||
From <code>{mergeRequest.selector_from ?? "requires repair"}</code>
|
||||
to <code>{mergeRequest.selector_to}</code>
|
||||
</p>
|
||||
{#if mergeRequest.current_subject_ref && mergeRequest.review_subject_ref === mergeRequest.current_subject_ref}
|
||||
<p><strong>Source review:</strong> {mergeRequest.review_status} for exact ref <code>{mergeRequest.current_subject_ref}</code></p>
|
||||
{:else if mergeRequest.current_subject_ref && mergeRequest.review_subject_ref}
|
||||
<p><strong>Fresh source review required:</strong> selector_from moved from <code>{mergeRequest.review_subject_ref}</code> to <code>{mergeRequest.current_subject_ref}</code>.</p>
|
||||
{:else if mergeRequest.current_subject_ref}
|
||||
<p><strong>Fresh source review required:</strong> no effective verdict exists for <code>{mergeRequest.current_subject_ref}</code>.</p>
|
||||
{:else}
|
||||
<p><strong>Source review unavailable:</strong> selector_from is unresolved.</p>
|
||||
{/if}
|
||||
<p><strong>Target integration:</strong> {mergeRequest.state === "merged" ? "recorded" : `awaiting Orchestrator integration into ${mergeRequest.selector_to}`}.</p>
|
||||
<p class="workspace-empty-copy">Target-only movement refreshes integration evidence; it does not invalidate approval for an unchanged source.</p>
|
||||
<a
|
||||
class="workspace-secondary-button"
|
||||
href={mergeRequestPagePath(data.workspaceId, mergeRequest.merge_request_id)}
|
||||
>Open Merge Request</a>
|
||||
</article>
|
||||
{/each}
|
||||
{:else}
|
||||
<p class="workspace-empty-copy">The assigned Coder has not opened a Merge Request.</p>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user