diff --git a/app/Actions/Tickets/StoreProjectTicketLink.php b/app/Actions/Tickets/StoreProjectTicketLink.php
index 71d3719..1cf6422 100644
--- a/app/Actions/Tickets/StoreProjectTicketLink.php
+++ b/app/Actions/Tickets/StoreProjectTicketLink.php
@@ -17,18 +17,21 @@ class StoreProjectTicketLink
) {}
/**
- * @param array{linked_ticket_id: int, ticket_link_type_id: int} $validated
+ * @param array{linked_ticket_id: int, ticket_link_type_id: int, link_direction?: 'source'|'counterpart'} $validated
*/
public function handle(Project $project, Ticket $ticket, User $user, array $validated): TicketLink
{
$linkedTicketId = Arr::get($validated, 'linked_ticket_id');
$ticketLinkTypeId = Arr::get($validated, 'ticket_link_type_id');
+ $isSourceTicket = Arr::get($validated, 'link_direction', 'source') === 'source';
$linkedTicket = Ticket::query()
->where('project_id', $project->id)
->findOrFail($linkedTicketId);
+ $sourceTicket = $isSourceTicket ? $ticket : $linkedTicket;
+ $targetTicket = $isSourceTicket ? $linkedTicket : $ticket;
- return DB::transaction(function () use ($linkedTicket, $user, $ticketLinkTypeId, $ticket): TicketLink {
+ return DB::transaction(function () use ($linkedTicket, $user, $ticketLinkTypeId, $ticket, $sourceTicket, $targetTicket, $isSourceTicket): TicketLink {
Ticket::query()
->whereKey([$ticket->id, $linkedTicket->id])
->orderBy('id')
@@ -50,31 +53,31 @@ class StoreProjectTicketLink
if ($ticketLink === null) {
$ticketLink = TicketLink::query()->create([
- 'source_ticket_id' => $ticket->id,
- 'target_ticket_id' => $linkedTicket->id,
+ 'source_ticket_id' => $sourceTicket->id,
+ 'target_ticket_id' => $targetTicket->id,
'ticket_link_type_id' => $ticketLinkTypeId,
]);
} else {
$ticketLink->update([
- 'source_ticket_id' => $ticket->id,
- 'target_ticket_id' => $linkedTicket->id,
+ 'source_ticket_id' => $sourceTicket->id,
+ 'target_ticket_id' => $targetTicket->id,
'ticket_link_type_id' => $ticketLinkTypeId,
]);
}
$ticketLink->load('ticketLinkType');
- $sourceLabel = $ticketLink->ticketLinkType->labelForSource(true);
- $targetLabel = $ticketLink->ticketLinkType->labelForSource(false);
+ $ticketLabel = $ticketLink->ticketLinkType->labelForSource($isSourceTicket);
+ $linkedTicketLabel = $ticketLink->ticketLinkType->labelForSource(! $isSourceTicket);
$this->createTicketWorklogEntry->handle(
$ticket,
$user,
TicketWorklogEntryType::LinkUpdated,
- "Linked {$linkedTicket->ticket_key} as {$sourceLabel}.",
+ "Linked {$linkedTicket->ticket_key} as {$ticketLabel}.",
[
'linked_ticket_key' => $linkedTicket->ticket_key,
- 'ticket_link_type' => $sourceLabel,
+ 'ticket_link_type' => $ticketLabel,
],
);
@@ -82,10 +85,10 @@ class StoreProjectTicketLink
$linkedTicket,
$user,
TicketWorklogEntryType::LinkUpdated,
- "Linked {$ticket->ticket_key} as {$targetLabel}.",
+ "Linked {$ticket->ticket_key} as {$linkedTicketLabel}.",
[
'linked_ticket_key' => $ticket->ticket_key,
- 'ticket_link_type' => $targetLabel,
+ 'ticket_link_type' => $linkedTicketLabel,
],
);
diff --git a/app/Http/Controllers/Api/ProjectTicketLinkController.php b/app/Http/Controllers/Api/ProjectTicketLinkController.php
index 6555afd..1fa4eb4 100644
--- a/app/Http/Controllers/Api/ProjectTicketLinkController.php
+++ b/app/Http/Controllers/Api/ProjectTicketLinkController.php
@@ -36,11 +36,12 @@ class ProjectTicketLinkController extends ApiController
$ticketLink = $this->storeProjectTicketLink->handle($project, $ticket, $user, $request->validated());
$ticketLink->setAttribute('current_ticket_id', $ticket->id);
+ $label = $ticketLink->ticketLinkType->labelForSource($ticketLink->source_ticket_id === $ticket->id);
return TicketLinkResource::make($ticketLink->load(['sourceTicket', 'targetTicket', 'ticketLinkType']))
->additional([
'meta' => [
- 'message' => "{$ticketLink->ticketLinkType->label} link was saved.",
+ 'message' => "{$label} link was saved.",
],
])
->response()
diff --git a/app/Http/Controllers/ProjectTicketLinkController.php b/app/Http/Controllers/ProjectTicketLinkController.php
index 208b98f..65b14e3 100644
--- a/app/Http/Controllers/ProjectTicketLinkController.php
+++ b/app/Http/Controllers/ProjectTicketLinkController.php
@@ -34,9 +34,10 @@ class ProjectTicketLinkController extends Controller
);
$ticketLink = $this->storeProjectTicketLink->handle($project, $ticket, $user, $request->validated());
+ $label = $ticketLink->ticketLinkType->labelForSource($ticketLink->source_ticket_id === $ticket->id);
return to_route('projects.tickets.show', [$project, $ticket])
- ->with('status', "{$ticketLink->ticketLinkType->label} link was saved.");
+ ->with('status', "{$label} link was saved.");
}
public function destroy(
diff --git a/app/Http/Requests/StoreTicketLinkRequest.php b/app/Http/Requests/StoreTicketLinkRequest.php
index a4f2915..1bdc022 100644
--- a/app/Http/Requests/StoreTicketLinkRequest.php
+++ b/app/Http/Requests/StoreTicketLinkRequest.php
@@ -42,6 +42,7 @@ class StoreTicketLinkRequest extends FormRequest
fn ($query) => $query->where('project_id', $project->id),
),
],
+ 'link_direction' => ['sometimes', 'required', Rule::in(['source', 'counterpart'])],
];
}
diff --git a/resources/js/components/tickets/detail/TicketDetailRelationships.vue b/resources/js/components/tickets/detail/TicketDetailRelationships.vue
index 10e88f3..4246a85 100644
--- a/resources/js/components/tickets/detail/TicketDetailRelationships.vue
+++ b/resources/js/components/tickets/detail/TicketDetailRelationships.vue
@@ -35,6 +35,7 @@ const canAddLink = computed(
);
const form = useForm({
ticket_link_type_id: props.ticketLinkTypes[0]?.id ?? '',
+ link_direction: 'source',
linked_ticket_id: '',
});
const protection = useFormProtection(form, {
@@ -220,7 +221,7 @@ function submit(): void {
/>