ticket type rework
This commit is contained in:
@@ -3,40 +3,31 @@
|
||||
namespace App\Actions\ProjectTicketMetadata;
|
||||
|
||||
use App\Models\Project;
|
||||
use App\Models\TicketType;
|
||||
|
||||
class InitializeProjectTicketMetadata
|
||||
{
|
||||
public function handle(Project $project): void
|
||||
{
|
||||
$project->ticketTypes()->firstOrCreate(
|
||||
['system_key' => 'task'],
|
||||
$project->ticketTypes()->create(
|
||||
[
|
||||
'is_builtin' => true,
|
||||
'name' => 'Task',
|
||||
'position' => 1,
|
||||
],
|
||||
);
|
||||
|
||||
$project->ticketTypes()->firstOrCreate(
|
||||
['system_key' => 'parent'],
|
||||
$project->ticketTypes()->create(
|
||||
[
|
||||
'is_builtin' => true,
|
||||
'name' => 'Parent',
|
||||
'name' => 'Release',
|
||||
'is_parent' => true,
|
||||
'position' => 2,
|
||||
],
|
||||
);
|
||||
|
||||
$project->ticketTypes()
|
||||
->whereIn('system_key', TicketType::BUILTIN_KEYS)
|
||||
->orderBy('position')
|
||||
->get()
|
||||
->values()
|
||||
->each(function (TicketType $ticketType, int $index): void {
|
||||
$ticketType->forceFill([
|
||||
'is_builtin' => true,
|
||||
'position' => $index + 1,
|
||||
])->saveQuietly();
|
||||
});
|
||||
$project->ticketPriorities()->create(
|
||||
[
|
||||
'name' => 'Medium',
|
||||
'position' => 1,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -9,9 +9,9 @@ use Illuminate\Console\Attributes\Signature;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
#[Signature('app:create-initial-admin-user {name=Admin} {email=admin@kanbangit.test} {password=test}')]
|
||||
#[Signature('app:create-admin-user {name=Admin} {email=admin@kanbangit.test} {password=test}')]
|
||||
#[Description('Command description')]
|
||||
class CreateInitialAdminUser extends Command
|
||||
class CreateAdminUser extends Command
|
||||
{
|
||||
/**
|
||||
* Execute the console command.
|
||||
@@ -23,12 +23,13 @@ class CreateInitialAdminUser extends Command
|
||||
'email' => $this->argument('email'),
|
||||
'password' => Hash::make($this->argument('password')),
|
||||
]);
|
||||
$this->info('User created');
|
||||
|
||||
$user->permissionAssignments()->create([
|
||||
'permission' => Permission::GlobalAdmin,
|
||||
]);
|
||||
|
||||
$this->info(sprintf('Admin User created with emil=\'%s\' and password=\'%s\'', $this->argument('email'), $this->argument('password')));
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,9 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Actions\Permissions\PermissionService;
|
||||
use App\Actions\ProjectTicketMetadata\InitializeProjectTicketMetadata;
|
||||
use App\Enums\Permission;
|
||||
use App\Http\Requests\StoreProjectNamedSettingRequest;
|
||||
use App\Http\Requests\StoreProjectTicketTypeRequest;
|
||||
use App\Http\Requests\StoreTicketFieldDefinitionRequest;
|
||||
use App\Http\Requests\UpdateProjectNamedSettingRequest;
|
||||
use App\Http\Requests\UpdateTicketFieldDefinitionRequest;
|
||||
@@ -26,14 +26,12 @@ use Inertia\Response;
|
||||
class ProjectTicketMetadataSettingsController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly InitializeProjectTicketMetadata $initializeProjectTicketMetadata,
|
||||
private readonly PermissionService $permissionService,
|
||||
) {}
|
||||
|
||||
public function show(Request $request, Project $project): Response
|
||||
{
|
||||
$this->abortUnlessCanManage($request, $project);
|
||||
$this->initializeProjectTicketMetadata->handle($project);
|
||||
|
||||
return Inertia::render('projects/settings/Metadata', [
|
||||
'fieldTypeOptions' => collect(TicketFieldDefinition::FIELD_TYPES)
|
||||
@@ -43,6 +41,7 @@ class ProjectTicketMetadataSettingsController extends Controller
|
||||
])
|
||||
->all(),
|
||||
'project' => $project,
|
||||
'error' => session('error'),
|
||||
'status' => session('status'),
|
||||
'ticketFieldDefinitions' => $project->ticketFieldDefinitions()->get(),
|
||||
'ticketLinkTypes' => $project->ticketLinkTypes()->get(),
|
||||
@@ -51,27 +50,23 @@ class ProjectTicketMetadataSettingsController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function storeType(StoreProjectNamedSettingRequest $request, Project $project): RedirectResponse
|
||||
public function storeType(StoreProjectTicketTypeRequest $request, Project $project): RedirectResponse
|
||||
{
|
||||
$this->abortUnlessCanManage($request, $project);
|
||||
$this->initializeProjectTicketMetadata->handle($project);
|
||||
|
||||
$validated = $request->validated();
|
||||
$name = Arr::get($validated, 'name');
|
||||
$position = Arr::get($validated, 'position');
|
||||
|
||||
$ticketType = DB::transaction(function () use ($project, $name, $position): TicketType {
|
||||
$ticketType = DB::transaction(function () use ($project, $validated): TicketType {
|
||||
$ticketType = $project->ticketTypes()->create([
|
||||
'is_builtin' => false,
|
||||
'name' => $name,
|
||||
'name' => Arr::get($validated, 'name'),
|
||||
'position' => $project->ticketTypes()->count() + 1,
|
||||
'system_key' => null,
|
||||
'is_parent' => Arr::get($validated, 'is_parent', false),
|
||||
]);
|
||||
|
||||
$this->reorderModels(
|
||||
$project->ticketTypes()->whereKeyNot($ticketType->id)->get()->values(),
|
||||
$ticketType,
|
||||
$position ?? $project->ticketTypes()->count(),
|
||||
Arr::get($validated, 'position') ?? $project->ticketTypes()->count(),
|
||||
);
|
||||
|
||||
return $ticketType;
|
||||
@@ -87,21 +82,19 @@ class ProjectTicketMetadataSettingsController extends Controller
|
||||
TicketType $ticketType,
|
||||
): RedirectResponse {
|
||||
$this->abortUnlessCanManage($request, $project);
|
||||
$this->initializeProjectTicketMetadata->handle($project);
|
||||
|
||||
$validated = $request->validated();
|
||||
$name = Arr::get($validated, 'name');
|
||||
$position = Arr::get($validated, 'position');
|
||||
|
||||
DB::transaction(function () use ($project, $name, $position, $ticketType): void {
|
||||
DB::transaction(function () use ($project, $validated, $ticketType): void {
|
||||
$ticketType->update([
|
||||
'name' => $name,
|
||||
'name' => Arr::get($validated, 'name'),
|
||||
'is_parent' => Arr::get($validated, 'is_parent', false),
|
||||
]);
|
||||
|
||||
$this->reorderModels(
|
||||
$project->ticketTypes()->whereKeyNot($ticketType->id)->get()->values(),
|
||||
$ticketType,
|
||||
$position,
|
||||
Arr::get($validated, 'position'),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -113,7 +106,11 @@ class ProjectTicketMetadataSettingsController extends Controller
|
||||
{
|
||||
$this->abortUnlessCanManage($request, $project);
|
||||
|
||||
abort_if($ticketType->is_builtin, 403);
|
||||
if ($project->ticketTypes()->count() === 1) {
|
||||
return to_route('projects.settings.metadata', $project)
|
||||
->with('error', true)
|
||||
->with('status', 'The last ticket type cannot be deleted.');
|
||||
}
|
||||
|
||||
$deletedName = $ticketType->name;
|
||||
|
||||
@@ -188,6 +185,12 @@ class ProjectTicketMetadataSettingsController extends Controller
|
||||
): RedirectResponse {
|
||||
$this->abortUnlessCanManage($request, $project);
|
||||
|
||||
if ($project->ticketPriorities()->count() === 1) {
|
||||
return to_route('projects.settings.metadata', $project)
|
||||
->with('error', true)
|
||||
->with('status', 'The last ticket priority cannot be deleted.');
|
||||
}
|
||||
|
||||
$deletedName = $ticketPriority->name;
|
||||
|
||||
DB::transaction(function () use ($project, $ticketPriority): void {
|
||||
@@ -207,21 +210,18 @@ class ProjectTicketMetadataSettingsController extends Controller
|
||||
$this->abortUnlessCanManage($request, $project);
|
||||
|
||||
$validated = $request->validated();
|
||||
$label = Arr::get($validated, 'label');
|
||||
$fieldType = Arr::get($validated, 'field_type');
|
||||
$position = Arr::get($validated, 'position');
|
||||
|
||||
$ticketFieldDefinition = DB::transaction(function () use ($project, $fieldType, $label): TicketFieldDefinition {
|
||||
$ticketFieldDefinition = DB::transaction(function () use ($project, $validated): TicketFieldDefinition {
|
||||
$ticketFieldDefinition = $project->ticketFieldDefinitions()->create([
|
||||
'field_type' => $fieldType,
|
||||
'label' => $label,
|
||||
'field_type' => Arr::get($validated, 'field_type'),
|
||||
'label' => Arr::get($validated, 'label'),
|
||||
'position' => $project->ticketFieldDefinitions()->count() + 1,
|
||||
]);
|
||||
|
||||
$this->reorderModels(
|
||||
$project->ticketFieldDefinitions()->whereKeyNot($ticketFieldDefinition->id)->get()->values(),
|
||||
$ticketFieldDefinition,
|
||||
$position ?? $project->ticketFieldDefinitions()->count(),
|
||||
Arr::get($validated, 'position') ?? $project->ticketFieldDefinitions()->count(),
|
||||
);
|
||||
|
||||
return $ticketFieldDefinition;
|
||||
@@ -239,20 +239,17 @@ class ProjectTicketMetadataSettingsController extends Controller
|
||||
$this->abortUnlessCanManage($request, $project);
|
||||
|
||||
$validated = $request->validated();
|
||||
$label = Arr::get($validated, 'label');
|
||||
$fieldType = Arr::get($validated, 'field_type');
|
||||
$position = Arr::get($validated, 'position');
|
||||
|
||||
DB::transaction(function () use ($project, $fieldType, $label, $ticketFieldDefinition, $position): void {
|
||||
DB::transaction(function () use ($project, $ticketFieldDefinition, $validated): void {
|
||||
$ticketFieldDefinition->update([
|
||||
'field_type' => $fieldType,
|
||||
'label' => $label,
|
||||
'field_type' => Arr::get($validated, 'field_type'),
|
||||
'label' => Arr::get($validated, 'label'),
|
||||
]);
|
||||
|
||||
$this->reorderModels(
|
||||
$project->ticketFieldDefinitions()->whereKeyNot($ticketFieldDefinition->id)->get()->values(),
|
||||
$ticketFieldDefinition,
|
||||
$position,
|
||||
Arr::get($validated, 'position'),
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreProjectTicketTypeRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return $this->user() !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'position' => ['nullable', 'integer', 'min:1'],
|
||||
'is_parent' => ['nullable', 'boolean'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ class UpdateProjectNamedSettingRequest extends FormRequest
|
||||
return [
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'position' => ['required', 'integer', 'min:1'],
|
||||
'is_parent' => ['nullable', 'boolean'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,20 +8,19 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
#[Fillable(['is_builtin', 'name', 'position', 'project_id', 'system_key'])]
|
||||
#[Fillable(['name', 'position', 'project_id', 'is_parent'])]
|
||||
class TicketType extends Model
|
||||
{
|
||||
/**
|
||||
* @var array<int, string>
|
||||
*/
|
||||
public const BUILTIN_KEYS = [
|
||||
'task',
|
||||
'parent',
|
||||
];
|
||||
|
||||
/** @use HasFactory<TicketTypeFactory> */
|
||||
use HasFactory;
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'is_parent' => 'boolean',
|
||||
];
|
||||
}
|
||||
|
||||
public function project(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Project::class);
|
||||
|
||||
Reference in New Issue
Block a user