improvements

This commit is contained in:
Mark Gregory
2026-08-26 09:25:29 +01:00
parent 53a11ae0c7
commit 21d7b6eba9
6 changed files with 209 additions and 38 deletions
@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
if (Schema::hasTable('helpdesk_team_user')) {
return;
}
Schema::create('helpdesk_team_user', static function (Blueprint $table): void {
$table->foreignId('team_id')
->constrained('helpdesk_teams')
->cascadeOnDelete();
$table->foreignId('user_id')
->constrained('users')
->cascadeOnDelete();
$table->timestamps();
$table->primary(['team_id', 'user_id']);
});
}
public function down(): void
{
Schema::dropIfExists('helpdesk_team_user');
}
};
+38 -8
View File
@@ -42,7 +42,7 @@ final class SettingsManager extends Component
public array $categoryForm = ['id' => null, 'name' => '', 'slug' => '', 'color' => 'blue', 'description' => '', 'is_default' => false];
/** @var array<string, mixed> */
public array $teamForm = ['id' => null, 'name' => '', 'slug' => '', 'color' => 'indigo', 'description' => '', 'is_default' => false, 'archived_at' => null];
public array $teamForm = ['id' => null, 'name' => '', 'slug' => '', 'color' => 'indigo', 'description' => '', 'is_default' => false, 'archived_at' => null, 'user_ids' => []];
/** @var array<string, mixed> */
public array $projectForm = ['id' => null, 'team_id' => null, 'title' => '', 'slug' => '', 'color' => 'blue', 'description' => '', 'is_default' => false, 'archived_at' => null];
@@ -80,7 +80,7 @@ final class SettingsManager extends Component
$this->statusForm += ['id' => null, 'name' => '', 'slug' => '', 'color' => 'gray', 'sort_order' => 0, 'is_closed' => false, 'is_default' => false];
$this->priorityForm += ['id' => null, 'name' => '', 'slug' => '', 'color' => 'gray', 'sort_order' => 0, 'is_default' => false];
$this->categoryForm += ['id' => null, 'name' => '', 'slug' => '', 'color' => 'blue', 'description' => '', 'is_default' => false];
$this->teamForm += ['id' => null, 'name' => '', 'slug' => '', 'color' => 'indigo', 'description' => '', 'is_default' => false, 'archived_at' => null];
$this->teamForm += ['id' => null, 'name' => '', 'slug' => '', 'color' => 'indigo', 'description' => '', 'is_default' => false, 'archived_at' => null, 'user_ids' => []];
$this->projectForm += ['id' => null, 'team_id' => null, 'title' => '', 'slug' => '', 'color' => 'blue', 'description' => '', 'is_default' => false, 'archived_at' => null];
$this->boardForm += ['id' => null, 'name' => '', 'slug' => '', 'description' => '', 'owner_id' => null, 'is_default' => false, 'sort_order' => 0, 'status_ids' => []];
$this->repositoryForm += ['id' => null, 'project_id' => null, 'name' => '', 'provider' => 'git', 'remote_url' => '', 'default_branch' => 'main', 'webhook_secret' => ''];
@@ -250,22 +250,33 @@ final class SettingsManager extends Component
'teamForm.color' => ['required', 'string', Color::validationRule()],
'teamForm.description' => ['nullable', 'string'],
'teamForm.is_default' => ['boolean'],
'teamForm.user_ids' => ['array'],
'teamForm.user_ids.*' => ['integer', 'distinct', 'exists:users,id'],
])['teamForm'];
$userIds = array_values(array_unique(array_map('intval', $data['user_ids'] ?? [])));
unset($data['user_ids']);
$data['slug'] = $this->slug($data['slug'] ?: $data['name']);
$data = $this->guardDefaultColumn('helpdesk_teams', $data);
if ((bool) ($data['is_default'] ?? false)) {
$this->clearOtherDefaults(Team::class, $this->teamForm['id']);
}
$this->persistSettingModel(Team::class, $this->teamForm['id'], $data);
/** @var Team $team */
$team = $this->persistSettingModel(Team::class, $this->teamForm['id'], $data);
$team->users()->sync($userIds);
$this->resetTeamForm();
session()->flash('success', 'Team saved.');
}
public function editTeam(int $id): void
{
$this->teamForm = Team::query()->findOrFail($id)->only(['id', 'name', 'slug', 'color', 'description', 'is_default', 'archived_at']);
$team = Team::query()->with('users:id')->findOrFail($id);
$this->teamForm = $team->only(['id', 'name', 'slug', 'color', 'description', 'is_default', 'archived_at']);
$this->teamForm['user_ids'] = $team->users->pluck('id')->map(static fn ($id): int => (int) $id)->all();
$this->teamForm['color'] = Color::normalise($this->teamForm['color'] ?? 'indigo');
$this->section = 'teams';
}
@@ -276,9 +287,24 @@ final class SettingsManager extends Component
session()->flash('success', 'Team deleted.');
}
public function removeUserFromTeam(int $teamId, int $userId): void
{
$team = Team::query()->findOrFail($teamId);
$team->users()->detach($userId);
if ((int) ($this->teamForm['id'] ?? 0) === $teamId) {
$this->teamForm['user_ids'] = array_values(array_filter(
array_map('intval', $this->teamForm['user_ids'] ?? []),
static fn (int $id): bool => $id !== $userId,
));
}
session()->flash('success', 'User removed from team.');
}
public function resetTeamForm(): void
{
$this->teamForm = ['id' => null, 'name' => '', 'slug' => '', 'color' => 'indigo', 'description' => '', 'is_default' => false, 'archived_at' => null];
$this->teamForm = ['id' => null, 'name' => '', 'slug' => '', 'color' => 'indigo', 'description' => '', 'is_default' => false, 'archived_at' => null, 'user_ids' => []];
}
public function saveProject(): void
@@ -699,11 +725,14 @@ final class SettingsManager extends Component
public function render(): View
{
return view('modules.helpdesk.livewire.settings-manager', [
return view('helpdesk::livewire.settings-manager', [
'statuses' => $this->orderedStatuses(),
'priorities' => $this->orderedPriorities(),
'categories' => $this->orderedCategories(),
'teams' => $this->orderedTeams(),
'teamUsers' => User::query()
->orderBy('name')
->get(['id', 'name', 'email', 'helpdesk_agent', 'helpdesk_admin']),
'projects' => $this->orderedProjects(),
'boardOwners' => User::query()->where(static function ($query): void {
$query->where('helpdesk_agent', true)->orWhere('helpdesk_admin', true);
@@ -718,7 +747,7 @@ final class SettingsManager extends Component
'tags' => Tag::query()->orderBy('name')->get(),
'checklistTemplates' => ChecklistTemplate::query()->orderBy('name')->get(),
'colourOptions' => Color::options(),
])->layout('layouts.app');
])->layout('helpdesk::layouts.app.sidebar');
}
private function orderedStatuses(): mixed
@@ -753,7 +782,8 @@ final class SettingsManager extends Component
private function orderedTeams(): mixed
{
return Team::query()
->withCount(['projects', 'tickets'])
->with(['users:id,name,email'])
->withCount(['projects', 'tickets', 'users'])
->when($this->hasDefaultColumn('helpdesk_teams'), fn ($query) => $query->orderByDesc('is_default'))
->orderBy('name')
->get();
+14
View File
@@ -4,8 +4,11 @@ declare(strict_types=1);
namespace Modules\Helpdesk\Models;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
@@ -25,6 +28,17 @@ final class Team extends Model
'is_default' => 'boolean',
];
/** @return BelongsToMany<User, Team> */
public function users(): BelongsToMany
{
return $this->belongsToMany(
User::class,
'helpdesk_team_user',
'team_id',
'user_id'
)->withTimestamps();
}
/** @return HasMany<Project> */
public function projects(): HasMany
{