feat: ✨ set priority on tickets with order functionnality #75
This commit is contained in:
parent
64b95f6f28
commit
f932818c45
12 changed files with 185 additions and 79 deletions
|
|
@ -13,6 +13,7 @@ use App\Http\Requests\Bo\ChangeTicketStatus;
|
|||
use App\Http\Requests\Bo\CreateMessage;
|
||||
use App\Http\Requests\Bo\SortTickets;
|
||||
use App\Http\Requests\Bo\StoreTicket;
|
||||
use App\Http\Requests\Bo\UpdateChangeOrderRequest;
|
||||
use App\Http\Requests\Bo\UpdateMessage;
|
||||
use App\Http\Requests\Bo\UpdateTicket;
|
||||
use App\Lib\Helpers\FileStorageHelper;
|
||||
|
|
@ -29,12 +30,10 @@ use Illuminate\Support\Facades\DB;
|
|||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Traits\Controllers\ChangesModelOrder;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class TicketController extends Controller
|
||||
{
|
||||
use ChangesModelOrder;
|
||||
|
||||
/**
|
||||
* TicketController
|
||||
*/
|
||||
|
|
@ -508,6 +507,7 @@ class TicketController extends Controller
|
|||
Session::remove('tickets.st');
|
||||
Session::remove('tickets.pr');
|
||||
Session::remove('tickets.ty');
|
||||
Session::remove('tickets.or');
|
||||
Session::remove('tickets.search');
|
||||
}
|
||||
if ($request->assr) {
|
||||
|
|
@ -522,11 +522,15 @@ class TicketController extends Controller
|
|||
if ($request->tys) {
|
||||
Session::remove('tickets.ty');
|
||||
}
|
||||
if ($request->ord) {
|
||||
Session::remove('tickets.or');
|
||||
}
|
||||
if ($request->pr) {
|
||||
Session::put('tickets.pr', $request->pr);
|
||||
}
|
||||
if ($request->st) {
|
||||
Session::put('tickets.st', $request->st);
|
||||
Session::remove('tickets.or');
|
||||
}
|
||||
if ($request->ty) {
|
||||
Session::put('tickets.ty', $request->ty);
|
||||
|
|
@ -534,6 +538,9 @@ class TicketController extends Controller
|
|||
if ($request->ass) {
|
||||
Session::put('tickets.ass', $request->ass);
|
||||
}
|
||||
if ($request->or && Session::has('tickets.pr')) {
|
||||
Session::put('tickets.or', $request->or);
|
||||
}
|
||||
Session::save();
|
||||
|
||||
if (Session::has('tickets.pr')) {
|
||||
|
|
@ -553,6 +560,13 @@ class TicketController extends Controller
|
|||
if (Session::has('tickets.ty')) {
|
||||
$tickets->where('type', Session::get('tickets.ty'));
|
||||
}
|
||||
|
||||
if (Session::has('tickets.or')) {
|
||||
$tickets->orderBy('order', 'ASC');
|
||||
} else {
|
||||
$tickets->orderBy('last_activity', 'DESC');
|
||||
}
|
||||
|
||||
return $tickets;
|
||||
}
|
||||
|
||||
|
|
@ -709,4 +723,62 @@ class TicketController extends Controller
|
|||
}
|
||||
return \sprintf("<br><br> Fichier %d : <br>%s<br>", $fileNb, $file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change order.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\UpdateChangeOrderRequest $request
|
||||
* @param mixed ...$params
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \RuntimeException Si le nom du parametre de la route ne correspond pas au params utilisé.
|
||||
*/
|
||||
public function changeOrder(UpdateChangeOrderRequest $request, mixed ...$params): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$paramNames = collect(request()->route()->parameterNames);
|
||||
$className = Str::of($paramNames->get($paramNames->count() - 2))->lower()->studly();
|
||||
$className = "\\App\\Models\\{$className}";
|
||||
$model = Arr::get($params, $paramNames->count() - 2);
|
||||
|
||||
if (!class_exists($className)) {
|
||||
throw new \RuntimeException("The {$className} class doesn't exist.");
|
||||
}
|
||||
|
||||
if (!\is_object($model)) {
|
||||
throw new \RuntimeException("The second last param isn't an object.");
|
||||
}
|
||||
|
||||
if (get_class($model) !== (string)Str::of($className)->replaceStart('\\', '')) {
|
||||
throw new \RuntimeException("The {$className} doesn't match second last binded param.");
|
||||
}
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Model|null */
|
||||
$model = $className::query()->where($model->getRouteKeyName(), $model->getRouteKey())->first();
|
||||
|
||||
if (!$model) {
|
||||
return back()->with('error', trans('crud.messages.order_not_changed'));
|
||||
}
|
||||
|
||||
return DB::transaction(function () use ($request, $className, $model) {
|
||||
/** @var \Illuminate\Support\Collection $models */
|
||||
$models = $className::query()
|
||||
->orderBy('order', 'ASC')
|
||||
->where('site_id', $model->site_id)
|
||||
->where('status', '!=', TicketStatusEnum::archived)
|
||||
->where('id', '!=', $model->getKey())
|
||||
->where('order', $request->direction ? '<' : '>', $model->order)
|
||||
->get();
|
||||
/** @var \Illuminate\Database\Eloquent\Model|null $tmp */
|
||||
$tmp = $request->direction ? $models->last() : $models->first();
|
||||
|
||||
if (!$tmp) {
|
||||
return back()->with('error', trans('crud.messages.order_not_changed'));
|
||||
}
|
||||
|
||||
$newOrder = $tmp->getOriginal('order');
|
||||
$tmp->update(['order' => $model->getOriginal('order')]);
|
||||
$model->update(['order' => $newOrder]);
|
||||
|
||||
return redirect()->back()->with('success', trans('crud.messages.order_changed'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -223,10 +223,6 @@ class Controller extends BaseController
|
|||
) {
|
||||
$query = $query->orderBy(\sprintf("$table.%s", request()->sort_col), request()->sort_way);
|
||||
}
|
||||
} elseif (Schema::hasColumn($table, 'order')) {
|
||||
$query = $query->orderBy('order', 'ASC');
|
||||
Session::put("$rName.sort_col", 'order');
|
||||
Session::put("$rName.sort_way", 'asc');
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use App\Enums\Tickets\TicketStatusEnum;
|
||||
use App\Models\Site;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
|
|
@ -16,16 +15,14 @@ return new class extends Migration
|
|||
public function up(): void
|
||||
{
|
||||
Schema::table('tickets', function (Blueprint $table) {
|
||||
$table->integer('order')->after('status')->comment('Ordre du ticket');
|
||||
$table->integer('order')->after('status')->comment('Ticket order.');
|
||||
});
|
||||
|
||||
Ticket::query()->where('status', '!=', TicketStatusEnum::archived)->get()->map(function ($ticket, $ticketIndex) {
|
||||
$ticket->order = $ticketIndex + 1;
|
||||
$ticket->saveQuietly();
|
||||
});
|
||||
Ticket::query()->where('status', '=', TicketStatusEnum::archived)->get()->map(function ($ticket, $ticketIndex) {
|
||||
$ticket->order = $ticketIndex + 1;
|
||||
$ticket->saveQuietly();
|
||||
Site::query()->get()->map(function ($site) {
|
||||
$site->tickets->map(function ($ticket, $ticketIndex) {
|
||||
$ticket->order = $ticketIndex + 1;
|
||||
$ticket->saveQuietly();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,5 +50,6 @@
|
|||
"Verify Your Email Address": "Verify Your Email Address",
|
||||
"Whoops!": "Whoops!",
|
||||
"You are logged in!": "You are logged in!",
|
||||
"You are receiving this email because we received a password reset request for your account.": "You are receiving this email because we received a password reset request for your account."
|
||||
}
|
||||
"You are receiving this email because we received a password reset request for your account.": "You are receiving this email because we received a password reset request for your account.",
|
||||
"see_mode": "see :mode mode"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -214,4 +214,12 @@ return [
|
|||
'username' => 'username',
|
||||
'year' => 'year',
|
||||
],
|
||||
'custom' => [
|
||||
'type' => 'type',
|
||||
'tickets' => 'tickets',
|
||||
'assigned_to' => 'assigned to',
|
||||
'order' => 'order',
|
||||
'priority' => 'priority',
|
||||
'default' => 'default',
|
||||
]
|
||||
];
|
||||
|
|
|
|||
|
|
@ -55,5 +55,6 @@
|
|||
"Verify Your Email Address": "Vérifiez votre adresse e-mail",
|
||||
"Whoops!": "Oups !",
|
||||
"You are logged in!": "Vous êtes connecté·e !",
|
||||
"You are receiving this email because we received a password reset request for your account.": "Vous recevez cet e-mail car nous avons reçu une demande de réinitialisation de mot de passe pour votre compte."
|
||||
}
|
||||
"You are receiving this email because we received a password reset request for your account.": "Vous recevez cet e-mail car nous avons reçu une demande de réinitialisation de mot de passe pour votre compte.",
|
||||
"see_mode": "voir mode :mode"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -255,5 +255,7 @@ return [
|
|||
'tickets' => 'étiquettes',
|
||||
'assigned_to' => 'assigné à',
|
||||
'order' => 'ordre',
|
||||
'priority' => 'priorité',
|
||||
'default' => 'défaut',
|
||||
]
|
||||
];
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import {
|
|||
faDeleteLeft,
|
||||
faDiagramProject,
|
||||
faDownload,
|
||||
faEquals,
|
||||
faEraser,
|
||||
faEye,
|
||||
faEyeSlash,
|
||||
|
|
@ -60,6 +61,7 @@ import {
|
|||
faTicket,
|
||||
faTimes,
|
||||
faTrash,
|
||||
faTriangleExclamation,
|
||||
faUndoAlt,
|
||||
faUsers,
|
||||
faWandMagic,
|
||||
|
|
@ -137,4 +139,6 @@ library.add(faCopy);
|
|||
library.add(faClipboard);
|
||||
library.add(faXmark);
|
||||
library.add(faArrowRightFromBracket);
|
||||
library.add(faTriangleExclamation);
|
||||
library.add(faEquals);
|
||||
dom.watch();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
<td class="text-center align-middle">
|
||||
@if (isset($value))
|
||||
{{ $value }}
|
||||
@endif
|
||||
@can('changeOrder', $model)
|
||||
<div class="d-flex justify-content-center align-items-center">
|
||||
<form @class(['invisible' => $loop->first and $models->onFirstPage()])
|
||||
|
|
@ -30,7 +33,7 @@
|
|||
</button>
|
||||
</form>
|
||||
</div>
|
||||
@else
|
||||
@elseif(isset($noRightsVisible) && $noRightsVisible)
|
||||
<span class="text-danger" data-bs-toggle="tooltip" title="{{ __('crud.other.right') }}">
|
||||
<i class="fa-solid fa-ban"></i>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -12,21 +12,7 @@
|
|||
@endphp
|
||||
<tr class="table-col-sorter border-start-0 border-end-0 border-top-0 border-secondary border border-2">
|
||||
@foreach ($cols as $col => $colname)
|
||||
@if($col === 'order')
|
||||
@if(
|
||||
!request()->sort_col
|
||||
&& !request()->sort_way
|
||||
&& !request()->ass
|
||||
&& !request()->st
|
||||
&& !request()->pr
|
||||
&& !request()->ty
|
||||
&& !request()->search
|
||||
)
|
||||
@include('bo.modules.table-col-sorter-cell')
|
||||
@endif
|
||||
@else
|
||||
@include('bo.modules.table-col-sorter-cell')
|
||||
@endif
|
||||
@include('bo.modules.table-col-sorter-cell')
|
||||
@endforeach
|
||||
{{-- Buttons Col --}}
|
||||
<th class="text-end" scope="col">
|
||||
|
|
@ -42,4 +28,4 @@
|
|||
</span>
|
||||
@endif
|
||||
</th>
|
||||
</tr>
|
||||
</tr>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@
|
|||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="d-inline">{{ __('Gestion des tickets') }} @if (Session::get('tickets.st') == \App\Enums\Tickets\TicketStatusEnum::archived->value)
|
||||
<h2 class="d-inline">
|
||||
{{ __('Gestion des tickets') }}
|
||||
@if (Session::get('tickets.st') == \App\Enums\Tickets\TicketStatusEnum::archived->value)
|
||||
(Archivés)
|
||||
@endif
|
||||
</h2>
|
||||
|
|
@ -24,23 +26,39 @@
|
|||
@can('isAdmin')
|
||||
<a class="btn btn-info" href="{{ route('bo.labels.index') }}"><i class="fa-solid fa-tags"></i></a>
|
||||
@endcan
|
||||
<a class="btn btn-primary" href="{{ route('bo.ticket.create') }}"><i
|
||||
class="fa-solid fa-square-plus"></i> {{ __('ticket') }}</a>
|
||||
<a class="btn btn-primary" href="{{ route('bo.ticket.create') }}">
|
||||
<i class="fa-solid fa-square-plus"></i> {{ __('ticket') }}
|
||||
</a>
|
||||
@if (session('tickets.pr') && session('tickets.st') != \App\Enums\Tickets\TicketStatusEnum::archived->value)
|
||||
@if (session('tickets.or'))
|
||||
<a class="btn btn-info float-end" href="{{ route('bo.ticket.index', ['ord' => -1]) }}">
|
||||
<i class="fa-solid fa-equals"></i> {{ __('see_mode', ['mode' => __('validation.custom.default')]) }}
|
||||
</a>
|
||||
@else
|
||||
<a class="btn btn-danger" href="{{ route('bo.ticket.index', ['or' => 1]) }}">
|
||||
<i class="fa-solid fa-triangle-exclamation"></i> {{ __('see_mode', ['mode' => __('validation.custom.priority')]) }}
|
||||
</a>
|
||||
@endif
|
||||
@endif
|
||||
@if (session('tickets.st') == \App\Enums\Tickets\TicketStatusEnum::archived->value)
|
||||
<a class="btn btn-success" href="{{ route('bo.ticket.index', ['sts' => -1]) }}"><i
|
||||
class="fa-solid fa-inbox"></i></a>
|
||||
<a class="btn btn-success" href="{{ route('bo.ticket.index', ['sts' => -1]) }}">
|
||||
<i class="fa-solid fa-inbox"></i>
|
||||
</a>
|
||||
@else
|
||||
<a class="btn btn-secondary float-end"
|
||||
href="{{ route('bo.ticket.index', ['st' => \App\Enums\Tickets\TicketStatusEnum::archived]) }}"><i
|
||||
class="fa-solid fa-box-archive"></i></a>
|
||||
href="{{ route('bo.ticket.index', ['st' => \App\Enums\Tickets\TicketStatusEnum::archived]) }}">
|
||||
<i class="fa-solid fa-box-archive"></i>
|
||||
</a>
|
||||
@endif
|
||||
<a class="btn btn-dark" href="{{ route('bo.ticket.index', ['rst' => 1]) }}"><i
|
||||
class="fa-solid fa-eraser"></i> {{ __(' le tri') }}</a>
|
||||
<a class="btn btn-dark" href="{{ route('bo.ticket.index', ['rst' => 1]) }}">
|
||||
<i class="fa-solid fa-eraser"></i> {{ __(' le tri') }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="float-end me-2">
|
||||
<div class="input-group">
|
||||
<label class="input-group-text" for="selectProject"><i
|
||||
class="fa-solid fa-diagram-project"></i></label>
|
||||
<label class="input-group-text" for="selectProject">
|
||||
<i class="fa-solid fa-diagram-project"></i>
|
||||
</label>
|
||||
<select class="form-select" id="selectProject">
|
||||
<option value="-1">{{ __('Tous') }}</option>
|
||||
@foreach ($sites as $site)
|
||||
|
|
@ -137,12 +155,12 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<form class="w-75 float-end mt-3" id="searchTicketForm"
|
||||
<form class="float-end mt-3" id="searchTicketForm"
|
||||
action="{{ request()->fullUrlWithQuery(['search' => '']) }}">
|
||||
<div class="input-group mb-3">
|
||||
<input class="form-control" id="searchTicket" name="search" type="text"
|
||||
value="{{ session()->get('tickets.search') }}" aria-label="{{ __('Recherche de ticket..') }}"
|
||||
aria-describedby="searchTicket" placeholder="{{ __('Recherche de ticket..') }}">
|
||||
value="{{ session()->get('tickets.search') }}" aria-label="{{ __('Recherche de ticket...') }}"
|
||||
aria-describedby="searchTicket" placeholder="{{ __('Recherche de ticket...') }}">
|
||||
<button class="btn btn-outline-danger" id="searchDelete" type="button"><i
|
||||
class="fa-solid fa-delete-left"></i></button>
|
||||
<button class="btn btn-outline-primary" type="submit"><i
|
||||
|
|
@ -165,17 +183,35 @@
|
|||
<div class="overflow-scroll w-100">
|
||||
<table class="table-hover table">
|
||||
<thead>
|
||||
@include('bo.modules.table-col-sorter', [
|
||||
'cols' => [
|
||||
@php
|
||||
$cols = [];
|
||||
if (session('tickets.or')) {
|
||||
$cols = array_merge($cols, [
|
||||
'order' => Str::ucfirst(__('validation.custom.priority'))
|
||||
]);
|
||||
}
|
||||
$cols = array_merge($cols, [
|
||||
'id' => Str::ucfirst(__('validation.attributes.id')),
|
||||
'title' => Str::ucfirst(__('validation.attributes.name')),
|
||||
'type' => Str::ucfirst(__('validation.custom.type')),
|
||||
'tickets' => Str::ucfirst(__('validation.custom.tickets')),
|
||||
'assigned_to' => Str::ucfirst(__('validation.custom.assigned_to')),
|
||||
'order' => Str::ucfirst(__('validation.custom.order')),
|
||||
]);
|
||||
if (Auth::user()->isAdmin()) {
|
||||
$cols = array_merge($cols, [
|
||||
'tickets' => Str::ucfirst(__('validation.custom.tickets')),
|
||||
]);
|
||||
}
|
||||
if (Auth::user()->isAdmin()) {
|
||||
$cols = array_merge($cols, [
|
||||
'assigned_to' => Str::ucfirst(__('validation.custom.assigned_to')),
|
||||
]);
|
||||
}
|
||||
$cols = array_merge($cols, [
|
||||
'created_at' => Str::ucfirst(__('validation.attributes.created_at')),
|
||||
],
|
||||
'ignore' => ['id', 'tickets']
|
||||
]);
|
||||
@endphp
|
||||
@include('bo.modules.table-col-sorter', [
|
||||
'cols' => $cols,
|
||||
'ignore' => ['id', 'tickets', 'order']
|
||||
])
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
@ -186,8 +222,19 @@
|
|||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
@foreach ($tickets as $ticket)
|
||||
@foreach ($tickets as $key => $ticket)
|
||||
<tr class="position-relative">
|
||||
{{-- order --}}
|
||||
@if (session('tickets.or'))
|
||||
@include('bo.modules.change-model-order', [
|
||||
'routeName' => 'ticket',
|
||||
'model' => $ticket,
|
||||
'models' => $tickets,
|
||||
'value' => $key + 1,
|
||||
'noRightsVisible' => false,
|
||||
])
|
||||
@endif
|
||||
{{-- id --}}
|
||||
<td scope="row">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span class="me-1">{{ $ticket->id }} @if ($ticket->is_internal)
|
||||
|
|
@ -209,12 +256,15 @@
|
|||
</span>
|
||||
</div>
|
||||
</td>
|
||||
{{-- title --}}
|
||||
<td class="text-center">
|
||||
<span class="me-1">{{ $ticket->title }}</span>
|
||||
</td>
|
||||
{{-- type --}}
|
||||
<td class="text-center">
|
||||
<span class="badge {{ $ticket->type->class() }}">{{ $ticket->type->label() }}</span>
|
||||
</td>
|
||||
{{-- tag --}}
|
||||
@php
|
||||
$routeName = request()->route()->getName();
|
||||
@endphp
|
||||
|
|
@ -228,24 +278,10 @@
|
|||
</span>
|
||||
</td>
|
||||
@endcan
|
||||
{{-- assigned_to --}}
|
||||
@if (Auth::user()->isAdmin())
|
||||
<td>{{ $ticket->assignedUser ? $ticket->assignedUser->name : __('Personne') }}</td>
|
||||
@endif
|
||||
@if (
|
||||
!request()->sort_col
|
||||
&& !request()->sort_way
|
||||
&& !request()->ass
|
||||
&& !request()->st
|
||||
&& !request()->pr
|
||||
&& !request()->ty
|
||||
&& !request()->search
|
||||
)
|
||||
@include('bo.modules.change-model-order', [
|
||||
'routeName' => 'ticket',
|
||||
'model' => $ticket,
|
||||
'models' => $tickets,
|
||||
])
|
||||
@endif
|
||||
<td>{{ Carbon\Carbon::parse($ticket->created_at)->format('d/m/Y à H:i') }}</td>
|
||||
<td>
|
||||
<div class="d-flex flex-column">
|
||||
|
|
|
|||
|
|
@ -95,6 +95,10 @@ Route::middleware('admin-secure')
|
|||
)
|
||||
->middleware('can:createGitlabIssue,ticket')
|
||||
->name('ticket.create-issue');
|
||||
Route::patch('/tickets/{ticket}/change-order/{direction}', [
|
||||
TicketController::class,
|
||||
'changeOrder'
|
||||
])->where('direction', 'up|down')->name('ticket.change-order');
|
||||
});
|
||||
Route::resource('credit_accounts', AccountController::class)
|
||||
->only(['index'])
|
||||
|
|
@ -147,10 +151,6 @@ Route::middleware('admin-secure')
|
|||
Route::post('/{ticket}/status', [TicketController::class, 'changeStatus'])
|
||||
->middleware('can:changeStatus,ticket')
|
||||
->name('changeStatus');
|
||||
Route::patch('/{ticket}/change-order/{direction}', [
|
||||
TicketController::class,
|
||||
'changeOrder'
|
||||
])->where('direction', 'up|down')->name('change-order');
|
||||
Route::post('/{ticket}/subscribe', [TicketController::class, 'subscribe'])
|
||||
->middleware('can:suscribeToTicket,ticket')
|
||||
->name('subscribe');
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue