structure and style updates

This commit is contained in:
Mark Gregory
2026-06-16 23:21:49 +01:00
parent 80991208af
commit 2c2af4c50e
60 changed files with 209 additions and 216 deletions
+2 -3
View File
@@ -2,7 +2,6 @@
return [
'name' => 'AuditTrail',
'features' =>
[
],
'features' => [
],
];
+1
View File
@@ -1,4 +1,5 @@
<?php
use Modules\AuditTrail\Support\ModuleInfo;
if (! function_exists('audittrail_feature_enabled')) {
@@ -10,6 +10,7 @@ class AuditTrailController extends Controller
{
/**
* Display a listing of the resource.
*
* @return Renderable
*/
public function index()
@@ -19,6 +20,7 @@ class AuditTrailController extends Controller
/**
* Show the form for creating a new resource.
*
* @return Renderable
*/
public function create()
@@ -28,7 +30,7 @@ class AuditTrailController extends Controller
/**
* Store a newly created resource in storage.
* @param Request $request
*
* @return Renderable
*/
public function store(Request $request)
@@ -38,7 +40,8 @@ class AuditTrailController extends Controller
/**
* Show the specified resource.
* @param int $id
*
* @param int $id
* @return Renderable
*/
public function show($id)
@@ -48,7 +51,8 @@ class AuditTrailController extends Controller
/**
* Show the form for editing the specified resource.
* @param int $id
*
* @param int $id
* @return Renderable
*/
public function edit($id)
@@ -58,8 +62,8 @@ class AuditTrailController extends Controller
/**
* Update the specified resource in storage.
* @param Request $request
* @param int $id
*
* @param int $id
* @return Renderable
*/
public function update(Request $request, $id)
@@ -69,7 +73,8 @@ class AuditTrailController extends Controller
/**
* Remove the specified resource from storage.
* @param int $id
*
* @param int $id
* @return Renderable
*/
public function destroy($id)
@@ -2,41 +2,29 @@
namespace Modules\AuditTrail\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Database\Eloquent\Factory;
use Illuminate\Support\Facades\File;
use Modules\AuditTrail\Support\ModuleInfo;
use Config;
use Illuminate\Support\Facades\File;
use Illuminate\Support\ServiceProvider;
use Modules\AuditTrail\Support\ModuleInfo;
class AuditTrailServiceProvider extends ServiceProvider
{
/**
* @var string $moduleName
*/
protected string $moduleName = 'AuditTrail';
/**
* @var string $moduleNameLower
*/
protected string $moduleNameLower = 'audittrail';
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides():array
/**
* Get the services provided by the provider.
*/
public function provides(): array
{
return [];
}
/**
* Boot the application events.
*
* @return void
*/
public function boot() : void
public function boot(): void
{
$this->registerTranslations();
$this->registerConfig();
@@ -48,8 +36,6 @@ class AuditTrailServiceProvider extends ServiceProvider
/**
* Register the service provider.
*
* @return void
*/
public function register(): void
{
@@ -58,8 +44,6 @@ class AuditTrailServiceProvider extends ServiceProvider
/**
* Register the helpers.
*
* @return void
*/
protected function registerHelpers(): void
{
@@ -68,71 +52,64 @@ class AuditTrailServiceProvider extends ServiceProvider
}
}
/**
/**
* Dynamically Register Commands.
*
* @return void
*/
public function registerCommands(): void
{
if (!$this->app->runningInConsole()) {
return;
}
$commandPath = __DIR__ . '/../Console';
$commands = collect(File::allFiles($commandPath))
->map(function ($file) {
$class = 'Modules\\' . $this->moduleName . '\\Console\\' . $file->getFilenameWithoutExtension();
return $class;
})
->filter(function ($class) {
return class_exists($class);
})
->values()
->all();
$this->commands($commands);
{
if (! $this->app->runningInConsole()) {
return;
}
$commandPath = __DIR__.'/../Console';
$commands = collect(File::allFiles($commandPath))
->map(function ($file) {
$class = 'Modules\\'.$this->moduleName.'\\Console\\'.$file->getFilenameWithoutExtension();
return $class;
})
->filter(function ($class) {
return class_exists($class);
})
->values()
->all();
$this->commands($commands);
}
/**
* Register config.
*
* @return void
*/
protected function registerConfig(): void
{
$this->publishes([
module_path(ModuleInfo::name(), 'Config/config.php') => config_path( ModuleInfo::nameLower(). '.php'),
module_path(ModuleInfo::name(), 'Config/config.php') => config_path(ModuleInfo::nameLower().'.php'),
], 'config');
$this->mergeConfigFrom(
module_path(ModuleInfo::name(), 'Config/config.php'), ModuleInfo::nameLower()
module_path(ModuleInfo::name(), 'Config/config.php'), ModuleInfo::nameLower()
);
}
/**
* Register views.
*
* @return void
*/
public function registerViews(): void
{
$viewPath = resource_path('views/modules/' . ModuleInfo::nameLower());
$viewPath = resource_path('views/modules/'.ModuleInfo::nameLower());
$sourcePath = module_path(ModuleInfo::name(), 'Resources/views');
$this->publishes([
$sourcePath => $viewPath
], ['views', ModuleInfo::nameLower() . '-module-views']);
$this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), ModuleInfo::nameLower());
$sourcePath => $viewPath,
], ['views', ModuleInfo::nameLower().'-module-views']);
$this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), ModuleInfo::nameLower());
}
/**
* Register translations.
*
* @return void
*/
public function registerTranslations(): void
{
$langPath = resource_path('lang/modules/' . ModuleInfo::nameLower());
$langPath = resource_path('lang/modules/'.ModuleInfo::nameLower());
if (is_dir($langPath)) {
$this->loadTranslationsFrom($langPath, ModuleInfo::nameLower());
$this->loadTranslationsFrom($langPath, ModuleInfo::nameLower());
} else {
$this->loadTranslationsFrom(module_path(ModuleInfo::name(), 'Resources/lang'), ModuleInfo::nameLower());
}
@@ -140,16 +117,16 @@ class AuditTrailServiceProvider extends ServiceProvider
/**
* Regsiter View Paths
* @return array
*/
private function getPublishableViewPaths(): array
{
$paths = [];
foreach (Config::get('view.paths') as $path) {
if (is_dir($path . '/modules/' . ModuleInfo::nameLower())) {
$paths[] = $path . '/modules/' . ModuleInfo::nameLower();
if (is_dir($path.'/modules/'.ModuleInfo::nameLower())) {
$paths[] = $path.'/modules/'.ModuleInfo::nameLower();
}
}
return $paths;
}
}
@@ -2,8 +2,8 @@
namespace Modules\AuditTrail\Providers;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{
+1 -1
View File
@@ -15,4 +15,4 @@ use Illuminate\Http\Request;
Route::middleware('auth:api')->get('/audittrail', function (Request $request) {
return $request->user();
});
});
+1 -1
View File
@@ -11,6 +11,6 @@
|
*/
Route::prefix('audittrail')->group(function() {
Route::prefix('audittrail')->group(function () {
Route::get('/', 'AuditTrailController@index');
});
+1 -3
View File
@@ -4,11 +4,10 @@ namespace Modules\AuditTrail\Support;
class ModuleInfo
{
protected static string $moduleName = 'AuditTrail';
protected static string $moduleName = 'AuditTrail';
/**
* defines the Module Name
* @return string
*/
public static function name(): string
{
@@ -17,7 +16,6 @@ class ModuleInfo
/**
* define the lowercase version
* @return string
*/
public static function nameLower(): string
{
+1
View File
@@ -1,4 +1,5 @@
<?php
use Modules\Countries\Support\ModuleInfo;
if (! function_exists('countries_feature_enabled')) {
@@ -57,7 +57,7 @@ class CountriesController extends Controller
*/
public function create(): View
{
return view('countries::create', ['country' => new Country()]);
return view('countries::create', ['country' => new Country]);
}
/**
@@ -112,7 +112,6 @@ class CountriesController extends Controller
/**
* Build the database payload from validated request data.
*
* @param StoreCountryRequest|UpdateCountryRequest $request
* @return array<string, mixed>
*/
private function payload(StoreCountryRequest|UpdateCountryRequest $request): array
@@ -16,7 +16,6 @@ class StoreCountryRequest extends FormRequest
return (bool) $this->user()?->isMpbaPlatformAdmin();
}
/**
* Normalise ISO code inputs before validation.
*/
@@ -16,7 +16,6 @@ class UpdateCountryRequest extends FormRequest
return (bool) $this->user()?->isMpbaPlatformAdmin();
}
/**
* Normalise ISO code inputs before validation.
*/
@@ -125,6 +125,7 @@ class CountriesServiceProvider extends ServiceProvider
if (is_dir($publishedPath)) {
$this->loadTranslationsFrom($publishedPath, ModuleInfo::nameLower());
return;
}
+1 -3
View File
@@ -7,9 +7,7 @@ use Illuminate\Contracts\Validation\ValidationRule;
class ValidCountryCode implements ValidationRule
{
public function __construct(private readonly bool $activeOnly = true)
{
}
public function __construct(private readonly bool $activeOnly = true) {}
public function validate(string $attribute, mixed $value, Closure $fail): void
{
@@ -11,13 +11,13 @@ class ValidIso3166CountryCode implements ValidationRule
public function __construct(
private readonly bool $activeOnly = true,
private readonly string $format = 'alpha2',
) {
}
) {}
public function validate(string $attribute, mixed $value, Closure $fail): void
{
if (! is_string($value) && ! is_int($value)) {
$fail('The :attribute must be a valid ISO 3166 country code.');
return;
}
@@ -8,14 +8,13 @@ use Modules\Countries\Models\CountrySubdivision;
class ValidIso3166SubdivisionCode implements ValidationRule
{
public function __construct(private readonly bool $activeOnly = true)
{
}
public function __construct(private readonly bool $activeOnly = true) {}
public function validate(string $attribute, mixed $value, Closure $fail): void
{
if (! is_string($value) || ! preg_match('/^[A-Z]{2}-[A-Z0-9]{1,6}$/', strtoupper($value))) {
$fail('The :attribute must be a valid ISO 3166-2 subdivision code.');
return;
}
+5
View File
@@ -7,10 +7,15 @@ use InvalidArgumentException;
final class Iso3166
{
public const STATUS_OFFICIAL = 'official';
public const STATUS_RESERVED = 'reserved';
public const STATUS_TRANSITIONAL = 'transitional';
public const STATUS_DELETED = 'deleted';
public const STATUS_USER_ASSIGNED = 'user_assigned';
public const STATUS_EXCEPTIONALLY_RESERVED = 'exceptionally_reserved';
/** @return list<string> */
+1 -3
View File
@@ -4,11 +4,10 @@ namespace Modules\Countries\Support;
class ModuleInfo
{
protected static string $moduleName = 'Countries';
protected static string $moduleName = 'Countries';
/**
* defines the Module Name
* @return string
*/
public static function name(): string
{
@@ -17,7 +16,6 @@ class ModuleInfo
/**
* define the lowercase version
* @return string
*/
public static function nameLower(): string
{
@@ -4,8 +4,6 @@ namespace Modules\Countries\Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Modules\Countries\Database\Seeders\CountriesDatabaseSeeder;
use Modules\Countries\Models\Country;
use Modules\Countries\Models\CountrySubdivision;
use Modules\Countries\Rules\ValidIso3166CountryCode;
use Modules\Countries\Rules\ValidIso3166SubdivisionCode;
use Tests\TestCase;
@@ -9,9 +9,9 @@ use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Storage;
use Modules\Documentation\Http\Requests\StoreDocumentationDocumentRequest;
use Modules\Documentation\Http\Requests\UpdateDocumentationDocumentRequest;
use Modules\Documentation\Models\DocumentationAttachment;
use Modules\Documentation\Models\DocumentationCategory;
use Modules\Documentation\Models\DocumentationDocument;
use Modules\Documentation\Models\DocumentationAttachment;
class DocumentationController extends Controller
{
@@ -31,7 +31,7 @@ class DocumentationController extends Controller
}
if ($request->filled('search')) {
$search = '%' . $request->string('search')->trim()->toString() . '%';
$search = '%'.$request->string('search')->trim()->toString().'%';
$query->where(function ($builder) use ($search): void {
$builder->where('title', 'like', $search)
->orWhere('summary', 'like', $search)
@@ -197,7 +197,6 @@ class DocumentationController extends Controller
return redirect()->route('documentation.documents.edit', $document)->with('status', 'Attachment removed successfully.');
}
/**
* Extract body content from an uploaded Markdown file when requested.
*/
@@ -33,9 +33,9 @@ class StoreDocumentationDocumentRequest extends FormRequest
'is_featured' => ['nullable', 'boolean'],
'version' => ['required', 'string', 'max:50'],
'reference' => ['nullable', 'string', 'max:100'],
'attachment' => ['nullable', 'file', 'max:' . config('documentation.max_upload_kb', 20480), 'mimes:' . implode(',', config('documentation.allowed_upload_mimes', []))],
'attachment' => ['nullable', 'file', 'max:'.config('documentation.max_upload_kb', 20480), 'mimes:'.implode(',', config('documentation.allowed_upload_mimes', []))],
'attachments' => ['nullable', 'array'],
'attachments.*' => ['file', 'max:' . config('documentation.max_upload_kb', 20480), 'mimes:' . implode(',', config('documentation.allowed_upload_mimes', []))],
'attachments.*' => ['file', 'max:'.config('documentation.max_upload_kb', 20480), 'mimes:'.implode(',', config('documentation.allowed_upload_mimes', []))],
];
}
}
@@ -36,9 +36,9 @@ class UpdateDocumentationDocumentRequest extends FormRequest
'is_featured' => ['nullable', 'boolean'],
'version' => ['required', 'string', 'max:50'],
'reference' => ['nullable', 'string', 'max:100'],
'attachment' => ['nullable', 'file', 'max:' . config('documentation.max_upload_kb', 20480), 'mimes:' . implode(',', config('documentation.allowed_upload_mimes', []))],
'attachment' => ['nullable', 'file', 'max:'.config('documentation.max_upload_kb', 20480), 'mimes:'.implode(',', config('documentation.allowed_upload_mimes', []))],
'attachments' => ['nullable', 'array'],
'attachments.*' => ['file', 'max:' . config('documentation.max_upload_kb', 20480), 'mimes:' . implode(',', config('documentation.allowed_upload_mimes', []))],
'attachments.*' => ['file', 'max:'.config('documentation.max_upload_kb', 20480), 'mimes:'.implode(',', config('documentation.allowed_upload_mimes', []))],
'remove_attachment' => ['nullable', 'boolean'],
];
}
@@ -57,13 +57,13 @@ class DocumentationAttachment extends Model
}
if ($bytes < 1024) {
return $bytes . ' B';
return $bytes.' B';
}
if ($bytes < 1048576) {
return number_format($bytes / 1024, 1) . ' KB';
return number_format($bytes / 1024, 1).' KB';
}
return number_format($bytes / 1048576, 1) . ' MB';
return number_format($bytes / 1048576, 1).' MB';
}
}
@@ -66,7 +66,7 @@ class DocumentationCategory extends Model
/**
* Active category scope.
*
* @param Builder<DocumentationCategory> $query
* @param Builder<DocumentationCategory> $query
* @return Builder<DocumentationCategory>
*/
public function scopeActive(Builder $query): Builder
@@ -77,7 +77,7 @@ class DocumentationCategory extends Model
/**
* Ordered category scope.
*
* @param Builder<DocumentationCategory> $query
* @param Builder<DocumentationCategory> $query
* @return Builder<DocumentationCategory>
*/
public function scopeOrdered(Builder $query): Builder
@@ -29,7 +29,9 @@ class DocumentationDocument extends Model
use SoftDeletes;
public const STATUS_DRAFT = 'draft';
public const STATUS_PUBLISHED = 'published';
public const STATUS_ARCHIVED = 'archived';
/** @var list<string> */
@@ -99,7 +101,7 @@ class DocumentationDocument extends Model
/**
* Published document scope.
*
* @param Builder<DocumentationDocument> $query
* @param Builder<DocumentationDocument> $query
* @return Builder<DocumentationDocument>
*/
public function scopePublished(Builder $query): Builder
@@ -110,13 +112,14 @@ class DocumentationDocument extends Model
/**
* Featured document scope.
*
* @param Builder<DocumentationDocument> $query
* @param Builder<DocumentationDocument> $query
* @return Builder<DocumentationDocument>
*/
public function scopeFeatured(Builder $query): Builder
{
return $query->where('is_featured', true);
}
/**
* Render the document body as safe Markdown HTML for display.
*/
@@ -135,7 +138,7 @@ class DocumentationDocument extends Model
]);
}
return '<p>' . nl2br(e($body), false) . '</p>';
return '<p>'.nl2br(e($body), false).'</p>';
}
/**
@@ -148,5 +151,4 @@ class DocumentationDocument extends Model
return str_ends_with($name, '.md') || in_array($mime, ['text/markdown', 'text/x-markdown', 'text/plain'], true);
}
}
@@ -2,8 +2,8 @@
namespace Modules\Documentation\Providers;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{
@@ -2,13 +2,13 @@
namespace Modules\Documentation\Tests\Feature;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;
use Modules\Documentation\Models\DocumentationCategory;
use Modules\Documentation\Models\DocumentationDocument;
use Modules\Documentation\Models\DocumentationAttachment;
use Tests\TestCase;
class DocumentationModuleTest extends TestCase
{
@@ -17,7 +17,7 @@ class DocumentationModuleTest extends TestCase
/**
* Add a CSRF token for projects that keep web middleware enabled during tests.
*
* @param array<string, mixed> $payload
* @param array<string, mixed> $payload
* @return array<string, mixed>
*/
private function csrfPayload(array $payload): array
@@ -30,7 +30,7 @@ class DocumentationModuleTest extends TestCase
*/
public function test_documentation_dashboard_renders(): void
{
$user = \App\Models\User::factory()->create();
$user = User::factory()->create();
$this->actingAs($user)
->get(route('documentation.documents.index'))
@@ -43,7 +43,7 @@ class DocumentationModuleTest extends TestCase
*/
public function test_document_can_be_created(): void
{
$user = \App\Models\User::factory()->create();
$user = User::factory()->create();
$category = DocumentationCategory::query()->create([
'name' => 'Operations',
'slug' => 'operations',
@@ -72,7 +72,6 @@ class DocumentationModuleTest extends TestCase
]);
}
/**
* Markdown attachments are stored and imported into the document body.
*/
@@ -80,7 +79,7 @@ class DocumentationModuleTest extends TestCase
{
Storage::fake('public');
$user = \App\Models\User::factory()->create();
$user = User::factory()->create();
$file = UploadedFile::fake()->createWithContent('goods-in.md', "# Goods In\n\n- Scan delivery note\n- Confirm quantities");
$response = $this->actingAs($user)->withSession(['_token' => 'test-token'])->post(route('documentation.documents.store'), $this->csrfPayload([
@@ -102,8 +101,6 @@ class DocumentationModuleTest extends TestCase
Storage::disk('public')->assertExists($document->attachment_path);
}
/**
* Multiple supporting attachments can be uploaded, downloaded and removed.
*/
@@ -111,7 +108,7 @@ class DocumentationModuleTest extends TestCase
{
Storage::fake('public');
$user = \App\Models\User::factory()->create();
$user = User::factory()->create();
$response = $this->actingAs($user)->withSession(['_token' => 'test-token'])->post(route('documentation.documents.store'), $this->csrfPayload([
'title' => 'Attachment Pack',
@@ -153,7 +150,7 @@ class DocumentationModuleTest extends TestCase
*/
public function test_document_editor_has_markdown_code_controls(): void
{
$user = \App\Models\User::factory()->create();
$user = User::factory()->create();
$this->actingAs($user)
->get(route('documentation.documents.create'))
@@ -168,7 +165,7 @@ class DocumentationModuleTest extends TestCase
*/
public function test_category_can_be_created(): void
{
$user = \App\Models\User::factory()->create();
$user = User::factory()->create();
$this->actingAs($user)->withSession(['_token' => 'test-token'])->post(route('documentation.categories.store'), $this->csrfPayload([
'name' => 'Policies',
+1 -1
View File
@@ -7,7 +7,7 @@ return [
'middleware' => ['web', 'auth'],
'disk' => env('HELPDESK_ATTACHMENTS_DISK', 'local'),
'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',
];
@@ -24,7 +24,6 @@ return new class extends Migration
$table->unique(['company_id', 'slug']);
});
Schema::create('helpdesk_sla_policies', static function (Blueprint $table): void {
$table->id();
$table->foreignId('company_id')->nullable()->constrained('companies')->nullOnDelete();
@@ -107,8 +106,6 @@ return new class extends Migration
$table->index(['category_id', 'team_id', 'is_active']);
});
Schema::create('helpdesk_automation_rules', static function (Blueprint $table): void {
$table->id();
$table->foreignId('company_id')->nullable()->constrained('companies')->nullOnDelete();
@@ -126,7 +126,7 @@ final class TicketControlsController extends Controller
/**
* Apply a direct guarded ticket update without relying on Livewire hydration.
*
* @param array<string, mixed> $updates
* @param array<string, mixed> $updates
*/
private function updateTicket(Ticket $ticket, array $updates): void
{
+1 -4
View File
@@ -6,8 +6,8 @@ namespace Modules\Helpdesk\Livewire;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Livewire\Component;
use Modules\Helpdesk\Models\KanbanBoard as KanbanBoardModel;
use Modules\Helpdesk\Models\Status;
@@ -99,9 +99,6 @@ final class KanbanBoard extends Component
/**
* Normalise the board selector value from Livewire/browser select events.
*
* @param int|string|null $value
* @return void
*/
public function updatedBoardId(int|string|null $value): void
{
+13 -17
View File
@@ -12,15 +12,15 @@ use Illuminate\Support\Str;
use Livewire\Component;
use Modules\Helpdesk\Models\AutomationRule;
use Modules\Helpdesk\Models\CannedResponse;
use Modules\Helpdesk\Models\ChecklistTemplate;
use Modules\Helpdesk\Models\Category;
use Modules\Helpdesk\Models\ChecklistTemplate;
use Modules\Helpdesk\Models\GitRepository;
use Modules\Helpdesk\Models\KanbanBoard;
use Modules\Helpdesk\Models\Priority;
use Modules\Helpdesk\Models\Product;
use Modules\Helpdesk\Models\Project;
use Modules\Helpdesk\Models\Status;
use Modules\Helpdesk\Models\SlaPolicy;
use Modules\Helpdesk\Models\Status;
use Modules\Helpdesk\Models\Tag;
use Modules\Helpdesk\Models\Team;
use Modules\Helpdesk\Models\WorkflowTemplate;
@@ -297,7 +297,6 @@ final class SettingsManager extends Component
$this->projectForm = ['id' => null, 'company_id' => null, 'team_id' => null, 'title' => '', 'slug' => '', 'color' => 'blue', 'description' => '', 'is_default' => false, 'archived_at' => null];
}
public function saveBoard(): void
{
$data = $this->validate([
@@ -435,7 +434,6 @@ final class SettingsManager extends Component
$this->workflowForm = ['id' => null, 'name' => '', 'event' => 'ticket.created', 'subject' => '', 'html_body' => '', 'text_body' => '', 'to_role' => 'requester', 'cc' => '', 'bcc' => '', 'is_active' => true];
}
public function saveCannedResponse(): void
{
$data = $this->validate([
@@ -458,7 +456,7 @@ final class SettingsManager extends Component
public function editCannedResponse(int $id): void
{
$this->cannedForm = CannedResponse::query()->findOrFail($id)->only(['id','company_id','category_id','team_id','name','slug','visibility','subject','body','is_active','sort_order']);
$this->cannedForm = CannedResponse::query()->findOrFail($id)->only(['id', 'company_id', 'category_id', 'team_id', 'name', 'slug', 'visibility', 'subject', 'body', 'is_active', 'sort_order']);
$this->section = 'canned';
}
@@ -498,7 +496,7 @@ final class SettingsManager extends Component
public function editSlaPolicy(int $id): void
{
$this->slaForm = SlaPolicy::query()->findOrFail($id)->only(['id','company_id','priority_id','category_id','name','slug','first_response_minutes','resolution_minutes','business_hours_only','is_default','is_active']);
$this->slaForm = SlaPolicy::query()->findOrFail($id)->only(['id', 'company_id', 'priority_id', 'category_id', 'name', 'slug', 'first_response_minutes', 'resolution_minutes', 'business_hours_only', 'is_default', 'is_active']);
$this->section = 'sla';
}
@@ -540,7 +538,7 @@ final class SettingsManager extends Component
public function editAutomationRule(int $id): void
{
$this->automationForm = AutomationRule::query()->findOrFail($id)->only(['id','company_id','name','slug','match_sender','match_subject','match_mailbox','match_category_id','set_priority_id','set_category_id','set_team_id','set_project_id','set_status_id','set_agent_id','is_active','sort_order']);
$this->automationForm = AutomationRule::query()->findOrFail($id)->only(['id', 'company_id', 'name', 'slug', 'match_sender', 'match_subject', 'match_mailbox', 'match_category_id', 'set_priority_id', 'set_category_id', 'set_team_id', 'set_project_id', 'set_status_id', 'set_agent_id', 'is_active', 'sort_order']);
$this->section = 'automation';
}
@@ -575,7 +573,7 @@ final class SettingsManager extends Component
public function editProduct(int $id): void
{
$this->productForm = Product::query()->findOrFail($id)->only(['id','company_id','name','slug','type','version','release_channel','description','is_active']);
$this->productForm = Product::query()->findOrFail($id)->only(['id', 'company_id', 'name', 'slug', 'type', 'version', 'release_channel', 'description', 'is_active']);
$this->section = 'products';
}
@@ -606,7 +604,7 @@ final class SettingsManager extends Component
public function editTag(int $id): void
{
$this->tagForm = Tag::query()->findOrFail($id)->only(['id','company_id','name','slug','color']);
$this->tagForm = Tag::query()->findOrFail($id)->only(['id', 'company_id', 'name', 'slug', 'color']);
$this->section = 'tags';
}
@@ -644,7 +642,7 @@ final class SettingsManager extends Component
public function editChecklistTemplate(int $id): void
{
$template = ChecklistTemplate::query()->findOrFail($id);
$this->checklistTemplateForm = $template->only(['id','company_id','category_id','project_id','name','slug','is_active']) + [
$this->checklistTemplateForm = $template->only(['id', 'company_id', 'category_id', 'project_id', 'name', 'slug', 'is_active']) + [
'items_text' => collect($template->items ?? [])->map(fn ($item): string => is_array($item) ? (string) ($item['title'] ?? '') : (string) $item)->implode("\n"),
];
$this->section = 'checklists';
@@ -661,7 +659,6 @@ final class SettingsManager extends Component
$this->checklistTemplateForm = ['id' => null, 'company_id' => null, 'category_id' => null, 'project_id' => null, 'name' => '', 'slug' => '', 'items_text' => '', 'is_active' => true];
}
public function saveDefaultHelpdeskCompany(): void
{
if (! Schema::hasTable('companies') || ! Schema::hasColumn('companies', 'is_default_helpdesk_company')) {
@@ -709,12 +706,14 @@ final class SettingsManager extends Component
'categories' => $this->orderedCategories(),
'teams' => $this->orderedTeams(),
'projects' => $this->orderedProjects(),
'boardOwners' => User::query()->where(static function ($query): void { $query->where('helpdesk_agent', true)->orWhere('helpdesk_admin', true); })->orderBy('name')->get(['id', 'name', 'email']),
'boardOwners' => User::query()->where(static function ($query): void {
$query->where('helpdesk_agent', true)->orWhere('helpdesk_admin', true);
})->orderBy('name')->get(['id', 'name', 'email']),
'boards' => KanbanBoard::query()->with(['statuses', 'owner:id,name,email'])->withCount('tickets')->orderBy('sort_order')->orderBy('name')->get(),
'repositories' => GitRepository::query()->with(['project'])->withCount(['commits', 'webhookLogs'])->orderBy('name')->get(),
'workflowTemplates' => WorkflowTemplate::query()->orderBy('event')->orderBy('name')->get(),
'cannedResponses' => CannedResponse::query()->with(['category','team'])->orderBy('sort_order')->orderBy('name')->get(),
'slaPolicies' => SlaPolicy::query()->with(['priority','category'])->orderByDesc('is_default')->orderBy('name')->get(),
'cannedResponses' => CannedResponse::query()->with(['category', 'team'])->orderBy('sort_order')->orderBy('name')->get(),
'slaPolicies' => SlaPolicy::query()->with(['priority', 'category'])->orderByDesc('is_default')->orderBy('name')->get(),
'automationRules' => AutomationRule::query()->orderBy('sort_order')->orderBy('name')->get(),
'products' => Product::query()->withCount('tickets')->orderBy('name')->get(),
'tags' => Tag::query()->orderBy('name')->get(),
@@ -722,8 +721,6 @@ final class SettingsManager extends Component
])->layout('layouts.app');
}
private function orderedStatuses(): mixed
{
return Status::query()
@@ -772,7 +769,6 @@ final class SettingsManager extends Component
->get();
}
/**
* Remove is_default before save when the database has not been migrated yet.
*
+1 -6
View File
@@ -17,8 +17,8 @@ use Modules\Helpdesk\Models\KanbanBoard;
use Modules\Helpdesk\Models\Priority;
use Modules\Helpdesk\Models\Product;
use Modules\Helpdesk\Models\Project;
use Modules\Helpdesk\Models\Team;
use Modules\Helpdesk\Models\Tag;
use Modules\Helpdesk\Models\Team;
use Modules\Helpdesk\Services\TicketService;
final class TicketCreate extends Component
@@ -55,7 +55,6 @@ final class TicketCreate extends Component
#[Validate('nullable|date')]
public ?string $due_at = null;
/** @var array<int, int> */
#[Validate('array')]
public array $tag_ids = [];
@@ -102,7 +101,6 @@ final class TicketCreate extends Component
return $this->redirectRoute('helpdesk.tickets.index', navigate: true);
}
/**
* Clear the create form, including Select2 and Flatpickr browser widgets.
*/
@@ -154,7 +152,6 @@ final class TicketCreate extends Component
->value('id');
}
if (blank($this->board_id) && Schema::hasTable('helpdesk_kanban_boards')) {
$this->board_id = KanbanBoard::query()
->where('is_default', true)
@@ -213,8 +210,6 @@ final class TicketCreate extends Component
}
}
/**
* Return Kanban board options with the default board listed first.
*/
-1
View File
@@ -7,7 +7,6 @@ namespace Modules\Helpdesk\Livewire;
use App\Models\User;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
+3 -2
View File
@@ -10,14 +10,15 @@ use Illuminate\Database\Eloquent\Collection as EloquentCollection;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Schema;
use Illuminate\Validation\Rule;
use Livewire\Attributes\Validate;
use Livewire\Component;
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
use Livewire\WithFileUploads;
use Modules\Helpdesk\Models\CannedResponse;
use Modules\Helpdesk\Models\ChecklistItem;
use Modules\Helpdesk\Models\Comment;
use Modules\Helpdesk\Models\Priority;
use Modules\Helpdesk\Models\Status;
use Modules\Helpdesk\Models\Ticket;
@@ -299,7 +300,7 @@ final class TicketShow extends Component
$this->hydrateTicketUsers($ticket);
$comments = \Modules\Helpdesk\Models\Comment::query()
$comments = Comment::query()
->where('ticket_id', $ticket->id)
->with(['user.company', 'attachments'])
->oldest()
+4 -2
View File
@@ -9,6 +9,8 @@ use Illuminate\Database\Eloquent\Model;
final class AutomationRule extends Model
{
protected $table = 'helpdesk_automation_rules';
protected $fillable = ['company_id','name','slug','match_sender','match_subject','match_mailbox','match_category_id','set_priority_id','set_category_id','set_team_id','set_project_id','set_status_id','set_agent_id','is_active','sort_order'];
protected $casts = ['company_id'=>'integer','match_category_id'=>'integer','set_priority_id'=>'integer','set_category_id'=>'integer','set_team_id'=>'integer','set_project_id'=>'integer','set_status_id'=>'integer','set_agent_id'=>'integer','is_active'=>'boolean','sort_order'=>'integer'];
protected $fillable = ['company_id', 'name', 'slug', 'match_sender', 'match_subject', 'match_mailbox', 'match_category_id', 'set_priority_id', 'set_category_id', 'set_team_id', 'set_project_id', 'set_status_id', 'set_agent_id', 'is_active', 'sort_order'];
protected $casts = ['company_id' => 'integer', 'match_category_id' => 'integer', 'set_priority_id' => 'integer', 'set_category_id' => 'integer', 'set_team_id' => 'integer', 'set_project_id' => 'integer', 'set_status_id' => 'integer', 'set_agent_id' => 'integer', 'is_active' => 'boolean', 'sort_order' => 'integer'];
}
+14 -4
View File
@@ -10,8 +10,18 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
final class CannedResponse extends Model
{
protected $table = 'helpdesk_canned_responses';
protected $fillable = ['company_id','category_id','team_id','name','slug','visibility','subject','body','is_active','sort_order'];
protected $casts = ['company_id'=>'integer','category_id'=>'integer','team_id'=>'integer','is_active'=>'boolean','sort_order'=>'integer'];
public function category(): BelongsTo { return $this->belongsTo(Category::class, 'category_id'); }
public function team(): BelongsTo { return $this->belongsTo(Team::class, 'team_id'); }
protected $fillable = ['company_id', 'category_id', 'team_id', 'name', 'slug', 'visibility', 'subject', 'body', 'is_active', 'sort_order'];
protected $casts = ['company_id' => 'integer', 'category_id' => 'integer', 'team_id' => 'integer', 'is_active' => 'boolean', 'sort_order' => 'integer'];
public function category(): BelongsTo
{
return $this->belongsTo(Category::class, 'category_id');
}
public function team(): BelongsTo
{
return $this->belongsTo(Team::class, 'team_id');
}
}
+9 -3
View File
@@ -10,7 +10,13 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
final class ChecklistItem extends Model
{
protected $table = 'helpdesk_checklist_items';
protected $fillable = ['ticket_id','template_id','title','description','is_completed','completed_by','completed_at','sort_order'];
protected $casts = ['ticket_id'=>'integer','template_id'=>'integer','is_completed'=>'boolean','completed_by'=>'integer','completed_at'=>'datetime','sort_order'=>'integer'];
public function ticket(): BelongsTo { return $this->belongsTo(Ticket::class, 'ticket_id'); }
protected $fillable = ['ticket_id', 'template_id', 'title', 'description', 'is_completed', 'completed_by', 'completed_at', 'sort_order'];
protected $casts = ['ticket_id' => 'integer', 'template_id' => 'integer', 'is_completed' => 'boolean', 'completed_by' => 'integer', 'completed_at' => 'datetime', 'sort_order' => 'integer'];
public function ticket(): BelongsTo
{
return $this->belongsTo(Ticket::class, 'ticket_id');
}
}
@@ -9,6 +9,8 @@ use Illuminate\Database\Eloquent\Model;
final class ChecklistTemplate extends Model
{
protected $table = 'helpdesk_checklist_templates';
protected $fillable = ['company_id','category_id','project_id','name','slug','items','is_active'];
protected $casts = ['company_id'=>'integer','category_id'=>'integer','project_id'=>'integer','items'=>'array','is_active'=>'boolean'];
protected $fillable = ['company_id', 'category_id', 'project_id', 'name', 'slug', 'items', 'is_active'];
protected $casts = ['company_id' => 'integer', 'category_id' => 'integer', 'project_id' => 'integer', 'items' => 'array', 'is_active' => 'boolean'];
}
+1 -1
View File
@@ -4,9 +4,9 @@ declare(strict_types=1);
namespace Modules\Helpdesk\Models;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Models\User;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
+9 -3
View File
@@ -10,7 +10,13 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
final class Product extends Model
{
protected $table = 'helpdesk_products';
protected $fillable = ['company_id','name','slug','type','version','release_channel','description','is_active'];
protected $casts = ['company_id'=>'integer','is_active'=>'boolean'];
public function tickets(): HasMany { return $this->hasMany(Ticket::class, 'product_id'); }
protected $fillable = ['company_id', 'name', 'slug', 'type', 'version', 'release_channel', 'description', 'is_active'];
protected $casts = ['company_id' => 'integer', 'is_active' => 'boolean'];
public function tickets(): HasMany
{
return $this->hasMany(Ticket::class, 'product_id');
}
}
+14 -4
View File
@@ -10,8 +10,18 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
final class SlaPolicy extends Model
{
protected $table = 'helpdesk_sla_policies';
protected $fillable = ['company_id','priority_id','category_id','name','slug','first_response_minutes','resolution_minutes','business_hours_only','is_default','is_active'];
protected $casts = ['company_id'=>'integer','priority_id'=>'integer','category_id'=>'integer','first_response_minutes'=>'integer','resolution_minutes'=>'integer','business_hours_only'=>'boolean','is_default'=>'boolean','is_active'=>'boolean'];
public function priority(): BelongsTo { return $this->belongsTo(Priority::class, 'priority_id'); }
public function category(): BelongsTo { return $this->belongsTo(Category::class, 'category_id'); }
protected $fillable = ['company_id', 'priority_id', 'category_id', 'name', 'slug', 'first_response_minutes', 'resolution_minutes', 'business_hours_only', 'is_default', 'is_active'];
protected $casts = ['company_id' => 'integer', 'priority_id' => 'integer', 'category_id' => 'integer', 'first_response_minutes' => 'integer', 'resolution_minutes' => 'integer', 'business_hours_only' => 'boolean', 'is_default' => 'boolean', 'is_active' => 'boolean'];
public function priority(): BelongsTo
{
return $this->belongsTo(Priority::class, 'priority_id');
}
public function category(): BelongsTo
{
return $this->belongsTo(Category::class, 'category_id');
}
}
+9 -3
View File
@@ -10,7 +10,13 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany;
final class Tag extends Model
{
protected $table = 'helpdesk_tags';
protected $fillable = ['company_id','name','slug','color'];
protected $casts = ['company_id'=>'integer'];
public function tickets(): BelongsToMany { return $this->belongsToMany(Ticket::class, 'helpdesk_ticket_tag', 'tag_id', 'ticket_id'); }
protected $fillable = ['company_id', 'name', 'slug', 'color'];
protected $casts = ['company_id' => 'integer'];
public function tickets(): BelongsToMany
{
return $this->belongsToMany(Ticket::class, 'helpdesk_ticket_tag', 'tag_id', 'ticket_id');
}
}
-1
View File
@@ -114,7 +114,6 @@ final class Ticket extends Model
->oldest();
}
/** @return BelongsTo<SlaPolicy, Ticket> */
public function slaPolicy(): BelongsTo
{
+4 -2
View File
@@ -9,6 +9,8 @@ use Illuminate\Database\Eloquent\Model;
final class TicketRating extends Model
{
protected $table = 'helpdesk_ticket_ratings';
protected $fillable = ['ticket_id','agent_id','team_id','category_id','rating','token','comment','rated_at'];
protected $casts = ['ticket_id'=>'integer','agent_id'=>'integer','team_id'=>'integer','category_id'=>'integer','rating'=>'integer','rated_at'=>'datetime'];
protected $fillable = ['ticket_id', 'agent_id', 'team_id', 'category_id', 'rating', 'token', 'comment', 'rated_at'];
protected $casts = ['ticket_id' => 'integer', 'agent_id' => 'integer', 'team_id' => 'integer', 'category_id' => 'integer', 'rating' => 'integer', 'rated_at' => 'datetime'];
}
+4 -2
View File
@@ -9,6 +9,8 @@ use Illuminate\Database\Eloquent\Model;
final class TicketSlaEvent extends Model
{
protected $table = 'helpdesk_ticket_sla_events';
protected $fillable = ['ticket_id','sla_policy_id','event','due_at','occurred_at','breached','meta'];
protected $casts = ['ticket_id'=>'integer','sla_policy_id'=>'integer','due_at'=>'datetime','occurred_at'=>'datetime','breached'=>'boolean','meta'=>'array'];
protected $fillable = ['ticket_id', 'sla_policy_id', 'event', 'due_at', 'occurred_at', 'breached', 'meta'];
protected $casts = ['ticket_id' => 'integer', 'sla_policy_id' => 'integer', 'due_at' => 'datetime', 'occurred_at' => 'datetime', 'breached' => 'boolean', 'meta' => 'array'];
}
+1 -1
View File
@@ -5,8 +5,8 @@ declare(strict_types=1);
use Illuminate\Support\Facades\Route;
use Modules\Helpdesk\Http\Controllers\AttachmentDownloadController;
use Modules\Helpdesk\Http\Controllers\HelpdeskController;
use Modules\Helpdesk\Http\Controllers\TicketStoreController;
use Modules\Helpdesk\Http\Controllers\TicketControlsController;
use Modules\Helpdesk\Http\Controllers\TicketStoreController;
use Modules\Helpdesk\Http\Controllers\WorkflowOpenController;
use Modules\Helpdesk\Livewire\KanbanBoard;
use Modules\Helpdesk\Livewire\SettingsManager;
@@ -9,7 +9,6 @@ use Modules\Helpdesk\Database\Seeders\HelpdeskDatabaseSeeder as DatabaseHelpdesk
final class HelpdeskDatabaseSeeder extends Seeder
{
/** @return void */
public function run(): void
{
$this->call(DatabaseHelpdeskDatabaseSeeder::class);
@@ -66,5 +66,4 @@ final class CannedResponseRenderer
$ticket->setRelation('owner', $owner);
$ticket->setRelation('agent', $agent);
}
}
@@ -19,7 +19,7 @@ final class GitWebhookIngestionService
/**
* Persist supported Git provider commits and link them to matching Helpdesk ticket references.
*
* @param array<string, mixed> $payload
* @param array<string, mixed> $payload
* @return array{status: string, message: string, commit_count: int, linked_count: int, ignored_count: int}
*/
public function ingest(GitRepository $repository, array $payload, string $provider, ?string $deliveryId, ?string $event): array
@@ -102,8 +102,8 @@ final class GitWebhookIngestionService
/**
* Record a provider webhook acceptance, rejection or ignore decision for auditability.
*
* @param array{status: string, message: string, commit_count?: int, linked_count?: int, ignored_count?: int} $result
* @param array<string, mixed>|null $payload
* @param array{status: string, message: string, commit_count?: int, linked_count?: int, ignored_count?: int} $result
* @param array<string, mixed>|null $payload
*/
public function logWebhook(GitRepository $repository, string $provider, ?string $deliveryId, ?string $event, array $result, ?array $payload = null): void
{
@@ -158,9 +158,6 @@ final class GitWebhookIngestionService
};
}
/**
* @param mixed $value
*/
private function branchFromRef(mixed $value): ?string
{
$ref = $this->stringOrNull($value);
@@ -173,7 +170,7 @@ final class GitWebhookIngestionService
}
/**
* @param array<string, mixed> $payload
* @param array<string, mixed> $payload
* @return array<int, array<string, mixed>>
*/
private function commitsFromPayload(array $payload): array
@@ -208,9 +205,6 @@ final class GitWebhookIngestionService
return $query->first();
}
/**
* @param mixed $value
*/
private function parseTimestamp(mixed $value): ?CarbonImmutable
{
$timestamp = $this->stringOrNull($value);
@@ -226,9 +220,6 @@ final class GitWebhookIngestionService
}
}
/**
* @param mixed $value
*/
private function stringOrNull(mixed $value): ?string
{
if (! is_scalar($value)) {
@@ -9,10 +9,10 @@ use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Str;
use Modules\Helpdesk\Models\Ticket;
use Modules\Helpdesk\Models\WorkflowLog;
use Modules\Helpdesk\Models\WorkflowTemplate;
use Illuminate\Support\Str;
use Throwable;
final class WorkflowNotificationService
@@ -88,6 +88,7 @@ if (! component) {
window.Livewire.find(component.getAttribute('wire:id')).set({$encodedProperty}, {$encodedValue});
JS);
}
private function setTicketShowProperty(Browser $browser, string $property, mixed $value): void
{
$encodedProperty = json_encode($property, JSON_THROW_ON_ERROR);
@@ -95,6 +95,7 @@ final class KanbanBoardTest extends TestCase
$this->assertSame($targetBoard->id, $ticket->board_id);
}
/** @test */
public function kanban_board_filters_tickets_to_the_selected_board_only(): void
{
@@ -135,5 +136,4 @@ final class KanbanBoardTest extends TestCase
->assertSee('Escalation board ticket')
->assertDontSee('Default board ticket');
}
}
@@ -13,9 +13,7 @@ use Modules\Helpdesk\Models\ChecklistItem;
use Modules\Helpdesk\Models\ChecklistTemplate;
use Modules\Helpdesk\Models\Product;
use Modules\Helpdesk\Models\SlaPolicy;
use Modules\Helpdesk\Models\Ticket;
use Modules\Helpdesk\Models\TicketSlaEvent;
use Modules\Helpdesk\Services\AutomationRuleService;
use Modules\Helpdesk\Services\ChecklistService;
use Modules\Helpdesk\Services\SlaService;
use Modules\Helpdesk\Services\TicketService;
+1 -1
View File
@@ -5,8 +5,8 @@ declare(strict_types=1);
use Illuminate\Support\Facades\Route;
use Modules\Helpdesk\Http\Controllers\AttachmentDownloadController;
use Modules\Helpdesk\Http\Controllers\HelpdeskController;
use Modules\Helpdesk\Http\Controllers\TicketStoreController;
use Modules\Helpdesk\Http\Controllers\TicketControlsController;
use Modules\Helpdesk\Http\Controllers\TicketStoreController;
use Modules\Helpdesk\Http\Controllers\WorkflowOpenController;
use Modules\Helpdesk\Livewire\KanbanBoard;
use Modules\Helpdesk\Livewire\SettingsManager;
@@ -1,8 +1,8 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateActivityLogTable extends Migration
{
@@ -1,8 +1,8 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddEventColumnToActivityLogTable extends Migration
{
@@ -1,8 +1,8 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddBatchUuidColumnToActivityLogTable extends Migration
{
+4 -3
View File
@@ -1,5 +1,6 @@
<?php
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Route;
Route::view('/', 'welcome')->name('home');
@@ -14,7 +15,7 @@ require __DIR__.'/settings.php';
Route::get('/api/countries/resolve/{code}', function (string $code) {
$normalised = strtoupper(trim($code));
$country = \Illuminate\Support\Facades\DB::table('countries')
$country = DB::table('countries')
->whereRaw('UPPER(alpha2) = ?', [$normalised])
->orWhereRaw('UPPER(alpha3) = ?', [$normalised])
->orWhere('numeric', $normalised)
@@ -43,7 +44,7 @@ Route::get('/api/countries/resolve/{code}', function (string $code) {
Route::get('/api/countries/{code}/subdivisions', function (string $code) {
$normalised = strtoupper(trim($code));
$country = \Illuminate\Support\Facades\DB::table('countries')
$country = DB::table('countries')
->whereRaw('UPPER(alpha2) = ?', [$normalised])
->orWhereRaw('UPPER(alpha3) = ?', [$normalised])
->orWhere('numeric', $normalised)
@@ -51,7 +52,7 @@ Route::get('/api/countries/{code}/subdivisions', function (string $code) {
abort_if($country === null, 404);
$subdivisions = \Illuminate\Support\Facades\DB::table('country_subdivisions')
$subdivisions = DB::table('country_subdivisions')
->where('country_id', $country->id)
->orderBy('sort_order')
->orderBy('name')
+2 -3
View File
@@ -30,7 +30,7 @@ abstract class DuskTestCase extends BaseTestCase
*/
protected function driver(): RemoteWebDriver
{
$options = (new ChromeOptions())->addArguments([
$options = (new ChromeOptions)->addArguments([
'--disable-gpu',
'--headless=new',
'--window-size=1920,1080',
@@ -80,8 +80,7 @@ abstract class DuskTestCase extends BaseTestCase
));
usort($candidates, static function (string $left, string $right): int {
$score = static fn (string $path): int =>
str_contains($path, 'mac-arm64') ? 0
$score = static fn (string $path): int => str_contains($path, 'mac-arm64') ? 0
: (str_contains($path, 'mac-arm') ? 1
: (str_contains($path, 'mac') ? 2 : 3));