ui updates for ticket layout
This commit is contained in:
@@ -55,9 +55,12 @@ final class KanbanBoard extends Component
|
||||
Auth::user()
|
||||
);
|
||||
|
||||
$this->board_id = $board?->id;
|
||||
|
||||
$message = 'Ticket '.$ticket->reference.' moved from '.$oldStatusName.' to '.$status->name.'.';
|
||||
session()->flash('success', $message);
|
||||
$this->dispatch('wms:toast', type: 'success', title: 'Ticket moved', message: $message);
|
||||
$this->dispatch('helpdesk-kanban-ticket-moved', ticketId: (int) $ticket->id, statusId: (int) $status->id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,6 +98,7 @@ final class KanbanBoard extends Component
|
||||
$message = 'Ticket '.$fresh->reference.' moved from '.$oldBoardName.' to '.$board->name.'.';
|
||||
session()->flash('success', $message);
|
||||
$this->dispatch('wms:toast', type: 'success', title: 'Board changed', message: $message);
|
||||
$this->dispatch('helpdesk-kanban-ticket-moved', ticketId: (int) $fresh->id, statusId: (int) $fresh->status_id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,6 +24,7 @@ use Modules\Helpdesk\Models\Priority;
|
||||
use Modules\Helpdesk\Models\Status;
|
||||
use Modules\Helpdesk\Models\Ticket;
|
||||
use Modules\Helpdesk\Services\CannedResponseRenderer;
|
||||
use Modules\Helpdesk\Services\AttachmentService;
|
||||
use Modules\Helpdesk\Services\ChecklistService;
|
||||
use Modules\Helpdesk\Services\SlaService;
|
||||
use Modules\Helpdesk\Services\TicketService;
|
||||
@@ -43,6 +44,9 @@ final class TicketShow extends Component
|
||||
/** @var array<int, TemporaryUploadedFile> */
|
||||
public array $attachments = [];
|
||||
|
||||
/** @var array<int, TemporaryUploadedFile> */
|
||||
public array $supportingFiles = [];
|
||||
|
||||
public ?int $status_id = null;
|
||||
|
||||
public ?int $priority_id = null;
|
||||
@@ -259,6 +263,36 @@ final class TicketShow extends Component
|
||||
$this->dispatch('helpdesk-agent-updated', agentId: $this->agent_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist one or more supporting files directly against an existing ticket.
|
||||
*
|
||||
* This is intentionally separate from comment attachments so users can add
|
||||
* evidence to an already-created ticket without posting another response.
|
||||
*/
|
||||
public function saveSupportingFiles(AttachmentService $attachments): void
|
||||
{
|
||||
$this->authorize('comment', $this->ticket);
|
||||
|
||||
$maxUploadKilobytes = (int) config('helpdesk.max_upload_kb', 10240);
|
||||
$allowedMimes = implode(',', config('helpdesk.allowed_mimes', ['jpg', 'jpeg', 'png', 'pdf', 'txt', 'log', 'zip']));
|
||||
|
||||
$this->validate([
|
||||
'supportingFiles' => ['required', 'array', 'min:1'],
|
||||
'supportingFiles.*' => ['file', 'max:'.$maxUploadKilobytes, 'mimes:'.$allowedMimes],
|
||||
]);
|
||||
|
||||
$user = Auth::user();
|
||||
abort_if($user === null, 403);
|
||||
|
||||
$attachments->storeMany($this->ticket, $this->supportingFiles, (int) $user->id);
|
||||
|
||||
$this->reset('supportingFiles');
|
||||
$this->ticket = $this->freshTicket($this->ticket);
|
||||
|
||||
session()->flash('ticket-supporting-files-added', 'Supporting files attached.');
|
||||
$this->dispatch('helpdesk-supporting-files-added');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
{
|
||||
return view('helpdesk::livewire.ticket-show', [
|
||||
|
||||
@@ -254,11 +254,11 @@
|
||||
This board is being initialised with the default workflow statuses. Refresh the page if the columns do not appear immediately.
|
||||
</div>
|
||||
@else
|
||||
<div class="flex gap-4 overflow-x-auto pb-4" data-helpdesk-kanban-board>
|
||||
<div class="flex gap-4 overflow-x-auto pb-4" data-helpdesk-kanban-board wire:key="helpdesk-kanban-board-{{ $board?->id ?? 'none' }}">
|
||||
@foreach ($statuses as $status)
|
||||
@php($tickets = $ticketsByStatus[$status->id] ?? collect())
|
||||
|
||||
<section class="flex min-h-[640px] w-[330px] shrink-0 flex-col overflow-hidden rounded-2xl border border-zinc-200 bg-zinc-100 shadow-sm dark:border-zinc-700 dark:bg-zinc-950" dusk="kanban-column-{{ $status->slug }}">
|
||||
<section wire:key="helpdesk-kanban-column-{{ $board?->id }}-{{ $status->id }}" class="flex min-h-[640px] w-[330px] shrink-0 flex-col overflow-hidden rounded-2xl border border-zinc-200 bg-zinc-100 shadow-sm dark:border-zinc-700 dark:bg-zinc-950" dusk="kanban-column-{{ $status->slug }}">
|
||||
<header class="border-b border-zinc-200 bg-white px-4 py-4 dark:border-zinc-800 dark:bg-zinc-900">
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<div>
|
||||
@@ -281,6 +281,7 @@
|
||||
data-helpdesk-kanban-ticket
|
||||
data-ticket-id="{{ $ticket->id }}"
|
||||
dusk="kanban-ticket-{{ $ticket->id }}"
|
||||
wire:key="helpdesk-kanban-ticket-{{ $ticket->id }}-{{ $ticket->status_id }}-{{ optional($ticket->updated_at)->timestamp ?? 0 }}"
|
||||
>
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<div class="min-w-0">
|
||||
@@ -409,7 +410,9 @@
|
||||
|
||||
if (!ticketId || !statusId) return;
|
||||
|
||||
$wire.moveTicket(ticketId, statusId);
|
||||
$wire.moveTicket(ticketId, statusId).then(function () {
|
||||
initialiseHelpdeskKanban();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -417,6 +420,8 @@
|
||||
initialiseHelpdeskKanban();
|
||||
document.addEventListener('livewire:navigated', initialiseHelpdeskKanban);
|
||||
document.addEventListener('livewire:updated', initialiseHelpdeskKanban);
|
||||
document.addEventListener('livewire:update', initialiseHelpdeskKanban);
|
||||
document.addEventListener('helpdesk-kanban-ticket-moved', initialiseHelpdeskKanban);
|
||||
</script>
|
||||
@endscript
|
||||
</div>
|
||||
|
||||
@@ -307,42 +307,114 @@
|
||||
</div>
|
||||
</article>
|
||||
|
||||
@if ($ticket->attachments->isNotEmpty())
|
||||
<details class="overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
|
||||
<summary class="flex cursor-pointer list-none items-center justify-between gap-5 bg-gradient-to-r from-slate-950 via-blue-950 to-slate-900 px-7 py-7 text-white marker:hidden sm:px-9">
|
||||
<div class="flex min-w-0 items-start gap-5">
|
||||
<span class="inline-flex h-14 w-14 shrink-0 items-center justify-center rounded-2xl bg-blue-500/25 text-white ring-1 ring-white/20 shadow-lg shadow-black/20">
|
||||
<i class="fa-solid fa-paperclip text-xl" aria-hidden="true"></i>
|
||||
</span>
|
||||
<div class="min-w-0 space-y-2">
|
||||
<p class="text-xs font-black uppercase tracking-[0.22em] text-blue-200">Ticket attachments</p>
|
||||
<h2 class="text-2xl font-extrabold tracking-tight sm:text-3xl">Supporting files</h2>
|
||||
<p class="text-base font-medium leading-7 text-blue-50/85">Screenshots, documents and logs linked to this ticket.</p>
|
||||
<section class="overflow-hidden rounded-[2rem] border border-zinc-200 bg-white shadow-sm dark:border-zinc-700 dark:bg-zinc-900" data-helpdesk-supporting-files-card>
|
||||
<div class="bg-gradient-to-r from-slate-950 via-blue-950 to-slate-900 px-7 py-7 text-white sm:px-9">
|
||||
<div class="flex flex-col gap-5 xl:flex-row xl:items-center xl:justify-between">
|
||||
<div class="flex min-w-0 items-start gap-5">
|
||||
<span class="inline-flex h-14 w-14 shrink-0 items-center justify-center rounded-2xl bg-blue-500/25 text-white ring-1 ring-white/20 shadow-lg shadow-black/20">
|
||||
<i class="fa-solid fa-paperclip text-xl" aria-hidden="true"></i>
|
||||
</span>
|
||||
<div class="min-w-0 space-y-2">
|
||||
<p class="text-xs font-black uppercase tracking-[0.22em] text-blue-200">Ticket attachments</p>
|
||||
<h2 class="text-2xl font-extrabold tracking-tight sm:text-3xl">Supporting files</h2>
|
||||
<p class="text-base font-medium leading-7 text-blue-50/85">Attach multiple screenshots, documents, logs and evidence directly to this existing ticket.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="inline-flex w-fit shrink-0 items-center gap-3 rounded-2xl bg-white/15 px-5 py-3 text-base font-extrabold ring-1 ring-white/20 shadow-sm">
|
||||
<i class="fa-solid fa-paperclip text-sm" aria-hidden="true"></i>
|
||||
{{ $ticket->attachments->count() }} file{{ $ticket->attachments->count() === 1 ? '' : 's' }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span class="inline-flex shrink-0 items-center gap-3 rounded-2xl bg-white/15 px-5 py-3 text-base font-extrabold ring-1 ring-white/20 shadow-sm">
|
||||
<i class="fa-solid fa-paperclip text-sm" aria-hidden="true"></i>
|
||||
{{ $ticket->attachments->count() }} file{{ $ticket->attachments->count() === 1 ? '' : 's' }}
|
||||
<i class="fa-solid fa-chevron-right transition" aria-hidden="true"></i>
|
||||
</span>
|
||||
</summary>
|
||||
|
||||
<div class="grid gap-3 p-6 sm:grid-cols-2">
|
||||
@foreach ($ticket->attachments as $attachment)
|
||||
<a href="{{ route('helpdesk.attachments.download', $attachment->id) }}" target="_blank" class="group flex items-center justify-between gap-4 rounded-xl border border-zinc-200 p-4 text-sm transition hover:bg-zinc-50 dark:border-zinc-700 dark:hover:bg-zinc-800">
|
||||
<span class="min-w-0">
|
||||
<span class="block truncate font-bold text-zinc-900 dark:text-zinc-100">{{ $attachment->original_name ?? $attachment->original_filename ?? $attachment->filename ?? $attachment->file_name ?? basename($attachment->path ?? $attachment->file_path ?? '') }}</span>
|
||||
<span class="block text-xs text-zinc-500">{{ Number::fileSize($attachment->size ?? $attachment->size_bytes ?? 0) }}</span>
|
||||
</span>
|
||||
<span class="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-zinc-100 text-zinc-700 transition group-hover:bg-blue-600 group-hover:text-white dark:bg-zinc-800 dark:text-zinc-200">
|
||||
<i class="fa-solid fa-download" aria-hidden="true"></i>
|
||||
</span>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</details>
|
||||
@endif
|
||||
|
||||
<div class="space-y-5 p-6 sm:p-7">
|
||||
@if (session('ticket-supporting-files-added'))
|
||||
<div class="rounded-2xl border border-emerald-300 bg-emerald-50 px-4 py-3 text-sm font-bold text-emerald-800 dark:border-emerald-800 dark:bg-emerald-950 dark:text-emerald-100">
|
||||
{{ session('ticket-supporting-files-added') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@can('comment', $ticket)
|
||||
<div class="rounded-[1.5rem] border border-blue-200 bg-blue-50/80 p-5 shadow-sm dark:border-blue-900/60 dark:bg-blue-950/30" data-helpdesk-attachment-shell>
|
||||
<div class="flex min-h-[5.25rem] flex-col gap-4 sm:flex-row sm:items-center sm:justify-between" data-helpdesk-attachment-picker-row>
|
||||
<div class="flex min-w-0 items-center gap-4">
|
||||
<span class="inline-flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl border border-blue-200 bg-white text-blue-700 shadow-sm dark:border-blue-800 dark:bg-zinc-950 dark:text-blue-200">
|
||||
<i class="fa-solid fa-file-arrow-up text-base" aria-hidden="true"></i>
|
||||
</span>
|
||||
<span class="min-w-0">
|
||||
<span class="block text-sm font-black text-zinc-900 dark:text-zinc-100">Attach supporting evidence</span>
|
||||
<span class="block truncate text-xs font-semibold text-zinc-600 dark:text-zinc-300" data-helpdesk-supporting-file-label>
|
||||
{{ count($supportingFiles) === 0 ? 'No files selected' : count($supportingFiles).' file'.(count($supportingFiles) === 1 ? '' : 's').' selected' }}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap items-center justify-end gap-3">
|
||||
<label data-helpdesk-file-button>
|
||||
<i class="fa-solid fa-paperclip" aria-hidden="true"></i>
|
||||
<span>Choose files</span>
|
||||
<input id="helpdesk-supporting-files" type="file" multiple class="sr-only" wire:model="supportingFiles" data-helpdesk-supporting-file-input>
|
||||
</label>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
wire:click="saveSupportingFiles"
|
||||
wire:loading.attr="disabled"
|
||||
wire:target="supportingFiles,saveSupportingFiles"
|
||||
@disabled(count($supportingFiles) === 0)
|
||||
class="inline-flex min-h-12 items-center justify-center gap-2 rounded-2xl bg-emerald-600 px-5 py-3 text-sm font-black text-white shadow-sm transition hover:bg-emerald-700 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
>
|
||||
<i class="fa-solid fa-cloud-arrow-up" aria-hidden="true"></i>
|
||||
Save files
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div wire:loading wire:target="supportingFiles" class="mt-4 rounded-xl border border-blue-200 bg-white px-4 py-3 text-sm font-bold text-blue-800 dark:border-blue-800 dark:bg-zinc-950 dark:text-blue-100">
|
||||
Preparing selected files…
|
||||
</div>
|
||||
|
||||
@if (count($supportingFiles) > 0)
|
||||
<div class="mt-4 rounded-2xl border border-zinc-200 bg-white p-4 dark:border-zinc-800 dark:bg-zinc-950">
|
||||
<p class="mb-3 text-xs font-black uppercase tracking-[0.2em] text-zinc-500 dark:text-zinc-400">Ready to attach</p>
|
||||
<ul class="space-y-2">
|
||||
@foreach ($supportingFiles as $file)
|
||||
<li class="flex items-center justify-between gap-3 rounded-xl border border-zinc-200 bg-zinc-50 px-3 py-2 text-sm font-semibold text-zinc-800 dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-100">
|
||||
<span class="truncate">{{ $file->getClientOriginalName() }}</span>
|
||||
<span class="shrink-0 text-xs text-zinc-500">{{ Number::fileSize((int) $file->getSize()) }}</span>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@error('supportingFiles') <div class="mt-2 text-sm font-bold text-red-600">{{ $message }}</div> @enderror
|
||||
@error('supportingFiles.*') <div class="mt-2 text-sm font-bold text-red-600">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
@endcan
|
||||
|
||||
@if ($ticket->attachments->isEmpty())
|
||||
<div class="rounded-2xl border border-dashed border-zinc-300 bg-zinc-50 px-5 py-8 text-center text-sm font-semibold text-zinc-600 dark:border-zinc-700 dark:bg-zinc-950 dark:text-zinc-300">
|
||||
No supporting files have been attached yet.
|
||||
</div>
|
||||
@else
|
||||
<div class="grid gap-3 sm:grid-cols-2">
|
||||
@foreach ($ticket->attachments as $attachment)
|
||||
<a href="{{ route('helpdesk.attachments.download', $attachment->id) }}" target="_blank" class="group flex items-center justify-between gap-4 rounded-2xl border border-zinc-200 bg-white p-4 text-sm shadow-sm transition hover:-translate-y-0.5 hover:bg-zinc-50 hover:shadow-md dark:border-zinc-700 dark:bg-zinc-950 dark:hover:bg-zinc-900">
|
||||
<span class="min-w-0">
|
||||
<span class="block truncate font-black text-zinc-900 dark:text-zinc-100">{{ $attachment->original_name ?? $attachment->original_filename ?? $attachment->filename ?? $attachment->file_name ?? basename($attachment->path ?? $attachment->file_path ?? '') }}</span>
|
||||
<span class="block text-xs font-semibold text-zinc-500">{{ Number::fileSize($attachment->size ?? $attachment->size_bytes ?? 0) }}</span>
|
||||
</span>
|
||||
<span class="inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl bg-blue-600 text-white shadow-sm transition group-hover:bg-blue-700">
|
||||
<i class="fa-solid fa-download" aria-hidden="true"></i>
|
||||
</span>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="space-y-4">
|
||||
<details class="overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-sm dark:border-zinc-700 dark:bg-zinc-900" data-helpdesk-conversation-section>
|
||||
@@ -505,50 +577,6 @@
|
||||
@endif
|
||||
@endcan
|
||||
|
||||
<details class="mt-5 overflow-hidden rounded-[1.5rem] border border-zinc-200 bg-white/80 shadow-sm dark:border-zinc-800 dark:bg-zinc-950/50">
|
||||
<summary class="group flex cursor-pointer list-none items-center justify-between gap-4 bg-gradient-to-r from-slate-950 via-blue-950 to-slate-900 px-6 py-5 text-white transition hover:from-slate-900 hover:via-blue-900 hover:to-slate-900 [&::-webkit-details-marker]:hidden">
|
||||
<span class="flex min-w-0 items-center gap-4">
|
||||
<span class="inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl border border-blue-400/30 bg-blue-500/15 text-blue-200 shadow-inner">
|
||||
<i class="fa-solid fa-paperclip text-sm" aria-hidden="true"></i>
|
||||
</span>
|
||||
<span class="min-w-0">
|
||||
<span class="block text-xs font-black uppercase tracking-[0.28em] text-blue-200">Attachments</span>
|
||||
<span class="block text-xl font-black tracking-tight text-white">Supporting files</span>
|
||||
<span class="block truncate text-sm font-semibold text-zinc-300">Pin screenshots, logs and supporting documents.</span>
|
||||
</span>
|
||||
</span>
|
||||
<span class="flex shrink-0 items-center gap-3">
|
||||
<span class="rounded-full border border-white/10 bg-white/10 px-3 py-1 text-xs font-black text-white" data-helpdesk-file-count>0 files</span>
|
||||
<i class="fa-solid fa-chevron-down text-xs text-blue-200 transition group-open:rotate-180" aria-hidden="true"></i>
|
||||
</span>
|
||||
</summary>
|
||||
|
||||
<div class="border-t border-zinc-200 p-6 dark:border-zinc-800">
|
||||
<div class="rounded-2xl border border-zinc-200 bg-zinc-50/80 p-5 shadow-sm dark:border-zinc-800 dark:bg-zinc-950/70">
|
||||
<div class="flex min-h-[5.25rem] flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div class="flex min-w-0 items-center gap-4">
|
||||
<span class="inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-xl border border-zinc-300 bg-white text-zinc-700 dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-200">
|
||||
<i class="fa-solid fa-file-arrow-up text-sm" aria-hidden="true"></i>
|
||||
</span>
|
||||
<span class="min-w-0">
|
||||
<span class="block text-sm font-black text-zinc-900 dark:text-zinc-100">Attach supporting evidence</span>
|
||||
<span class="block truncate text-xs font-semibold text-zinc-500 dark:text-zinc-400" data-helpdesk-file-label>No files attached</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="flex shrink-0 items-center justify-center sm:min-w-[190px]">
|
||||
<label data-helpdesk-file-button>
|
||||
<i class="fa-solid fa-paperclip" aria-hidden="true"></i>
|
||||
<span>Attach files</span>
|
||||
<input name="attachments[]" type="file" multiple class="sr-only" data-helpdesk-file-input>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@error('attachments.*') <div class="mt-2 text-sm text-red-600">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<div class="mt-6 flex justify-end">
|
||||
<button dusk="post-comment" type="submit" class="inline-flex items-center justify-center rounded-xl bg-emerald-600 px-5 py-3 text-sm font-bold text-white shadow-sm transition hover:bg-emerald-700 focus:outline-none focus:ring-2 focus:ring-emerald-400/70">
|
||||
<i class="fa-solid fa-comments mr-2" aria-hidden="true"></i>
|
||||
@@ -677,11 +705,11 @@
|
||||
});
|
||||
}
|
||||
|
||||
const fileInput = event.target.closest('[data-helpdesk-file-input]');
|
||||
const fileInput = event.target.closest('[data-helpdesk-file-input], [data-helpdesk-supporting-file-input]');
|
||||
|
||||
if (fileInput) {
|
||||
const panel = fileInput.closest('details') || fileInput.closest('div');
|
||||
const label = panel?.querySelector('[data-helpdesk-file-label]');
|
||||
const label = panel?.querySelector('[data-helpdesk-file-label], [data-helpdesk-supporting-file-label]');
|
||||
const badge = panel?.querySelector('[data-helpdesk-file-count]');
|
||||
const count = fileInput.files?.length || 0;
|
||||
const text = count === 0 ? 'No files attached' : `${count} file${count === 1 ? '' : 's'} selected`;
|
||||
|
||||
@@ -56,7 +56,9 @@ final class KanbanBoardTest extends TestCase
|
||||
|
||||
Livewire::test(KanbanBoard::class)
|
||||
->call('moveTicket', $ticket->id, $lookups['closed']->id)
|
||||
->assertHasNoErrors();
|
||||
->assertHasNoErrors()
|
||||
->assertDispatched('helpdesk-kanban-ticket-moved')
|
||||
->assertSee($ticket->reference);
|
||||
|
||||
$ticket->refresh();
|
||||
|
||||
|
||||
@@ -116,6 +116,40 @@ final class TicketConversationTest extends TestCase
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function test_existing_ticket_accepts_multiple_supporting_file_attachments(): void
|
||||
{
|
||||
Storage::fake((string) config('helpdesk.disk', 'public'));
|
||||
|
||||
$fixtures = $this->seedLookupData();
|
||||
$owner = $this->user();
|
||||
$ticket = $this->ticket(['owner' => $owner, 'status_id' => $fixtures['open']->id, 'priority_id' => $fixtures['normal']->id]);
|
||||
|
||||
Livewire::actingAs($owner)
|
||||
->test(TicketShow::class, ['ticket' => $ticket])
|
||||
->set('supportingFiles', [
|
||||
UploadedFile::fake()->create('existing-ticket-log.txt', 8, 'text/plain'),
|
||||
UploadedFile::fake()->create('existing-ticket-proof.pdf', 12, 'application/pdf'),
|
||||
])
|
||||
->call('saveSupportingFiles')
|
||||
->assertHasNoErrors()
|
||||
->assertDispatched('helpdesk-supporting-files-added');
|
||||
|
||||
self::assertSame(2, Attachment::query()->where('ticket_id', $ticket->id)->whereNull('comment_id')->count());
|
||||
|
||||
$this->assertDatabaseHas('helpdesk_attachments', [
|
||||
'ticket_id' => $ticket->id,
|
||||
'comment_id' => null,
|
||||
'original_name' => 'existing-ticket-log.txt',
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('helpdesk_attachments', [
|
||||
'ticket_id' => $ticket->id,
|
||||
'comment_id' => null,
|
||||
'original_name' => 'existing-ticket-proof.pdf',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_post_endpoint_accepts_multiple_comment_attachments(): void
|
||||
{
|
||||
Storage::fake((string) config('helpdesk.disk', 'public'));
|
||||
|
||||
@@ -344,3 +344,14 @@ versions:
|
||||
- Removed direct Helpdesk Vite manifest loading from ticket create when the module build manifest is not present.
|
||||
- Updated Helpdesk conversation feature coverage for multiple attachments and super-admin response deletion.
|
||||
- Kept module.json version in sync with changelog.yaml.
|
||||
|
||||
- version: 1.9.20
|
||||
date: 2026-06-17
|
||||
changes:
|
||||
- Moved existing-ticket attachment upload into the Supporting files card instead of the response form.
|
||||
- Added Livewire-backed multi-file uploads directly against existing tickets without requiring a new response.
|
||||
- Preserved normal response posting while removing the misplaced response attachment chooser from the ticket detail form.
|
||||
- Improved the Supporting files attachment button styling and selected-file status display.
|
||||
- Added Kanban board re-render keys and moved-ticket browser events so drag/drop status moves refresh reliably.
|
||||
- Added feature coverage for existing-ticket multiple supporting file uploads and Kanban moved-ticket dispatch.
|
||||
- Kept module.json version in sync with changelog.yaml.
|
||||
|
||||
@@ -22,5 +22,5 @@
|
||||
"Modules\\Helpdesk\\Providers\\HelpdeskServiceProvider"
|
||||
],
|
||||
"files": [],
|
||||
"version": "1.9.19"
|
||||
"version": "1.9.20"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user