started to add indexes and fixed N+1 issue
This commit is contained in:
@@ -7,7 +7,7 @@ return [
|
||||
'middleware' => ['web', 'auth'],
|
||||
'disk' => env('HELPDESK_ATTACHMENTS_DISK', 'helpdesk'),
|
||||
'max_upload_kb' => (int) env('HELPDESK_MAX_UPLOAD_KB', 10240),
|
||||
'allowed_mimes' => ['md','pdf', 'png', 'jpg', 'jpeg', 'webp', 'doc', 'docx', 'xls', 'xlsx', 'txt', 'csv', 'zip'],
|
||||
'allowed_mimes' => ['md', 'pdf', 'png', 'jpg', 'jpeg', 'webp', 'doc', 'docx', 'xls', 'xlsx', 'txt', 'csv', 'zip'],
|
||||
'default_status_slug' => 'new',
|
||||
'closed_status_slug' => 'closed',
|
||||
];
|
||||
|
||||
@@ -43,7 +43,6 @@ final class HelpdeskDatabaseSeeder extends Seeder
|
||||
['name' => 'Stalled', 'slug' => 'stalled', 'color' => 'rose', 'sort_order' => 30, 'is_closed' => false],
|
||||
['name' => 'On-Hold', 'slug' => 'on-hold', 'color' => 'violet', 'sort_order' => 40, 'is_closed' => false],
|
||||
['name' => 'Closed', 'slug' => 'closed', 'color' => 'emerald', 'sort_order' => 90, 'is_closed' => true],
|
||||
['name' => 'Testing', 'slug' => 'testing', 'color' => 'green', 'sort_order' => 30, 'is_closed' => false],
|
||||
] as $row) {
|
||||
Status::query()->updateOrCreate(['slug' => $row['slug']], $row);
|
||||
}
|
||||
@@ -77,7 +76,6 @@ final class HelpdeskDatabaseSeeder extends Seeder
|
||||
['name' => 'Systems Deployment', 'color' => 'cyan', 'description' => 'Deployment, release, infrastructure and environment requests.'],
|
||||
['name' => 'Concepts', 'color' => 'purple', 'description' => 'Ideas, concepts, design discussion and future improvements.'],
|
||||
['name' => 'Bug', 'color' => 'rose', 'description' => 'Defects, regressions and incorrect behaviour.'],
|
||||
['name' => 'Documentation', 'color' => 'red', 'description' => 'System Documents creation or update.'],
|
||||
] as $row) {
|
||||
Category::query()->updateOrCreate(
|
||||
['company_id' => null, 'slug' => Str::slug($row['name'])],
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Helpdesk\Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Str;
|
||||
use Modules\Helpdesk\Models\Category;
|
||||
use Modules\Helpdesk\Models\Priority;
|
||||
use Modules\Helpdesk\Models\Project;
|
||||
use Modules\Helpdesk\Models\Status;
|
||||
use Modules\Helpdesk\Models\Team;
|
||||
use Modules\Helpdesk\Models\WorkflowTemplate;
|
||||
|
||||
final class HelpdeskDatabaseSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Seed the Helpdesk module lookup data and default workflow templates.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$this->seedStatuses();
|
||||
$this->seedPriorities();
|
||||
$this->seedCategories();
|
||||
$this->seedTeamsAndProjects();
|
||||
$this->seedWorkflowTemplates();
|
||||
}
|
||||
|
||||
/**
|
||||
* Seed ticket workflow statuses.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function seedStatuses(): void
|
||||
{
|
||||
foreach ([
|
||||
['name' => 'New', 'slug' => 'new', 'color' => 'sky', 'sort_order' => 5, 'is_closed' => false],
|
||||
['name' => 'Open', 'slug' => 'open', 'color' => 'blue', 'sort_order' => 10, 'is_closed' => false],
|
||||
['name' => 'In Progress', 'slug' => 'in-progress', 'color' => 'amber', 'sort_order' => 20, 'is_closed' => false],
|
||||
['name' => 'Stalled', 'slug' => 'stalled', 'color' => 'rose', 'sort_order' => 30, 'is_closed' => false],
|
||||
['name' => 'On-Hold', 'slug' => 'on-hold', 'color' => 'violet', 'sort_order' => 40, 'is_closed' => false],
|
||||
['name' => 'Closed', 'slug' => 'closed', 'color' => 'emerald', 'sort_order' => 90, 'is_closed' => true],
|
||||
] as $row) {
|
||||
Status::query()->updateOrCreate(['slug' => $row['slug']], $row);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Seed ticket priorities.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function seedPriorities(): void
|
||||
{
|
||||
foreach ([
|
||||
['name' => 'High', 'slug' => 'high', 'color' => 'red', 'sort_order' => 10],
|
||||
['name' => 'Medium', 'slug' => 'medium', 'color' => 'amber', 'sort_order' => 20],
|
||||
['name' => 'Low', 'slug' => 'low', 'color' => 'emerald', 'sort_order' => 30],
|
||||
] as $row) {
|
||||
Priority::query()->updateOrCreate(['slug' => $row['slug']], $row);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Seed ticket categories.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function seedCategories(): void
|
||||
{
|
||||
foreach ([
|
||||
['name' => 'Development', 'color' => 'indigo', 'description' => 'Software changes, enhancements and development work.'],
|
||||
['name' => 'Systems Deployment', 'color' => 'cyan', 'description' => 'Deployment, release, infrastructure and environment requests.'],
|
||||
['name' => 'Concepts', 'color' => 'purple', 'description' => 'Ideas, concepts, design discussion and future improvements.'],
|
||||
['name' => 'Bug', 'color' => 'rose', 'description' => 'Defects, regressions and incorrect behaviour.'],
|
||||
] as $row) {
|
||||
Category::query()->updateOrCreate(
|
||||
['company_id' => null, 'slug' => Str::slug($row['name'])],
|
||||
$row + ['company_id' => null, 'slug' => Str::slug($row['name'])]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Seed the default support team and a default project.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function seedTeamsAndProjects(): void
|
||||
{
|
||||
$team = Team::query()->updateOrCreate(
|
||||
['company_id' => null, 'slug' => 'support'],
|
||||
[
|
||||
'company_id' => null,
|
||||
'name' => 'Support',
|
||||
'slug' => 'support',
|
||||
'color' => 'blue',
|
||||
'description' => 'Default support team for triage, ownership and ticket routing.',
|
||||
]
|
||||
);
|
||||
|
||||
Project::query()->updateOrCreate(
|
||||
['company_id' => null, 'slug' => 'support-desk'],
|
||||
[
|
||||
'company_id' => null,
|
||||
'team_id' => $team->id,
|
||||
'title' => 'Support Desk',
|
||||
'slug' => 'support-desk',
|
||||
'color' => 'indigo',
|
||||
'description' => 'Default project for operational helpdesk tickets.',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Seed default professional workflow email templates.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function seedWorkflowTemplates(): void
|
||||
{
|
||||
foreach ([
|
||||
['name' => 'Ticket raised requester notice', 'event' => 'ticket.created', 'subject' => 'Ticket {{ ticket.reference }} has been raised', 'html_body' => '<p>Hello {{ requester.name }},</p><p>Your ticket <strong>{{ ticket.reference }}</strong> has been raised successfully.</p><p><strong>Subject:</strong> {{ ticket.subject }}</p><p><strong>Priority:</strong> {{ ticket.priority }}</p>', 'to_role' => 'requester'],
|
||||
['name' => 'Ticket updated requester notice', 'event' => 'ticket.updated', 'subject' => 'Ticket {{ ticket.reference }} has been updated', 'html_body' => '<p>Hello {{ requester.name }},</p><p>Your ticket <strong>{{ ticket.reference }}</strong> has been updated.</p><p><strong>Status:</strong> {{ ticket.status }}</p><p><strong>Priority:</strong> {{ ticket.priority }}</p>', 'to_role' => 'requester'],
|
||||
['name' => 'Ticket response requester notice', 'event' => 'ticket.commented', 'subject' => 'New response on ticket {{ ticket.reference }}', 'html_body' => '<p>Hello {{ requester.name }},</p><p>A new response has been added to <strong>{{ ticket.reference }}</strong>.</p><p><strong>Subject:</strong> {{ ticket.subject }}</p>', 'to_role' => 'requester'],
|
||||
['name' => 'Ticket closed requester notice', 'event' => 'ticket.closed', 'subject' => 'Ticket {{ ticket.reference }} has been closed', 'html_body' => '<p>Hello {{ requester.name }},</p><p>Your ticket <strong>{{ ticket.reference }}</strong> has been closed.</p><p>Thank you for using the support desk.</p>', 'to_role' => 'requester'],
|
||||
] as $template) {
|
||||
WorkflowTemplate::query()->updateOrCreate(
|
||||
['name' => $template['name'], 'event' => $template['event']],
|
||||
$template + ['text_body' => null, 'cc' => null, 'bcc' => null, 'is_active' => true]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,9 @@
|
||||
<div>
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.28em] text-blue-200">Helpdesk workflow</p>
|
||||
<h1 class="mt-2 text-3xl font-semibold tracking-tight">Kanban board</h1>
|
||||
<p class="mt-2 max-w-3xl text-sm text-blue-100/90">Drag tickets between configured statuses. Add, rename and order boards from Helpdesk Settings → Statuses.</p>
|
||||
<p class="mt-2 max-w-3xl text-sm text-blue-100/90">Drag tickets between configurable status boards. Add, rename and order boards from Helpdesk Settings → Statuses.</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<flux:button :href="route('helpdesk.tickets.create')" wire:navigate variant="primary" icon="plus">New ticket</flux:button>
|
||||
<flux:button :href="route('helpdesk.settings')" wire:navigate variant="ghost" icon="cog-6-tooth">Configure boards</flux:button>
|
||||
@@ -31,10 +32,10 @@
|
||||
this.draggedTicketId = event.currentTarget.dataset.ticketId;
|
||||
event.dataTransfer.effectAllowed = 'move';
|
||||
event.dataTransfer.setData('text/plain', this.draggedTicketId);
|
||||
event.currentTarget.classList.add('opacity-60', 'rotate-1');
|
||||
event.currentTarget.classList.add('opacity-60', 'rotate-1', 'scale-[0.99]');
|
||||
},
|
||||
dragEnd(event) {
|
||||
event.currentTarget.classList.remove('opacity-60', 'rotate-1');
|
||||
event.currentTarget.classList.remove('opacity-60', 'rotate-1', 'scale-[0.99]');
|
||||
this.draggedTicketId = null;
|
||||
this.draggingOverStatusId = null;
|
||||
},
|
||||
@@ -53,7 +54,7 @@
|
||||
const ticketId = event.dataTransfer.getData('text/plain') || this.draggedTicketId;
|
||||
this.draggingOverStatusId = null;
|
||||
|
||||
if (!ticketId) {
|
||||
if (! ticketId) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -62,10 +63,26 @@
|
||||
}"
|
||||
>
|
||||
@foreach ($statuses as $status)
|
||||
@php($tickets = $ticketsByStatus[$status->id] ?? collect())
|
||||
@php
|
||||
$tickets = $ticketsByStatus[$status->id] ?? collect();
|
||||
$statusColor = match ($status->color) {
|
||||
'sky' => '#0284c7',
|
||||
'blue' => '#2563eb',
|
||||
'amber' => '#d97706',
|
||||
'rose' => '#e11d48',
|
||||
'violet' => '#7c3aed',
|
||||
'emerald' => '#059669',
|
||||
'red' => '#dc2626',
|
||||
'green' => '#16a34a',
|
||||
'purple' => '#9333ea',
|
||||
'indigo' => '#4f46e5',
|
||||
'cyan' => '#0891b2',
|
||||
default => str_starts_with((string) $status->color, '#') ? $status->color : '#64748b',
|
||||
};
|
||||
@endphp
|
||||
|
||||
<section
|
||||
class="flex min-h-[640px] w-[340px] 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"
|
||||
class="flex min-h-[640px] w-[340px] shrink-0 flex-col overflow-hidden rounded-2xl border border-zinc-200 bg-zinc-100 shadow-sm transition dark:border-zinc-700 dark:bg-zinc-950"
|
||||
x-bind:class="draggingOverStatusId === '{{ $status->id }}' ? 'ring-2 ring-blue-500 ring-offset-2 dark:ring-offset-zinc-950' : ''"
|
||||
x-on:dragover="dragOver($event, {{ $status->id }})"
|
||||
x-on:dragleave="dragLeave({{ $status->id }})"
|
||||
@@ -76,11 +93,12 @@
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="inline-flex h-3 w-3 rounded-full" style="background-color: {{ $status->color }}"></span>
|
||||
<span class="inline-flex h-3 w-3 rounded-full" style="background-color: {{ $statusColor }}"></span>
|
||||
<h2 class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">{{ $status->name }}</h2>
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-zinc-500">{{ $tickets->count() }} tickets</p>
|
||||
</div>
|
||||
|
||||
@if ($status->is_closed)
|
||||
<span class="rounded-full bg-emerald-100 px-2 py-1 text-xs font-semibold text-emerald-700 dark:bg-emerald-950 dark:text-emerald-200">Closed</span>
|
||||
@endif
|
||||
@@ -89,6 +107,17 @@
|
||||
|
||||
<div class="flex-1 space-y-3 overflow-y-auto p-3">
|
||||
@forelse ($tickets as $ticket)
|
||||
@php
|
||||
$priorityColor = match ($ticket->priority?->color) {
|
||||
'red' => '#dc2626',
|
||||
'amber' => '#d97706',
|
||||
'emerald' => '#059669',
|
||||
'blue' => '#2563eb',
|
||||
'rose' => '#e11d48',
|
||||
default => '#64748b',
|
||||
};
|
||||
@endphp
|
||||
|
||||
<article
|
||||
wire:key="kanban-ticket-{{ $ticket->id }}"
|
||||
draggable="true"
|
||||
@@ -106,8 +135,9 @@
|
||||
</div>
|
||||
<h3 class="mt-2 line-clamp-3 text-sm font-semibold text-zinc-900 dark:text-zinc-100">{{ $ticket->subject }}</h3>
|
||||
</div>
|
||||
|
||||
@if ($ticket->priority)
|
||||
<span class="shrink-0 rounded-full px-2 py-1 text-xs font-semibold text-white" style="background-color: {{ $ticket->priority->color }}">{{ $ticket->priority->name }}</span>
|
||||
<span class="shrink-0 rounded-full px-2 py-1 text-xs font-semibold text-white" style="background-color: {{ $priorityColor }}">{{ $ticket->priority->name }}</span>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
<div class="space-y-6">
|
||||
@include('helpdesk::partials.page-header', [
|
||||
'eyebrow' => 'Helpdesk',
|
||||
'title' => 'Create Ticket',
|
||||
'subtitle' => 'Raise a new support request with priority, project, category, team and full details.',
|
||||
])
|
||||
|
||||
<form wire:submit.prevent="save" enctype="multipart/form-data" class="space-y-6">
|
||||
|
||||
<div class="rounded-2xl border border-zinc-200 bg-white shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
|
||||
<div class="border-b border-zinc-200 px-6 py-4 dark:border-zinc-700">
|
||||
<h2 class="text-lg font-semibold text-zinc-900 dark:text-zinc-100">Ticket details</h2>
|
||||
<p class="mt-1 text-sm text-zinc-500 dark:text-zinc-400">Capture the request clearly so the support workflow can route and notify correctly.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-6 p-6 lg:grid-cols-2">
|
||||
<div class="lg:col-span-2">
|
||||
<label class="block text-sm font-semibold text-zinc-700 dark:text-zinc-200" for="subject">Subject</label>
|
||||
<input id="subject" type="text" wire:model.defer="subject" class="mt-2 block w-full rounded-xl border-zinc-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-zinc-700 dark:bg-zinc-950 dark:text-zinc-100" data-dusk="ticket-subject">
|
||||
@error('subject') <p class="mt-2 text-sm text-red-600">{{ $message }}</p> @enderror
|
||||
</div>
|
||||
|
||||
@if($companies->isNotEmpty())
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-zinc-700 dark:text-zinc-200" for="company_id">Company</label>
|
||||
<select id="company_id" wire:model.defer="company_id" class="mt-2 block w-full rounded-xl border-zinc-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-zinc-700 dark:bg-zinc-950 dark:text-zinc-100">
|
||||
<option value="">Select company</option>
|
||||
@foreach ($companies as $company)
|
||||
<option value="{{ $company->id }}">{{ $company->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('company_id') <p class="mt-2 text-sm text-red-600">{{ $message }}</p> @enderror
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-zinc-700 dark:text-zinc-200" for="priority_id">Priority</label>
|
||||
<select id="priority_id" wire:model.defer="priority_id" class="mt-2 block w-full rounded-xl border-zinc-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-zinc-700 dark:bg-zinc-950 dark:text-zinc-100" data-dusk="ticket-priority">
|
||||
<option value="">Select priority</option>
|
||||
@foreach ($priorities as $priority)
|
||||
<option value="{{ $priority->id }}">{{ $priority->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('priority_id') <p class="mt-2 text-sm text-red-600">{{ $message }}</p> @enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-zinc-700 dark:text-zinc-200" for="category_id">Category</label>
|
||||
<select id="category_id" wire:model.defer="category_id" class="mt-2 block w-full rounded-xl border-zinc-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-zinc-700 dark:bg-zinc-950 dark:text-zinc-100">
|
||||
<option value="">Select category</option>
|
||||
@foreach ($categories as $category)
|
||||
<option value="{{ $category->id }}">{{ $category->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('category_id') <p class="mt-2 text-sm text-red-600">{{ $message }}</p> @enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-zinc-700 dark:text-zinc-200" for="project_id">Project</label>
|
||||
<select id="project_id" wire:model.defer="project_id" class="mt-2 block w-full rounded-xl border-zinc-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-zinc-700 dark:bg-zinc-950 dark:text-zinc-100">
|
||||
<option value="">Select project</option>
|
||||
@foreach ($projects as $project)
|
||||
<option value="{{ $project->id }}">{{ $project->title ?? $project->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('project_id') <p class="mt-2 text-sm text-red-600">{{ $message }}</p> @enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-zinc-700 dark:text-zinc-200" for="team_id">Team</label>
|
||||
<select id="team_id" wire:model.defer="team_id" class="mt-2 block w-full rounded-xl border-zinc-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-zinc-700 dark:bg-zinc-950 dark:text-zinc-100">
|
||||
<option value="">Select team</option>
|
||||
@foreach ($teams as $team)
|
||||
<option value="{{ $team->id }}">{{ $team->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('team_id') <p class="mt-2 text-sm text-red-600">{{ $message }}</p> @enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-zinc-700 dark:text-zinc-200" for="due_at">Due date</label>
|
||||
<input id="due_at" type="date" wire:model.defer="due_at" class="mt-2 block w-full rounded-xl border-zinc-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-zinc-700 dark:bg-zinc-950 dark:text-zinc-100">
|
||||
@error('due_at') <p class="mt-2 text-sm text-red-600">{{ $message }}</p> @enderror
|
||||
</div>
|
||||
|
||||
<div class="lg:col-span-2">
|
||||
<x-helpdesk::html-editor dusk="ticket-body-editor" wire:model="body" label="Details" rows="10" placeholder="Describe the issue, expected outcome, steps to reproduce and any useful context..." />
|
||||
</div>
|
||||
|
||||
<div class="lg:col-span-2">
|
||||
<label class="block text-sm font-semibold text-zinc-700 dark:text-zinc-200" for="attachments">Attachments</label>
|
||||
<input id="attachments" type="file" wire:model="attachments" multiple class="mt-2 block w-full rounded-xl border border-zinc-300 bg-white px-3 py-2 text-sm shadow-sm dark:border-zinc-700 dark:bg-zinc-950 dark:text-zinc-100">
|
||||
@error('attachments') <p class="mt-2 text-sm text-red-600">{{ $message }}</p> @enderror
|
||||
@error('attachments.*') <p class="mt-2 text-sm text-red-600">{{ $message }}</p> @enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-end gap-3 border-t border-zinc-200 px-6 py-4 dark:border-zinc-700">
|
||||
<a href="{{ route('helpdesk.tickets.index') }}" class="rounded-xl border border-zinc-300 px-4 py-2 text-sm font-semibold text-zinc-700 hover:bg-zinc-50 dark:border-zinc-700 dark:text-zinc-200 dark:hover:bg-zinc-800">Cancel</a>
|
||||
<button type="submit" class="rounded-xl bg-blue-600 px-5 py-2 text-sm font-semibold text-white shadow-sm hover:bg-blue-700" data-dusk="ticket-create-submit">Create Ticket</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -42,3 +42,24 @@ versions:
|
||||
- Added contrasting colour assignments for seeded lookup records.
|
||||
- Corrected the seeder namespace to Modules\\Helpdesk\\Database\\Seeders for PSR-4 module autoloading.
|
||||
- Kept module.json version in sync with changelog.yaml.
|
||||
|
||||
"1.0.7":
|
||||
changed:
|
||||
- Added ticket edit screen with assignment, status, priority, category, project, team, due date and body editing.
|
||||
- Added green Edit and blue Back actions on the ticket detail page.
|
||||
- Added ticket assignment update support directly from the ticket detail page.
|
||||
- Changed default created ticket status from Open to New.
|
||||
- Rebuilt the Kanban board as a horizontal draggable workflow board using native drag and drop.
|
||||
- Added a Configure boards action that links Kanban users to the existing configurable Statuses setup.
|
||||
- Kept module.json version in sync with changelog.yaml.
|
||||
|
||||
|
||||
"1.0.8":
|
||||
changed:
|
||||
- Fixed Helpdesk module view registration so helpdesk::livewire views resolve from the module folder reliably.
|
||||
- Restored the RouteServiceProvider file expected by the module service provider.
|
||||
- Rebuilt the performance indexes migration to skip indexes already created by earlier Helpdesk migrations.
|
||||
- Kept ticket creation as a pure Livewire form and defaulted newly created tickets to the New status.
|
||||
- Made the Kanban board resilient on empty installs by ensuring default status boards exist.
|
||||
- Improved Kanban board drag/drop styling and colour rendering while preserving configurable statuses.
|
||||
- Kept module.json version in sync with changelog.yaml.
|
||||
|
||||
@@ -13,5 +13,5 @@
|
||||
"Modules\\Helpdesk\\Providers\\HelpdeskServiceProvider"
|
||||
],
|
||||
"files": [],
|
||||
"version": "1.0.6"
|
||||
"version": "1.0.8"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user