move into sonardesk

This commit is contained in:
Mark Gregory
2026-10-12 14:50:13 +01:00
parent 5f0d2ceb72
commit 38b4a7406f
879 changed files with 24021 additions and 1 deletions
+6
View File
@@ -0,0 +1,6 @@
<?php
return [
'name' => 'Administration',
'enabled' => true,
];
@@ -0,0 +1,82 @@
<?php
namespace Modules\Administration\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Facades\Schema;
use Modules\Audit\Models\AuditLog;
use Modules\Media\Models\Media;
use Spatie\Permission\Models\Role;
final class DashboardController extends Controller
{
public function __invoke()
{
return stylist_backend_view(stylist()->backend()->entryView(), [
'userCount' => User::count(),
'roleCount' => Schema::hasTable('roles') ? Role::count() : 0,
'mediaCount' => Schema::hasTable('media') ? Media::count() : 0,
'auditCount' => Schema::hasTable('audit_logs') ? AuditLog::count() : 0,
'recentAudit' => $this->recentAudit(),
'modules' => $this->modules(),
]);
}
private function recentAudit(): LengthAwarePaginator
{
if (! Schema::hasTable('audit_logs')) {
return new LengthAwarePaginator(
items: [],
total: 0,
perPage: 8,
currentPage: Paginator::resolveCurrentPage('audit_page'),
options: [
'path' => request()->url(),
'pageName' => 'audit_page',
],
);
}
return AuditLog::query()
->latest('created_at')
->paginate(8, ['*'], 'audit_page')
->withQueryString();
}
private function modules(): LengthAwarePaginator
{
$statuses = json_decode((string) file_get_contents(base_path('modules_statuses.json')), true) ?: [];
$modules = [];
foreach (glob(base_path('Modules/*/module.json')) ?: [] as $manifest) {
$data = json_decode((string) file_get_contents($manifest), true) ?: [];
$name = $data['name'] ?? basename(dirname($manifest));
$modules[] = [
'name' => $name,
'version' => $data['version'] ?? '1.0.0',
'enabled' => (bool) ($statuses[$name] ?? false),
];
}
usort($modules, fn (array $a, array $b): int => strcasecmp($a['name'], $b['name']));
$pageName = 'modules_page';
$perPage = 8;
$currentPage = Paginator::resolveCurrentPage($pageName);
return (new LengthAwarePaginator(
items: array_slice($modules, ($currentPage - 1) * $perPage, $perPage),
total: count($modules),
perPage: $perPage,
currentPage: $currentPage,
options: [
'path' => request()->url(),
'pageName' => $pageName,
],
))->withQueryString();
}
}
@@ -0,0 +1,27 @@
<?php
namespace Modules\Administration\Http\Controllers;
use App\Http\Controllers\Controller;
final class ModuleController extends Controller
{
public function index()
{
$statuses = json_decode((string) file_get_contents(base_path('modules_statuses.json')), true) ?: [];
$modules = collect(glob(base_path('Modules/*/module.json')) ?: [])->map(function (string $manifest) use ($statuses): array {
$data = json_decode((string) file_get_contents($manifest), true) ?: [];
$name = $data['name'] ?? basename(dirname($manifest));
return [
'name' => $name,
'description' => $data['description'] ?? 'Laravel application module.',
'version' => $data['version'] ?? '1.0.0',
'enabled' => (bool) ($statuses[$name] ?? false),
'providers' => $data['providers'] ?? [],
];
})->sortBy('name', SORT_NATURAL | SORT_FLAG_CASE)->values();
return view('administration::modules.index', compact('modules'));
}
}
@@ -0,0 +1,21 @@
<?php
namespace Modules\Administration\Providers;
use Illuminate\Support\ServiceProvider;
use Modules\Administration\Support\ModuleInfo;
final class AdministrationServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->register(RouteServiceProvider::class);
$this->mergeConfigFrom(module_path(ModuleInfo::name(), 'Config/config.php'), ModuleInfo::nameLower());
}
public function boot(): void
{
$this->loadMigrationsFrom(module_path(ModuleInfo::name(), 'Database/Migrations'));
$this->loadViewsFrom(module_path(ModuleInfo::name(), 'Resources/views'), ModuleInfo::nameLower());
}
}
@@ -0,0 +1,17 @@
<?php
namespace Modules\Administration\Providers;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;
final class RouteServiceProvider extends ServiceProvider
{
public function boot(): void
{
parent::boot();
$this->routes(function (): void {
Route::middleware('web')->group(module_path('Administration', 'Routes/web.php'));
});
}
}
@@ -0,0 +1 @@
<x-layouts.app :title="__('Modules')"><div class="space-y-6"><div><h1 class="text-2xl font-semibold">Modules</h1><p class="mt-1 text-sm text-zinc-500">Installed platform modules and runtime status.</p></div><div class="overflow-hidden rounded-xl border border-zinc-200 bg-white dark:border-zinc-700 dark:bg-zinc-900"><table class="min-w-full divide-y divide-zinc-200 text-sm dark:divide-zinc-700"><thead class="bg-zinc-50 text-left text-xs uppercase text-zinc-500 dark:bg-zinc-950"><tr><th class="px-4 py-3">Module</th><th class="px-4 py-3">Version</th><th class="px-4 py-3">Status</th><th class="px-4 py-3">Providers</th></tr></thead><tbody class="divide-y divide-zinc-200 dark:divide-zinc-800">@foreach($modules as $module)<tr><td class="px-4 py-3"><div class="font-medium">{{ $module['name'] }}</div><div class="text-xs text-zinc-500">{{ $module['description'] }}</div></td><td class="px-4 py-3">{{ $module['version'] }}</td><td class="px-4 py-3">{{ $module['enabled'] ? 'Enabled' : 'Disabled' }}</td><td class="px-4 py-3 text-xs text-zinc-500">{{ implode(', ', $module['providers']) ?: '—' }}</td></tr>@endforeach</tbody></table></div></div></x-layouts.app>
+8
View File
@@ -0,0 +1,8 @@
<?php
use Illuminate\Support\Facades\Route;
use Modules\Administration\Http\Controllers\ModuleController;
Route::middleware(['auth', 'verified'])->prefix('administration')->name('administration.')->group(function (): void {
Route::get('/modules', [ModuleController::class, 'index'])->name('modules.index');
});
+16
View File
@@ -0,0 +1,16 @@
<?php
namespace Modules\Administration\Support;
final class ModuleInfo
{
public static function name(): string
{
return 'Administration';
}
public static function nameLower(): string
{
return 'administration';
}
}
@@ -0,0 +1,17 @@
<?php
use Illuminate\Support\Facades\Route;
use Modules\Administration\Http\Controllers\DashboardController;
it('boots the Administration module', function (): void {
expect(config('administration.name'))->toBe('Administration');
});
it('uses the primary dashboard for administration overview content', function (): void {
$dashboard = Route::getRoutes()->getByName('dashboard');
expect($dashboard)->not->toBeNull()
->and($dashboard->getActionName())->toBe(DashboardController::class)
->and(view()->exists('stylist-theme-admin::dashboard'))->toBeTrue()
->and(Route::has('administration.dashboard'))->toBeFalse();
});
+10
View File
@@ -0,0 +1,10 @@
{
"name": "absdev/administration-module",
"description": "Administration foundation module for the ABSDEV Laravel application platform.",
"type": "laravel-module",
"autoload": {
"psr-4": {
"Modules\\Administration\\": ""
}
}
}
+20
View File
@@ -0,0 +1,20 @@
{
"name": "Administration",
"alias": "administration",
"version": "1.0.0",
"description": "Administration foundation module for the ABSDEV Laravel application platform.",
"keywords": [
"laravel",
"modules",
"administration"
],
"priority": 10,
"providers": [
"Modules\\Administration\\Providers\\AdministrationServiceProvider"
],
"aliases": {},
"files": [],
"requires": [
"Core"
]
}