cleanup migration to filament

This commit is contained in:
Saeed Vaziry 2024-10-06 21:46:03 +02:00
parent 06d690138d
commit a94d1d42d2
420 changed files with 39 additions and 15481 deletions
app
public
resources/views

@ -1,138 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\Site\Deploy;
use App\Actions\Site\UpdateBranch;
use App\Actions\Site\UpdateDeploymentScript;
use App\Actions\Site\UpdateEnv;
use App\Exceptions\DeploymentScriptIsEmptyException;
use App\Exceptions\RepositoryNotFound;
use App\Exceptions\RepositoryPermissionDenied;
use App\Exceptions\SourceControlIsNotConnected;
use App\Exceptions\SSHUploadFailed;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Deployment;
use App\Models\Server;
use App\Models\Site;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class ApplicationController extends Controller
{
public function deploy(Server $server, Site $site): HtmxResponse
{
$this->authorize('manage', $server);
try {
app(Deploy::class)->run($site);
Toast::success('Deployment started!');
} catch (SourceControlIsNotConnected) {
Toast::error('Source control is not connected. Check site\'s settings.');
} catch (DeploymentScriptIsEmptyException) {
Toast::error('Deployment script is empty!');
} catch (RepositoryPermissionDenied) {
Toast::error('You do not have permission to access this repository!');
} catch (RepositoryNotFound) {
Toast::error('Repository not found!');
}
return htmx()->back();
}
public function showDeploymentLog(Server $server, Site $site, Deployment $deployment): RedirectResponse
{
$this->authorize('manage', $server);
return back()->with('content', $deployment->log?->getContent());
}
public function updateDeploymentScript(Server $server, Site $site, Request $request): RedirectResponse
{
$this->authorize('manage', $server);
app(UpdateDeploymentScript::class)->update($site, $request->input());
Toast::success('Deployment script updated!');
return back();
}
public function updateBranch(Server $server, Site $site, Request $request): RedirectResponse
{
$this->authorize('manage', $server);
app(UpdateBranch::class)->update($site, $request->input());
Toast::success('Branch updated!');
return back();
}
public function getEnv(Server $server, Site $site): RedirectResponse
{
$this->authorize('manage', $server);
return back()->with('env', $site->getEnv());
}
public function updateEnv(Server $server, Site $site, Request $request): RedirectResponse
{
$this->authorize('manage', $server);
try {
app(UpdateEnv::class)->update($site, $request->input());
Toast::success('Env updated!');
} catch (SSHUploadFailed) {
Toast::error('Failed to update .env file!');
}
return back();
}
public function enableAutoDeployment(Server $server, Site $site): HtmxResponse
{
$this->authorize('manage', $server);
if (! $site->isAutoDeployment()) {
try {
$site->enableAutoDeployment();
$site->refresh();
Toast::success('Auto deployment has been enabled.');
} catch (SourceControlIsNotConnected) {
Toast::error('Source control is not connected. Check site\'s settings.');
} catch (DeploymentScriptIsEmptyException) {
Toast::error('Deployment script is empty!');
} catch (RepositoryPermissionDenied) {
Toast::error('You do not have permission to access this repository!');
} catch (RepositoryNotFound) {
Toast::error('Repository not found!');
}
}
return htmx()->back();
}
public function disableAutoDeployment(Server $server, Site $site): HtmxResponse
{
$this->authorize('manage', $server);
if ($site->isAutoDeployment()) {
try {
$site->disableAutoDeployment();
$site->refresh();
Toast::success('Auto deployment has been disabled.');
} catch (SourceControlIsNotConnected) {
Toast::error('Source control is not connected. Check site\'s settings.');
}
}
return htmx()->back();
}
}

@ -1,72 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\CronJob\CreateCronJob;
use App\Actions\CronJob\DeleteCronJob;
use App\Actions\CronJob\DisableCronJob;
use App\Actions\CronJob\EnableCronJob;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\CronJob;
use App\Models\Server;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class CronjobController extends Controller
{
public function index(Server $server): View
{
$this->authorize('manage', $server);
return view('cronjobs.index', [
'server' => $server,
'cronjobs' => $server->cronJobs,
]);
}
public function store(Server $server, Request $request): HtmxResponse
{
$this->authorize('manage', $server);
app(CreateCronJob::class)->create($server, $request->input());
Toast::success('Cronjob created successfully.');
return htmx()->back();
}
public function destroy(Server $server, CronJob $cronJob): RedirectResponse
{
$this->authorize('manage', $server);
app(DeleteCronJob::class)->delete($server, $cronJob);
Toast::success('Cronjob deleted successfully.');
return back();
}
public function enable(Server $server, CronJob $cronJob): RedirectResponse
{
$this->authorize('manage', $server);
app(EnableCronJob::class)->enable($server, $cronJob);
Toast::success('Cronjob enabled successfully.');
return back();
}
public function disable(Server $server, CronJob $cronJob): RedirectResponse
{
$this->authorize('manage', $server);
app(DisableCronJob::class)->disable($server, $cronJob);
Toast::success('Cronjob disabled successfully.');
return back();
}
}

@ -1,92 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\Database\CreateBackup;
use App\Actions\Database\RestoreBackup;
use App\Actions\Database\RunBackup;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Backup;
use App\Models\BackupFile;
use App\Models\Server;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class DatabaseBackupController extends Controller
{
public function show(Server $server, Backup $backup): View
{
$this->authorize('manage', $server);
return view('databases.backups', [
'server' => $server,
'databases' => $server->databases,
'backup' => $backup,
'files' => $backup->files()->orderByDesc('id')->simplePaginate(10),
]);
}
public function run(Server $server, Backup $backup): RedirectResponse
{
$this->authorize('manage', $server);
app(RunBackup::class)->run($backup);
Toast::success('Backup is running.');
return back();
}
public function store(Server $server, Request $request): HtmxResponse
{
$this->authorize('manage', $server);
app(CreateBackup::class)->create('database', $server, $request->input());
Toast::success('Backup created successfully.');
return htmx()->back();
}
public function destroy(Server $server, Backup $backup): RedirectResponse
{
$this->authorize('manage', $server);
$backup->delete();
Toast::success('Backup deleted successfully.');
return back();
}
public function restore(Server $server, Backup $backup, BackupFile $backupFile, Request $request): HtmxResponse
{
$this->authorize('manage', $server);
app(RestoreBackup::class)->restore($backupFile, $request->input());
Toast::success('Backup restored successfully.');
return htmx()->back();
}
public function destroyFile(Server $server, Backup $backup, BackupFile $backupFile): RedirectResponse
{
$this->authorize('manage', $server);
$backupFile->delete();
$backupFile
->backup
->storage
->provider()
->ssh($server)
->delete($backupFile->storagePath());
Toast::success('Backup file deleted successfully.');
return back();
}
}

@ -1,55 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\Database\CreateDatabase;
use App\Actions\Database\CreateDatabaseUser;
use App\Actions\Database\DeleteDatabase;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Database;
use App\Models\Server;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class DatabaseController extends Controller
{
public function index(Server $server): View
{
$this->authorize('manage', $server);
return view('databases.index', [
'server' => $server,
'databases' => $server->databases,
'databaseUsers' => $server->databaseUsers,
'backups' => $server->backups,
]);
}
public function store(Server $server, Request $request): HtmxResponse
{
$this->authorize('manage', $server);
$database = app(CreateDatabase::class)->create($server, $request->input());
if ($request->input('user')) {
app(CreateDatabaseUser::class)->create($server, $request->input(), [$database->name]);
}
Toast::success('Database created successfully.');
return htmx()->back();
}
public function destroy(Server $server, Database $database): RedirectResponse
{
$this->authorize('manage', $server);
app(DeleteDatabase::class)->delete($server, $database);
Toast::success('Database deleted successfully.');
return back();
}
}

@ -1,62 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\Database\CreateDatabaseUser;
use App\Actions\Database\DeleteDatabaseUser;
use App\Actions\Database\LinkUser;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\DatabaseUser;
use App\Models\Server;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class DatabaseUserController extends Controller
{
public function store(Server $server, Request $request): HtmxResponse
{
$this->authorize('manage', $server);
$database = app(CreateDatabaseUser::class)->create($server, $request->input());
if ($request->input('user')) {
app(CreateDatabaseUser::class)->create($server, $request->input(), [$database->name]);
}
Toast::success('User created successfully.');
return htmx()->back();
}
public function destroy(Server $server, DatabaseUser $databaseUser): RedirectResponse
{
$this->authorize('manage', $server);
app(DeleteDatabaseUser::class)->delete($server, $databaseUser);
Toast::success('User deleted successfully.');
return back();
}
public function password(Server $server, DatabaseUser $databaseUser): RedirectResponse
{
$this->authorize('manage', $server);
return back()->with([
'password' => $databaseUser->password,
]);
}
public function link(Server $server, DatabaseUser $databaseUser, Request $request): HtmxResponse
{
$this->authorize('manage', $server);
app(LinkUser::class)->link($databaseUser, $request->input());
Toast::success('Database linked successfully.');
return htmx()->back();
}
}

@ -1,48 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\FirewallRule\CreateRule;
use App\Actions\FirewallRule\DeleteRule;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\FirewallRule;
use App\Models\Server;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class FirewallController extends Controller
{
public function index(Server $server): View
{
$this->authorize('manage', $server);
return view('firewall.index', [
'server' => $server,
'rules' => $server->firewallRules,
]);
}
public function store(Server $server, Request $request): HtmxResponse
{
$this->authorize('manage', $server);
app(CreateRule::class)->create($server, $request->input());
Toast::success('Firewall rule created!');
return htmx()->back();
}
public function destroy(Server $server, FirewallRule $firewallRule): RedirectResponse
{
$this->authorize('manage', $server);
app(DeleteRule::class)->delete($server, $firewallRule);
Toast::success('Firewall rule deleted!');
return back();
}
}

@ -1,50 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\Monitoring\GetMetrics;
use App\Actions\Monitoring\UpdateMetricSettings;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Server;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class MetricController extends Controller
{
public function index(Server $server, Request $request): View|RedirectResponse
{
$this->authorize('manage', $server);
$this->checkIfMonitoringServiceInstalled($server);
return view('metrics.index', [
'server' => $server,
'data' => app(GetMetrics::class)->filter($server, $request->input()),
'lastMetric' => $server->metrics()->latest()->first(),
]);
}
public function settings(Server $server, Request $request): HtmxResponse
{
$this->authorize('manage', $server);
$this->checkIfMonitoringServiceInstalled($server);
app(UpdateMetricSettings::class)->update($server, $request->input());
Toast::success('Metric settings updated successfully');
return htmx()->back();
}
private function checkIfMonitoringServiceInstalled(Server $server): void
{
$this->authorize('manage', $server);
if (! $server->monitoring()) {
abort(404, 'Monitoring service is not installed on this server');
}
}
}

@ -1,101 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\PHP\ChangeDefaultCli;
use App\Actions\PHP\GetPHPIni;
use App\Actions\PHP\InstallNewPHP;
use App\Actions\PHP\InstallPHPExtension;
use App\Actions\PHP\UninstallPHP;
use App\Actions\PHP\UpdatePHPIni;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Server;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
class PHPController extends Controller
{
public function index(Server $server): View
{
$this->authorize('manage', $server);
return view('php.index', [
'server' => $server,
'phps' => $server->services()->where('type', 'php')->get(),
'defaultPHP' => $server->defaultService('php'),
]);
}
public function install(Server $server, Request $request): HtmxResponse
{
$this->authorize('manage', $server);
try {
app(InstallNewPHP::class)->install($server, $request->input());
Toast::success('PHP is being installed!');
} catch (ValidationException $e) {
Toast::error($e->getMessage());
}
return htmx()->back();
}
public function installExtension(Server $server, Request $request): HtmxResponse
{
$this->authorize('manage', $server);
app(InstallPHPExtension::class)->install($server, $request->input());
Toast::success('PHP extension is being installed! Check the logs');
return htmx()->back();
}
public function defaultCli(Server $server, Request $request): HtmxResponse
{
$this->authorize('manage', $server);
app(ChangeDefaultCli::class)->change($server, $request->input());
Toast::success('Default PHP CLI is being changed!');
return htmx()->back();
}
public function getIni(Server $server, Request $request): RedirectResponse
{
$this->authorize('manage', $server);
$ini = app(GetPHPIni::class)->getIni($server, $request->input());
return back()->with('ini', $ini);
}
public function updateIni(Server $server, Request $request): RedirectResponse
{
$this->authorize('manage', $server);
app(UpdatePHPIni::class)->update($server, $request->input());
Toast::success(__('PHP ini (:type) updated!', ['type' => $request->input('type')]));
return back()->with([
'ini' => $request->input('ini'),
]);
}
public function uninstall(Server $server, Request $request): RedirectResponse
{
$this->authorize('manage', $server);
app(UninstallPHP::class)->uninstall($server, $request->input());
Toast::success('PHP is being uninstalled!');
return back();
}
}

@ -1,42 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\User\UpdateUserPassword;
use App\Actions\User\UpdateUserProfileInformation;
use App\Facades\Toast;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class ProfileController extends Controller
{
public function index(): View
{
return view('profile.index');
}
public function info(Request $request): RedirectResponse
{
app(UpdateUserProfileInformation::class)->update(
$request->user(),
$request->input()
);
Toast::success('Profile information updated.');
return back();
}
public function password(Request $request): RedirectResponse
{
app(UpdateUserPassword::class)->update(
$request->user(),
$request->input()
);
Toast::success('Password updated.');
return back();
}
}

@ -1,70 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\Queue\CreateQueue;
use App\Actions\Queue\DeleteQueue;
use App\Actions\Queue\GetQueueLogs;
use App\Actions\Queue\ManageQueue;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Queue;
use App\Models\Server;
use App\Models\Site;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class QueueController extends Controller
{
public function index(Server $server, Site $site): View
{
$this->authorize('manage', $server);
return view('queues.index', [
'server' => $server,
'site' => $site,
'queues' => $site->queues,
]);
}
public function store(Server $server, Site $site, Request $request): HtmxResponse
{
$this->authorize('manage', $server);
app(CreateQueue::class)->create($site, $request->input());
Toast::success('Queue is being created.');
return htmx()->back();
}
public function action(Server $server, Site $site, Queue $queue, string $action): HtmxResponse
{
$this->authorize('manage', $server);
app(ManageQueue::class)->{$action}($queue);
Toast::success('Queue is about to '.$action);
return htmx()->back();
}
public function destroy(Server $server, Site $site, Queue $queue): RedirectResponse
{
$this->authorize('manage', $server);
app(DeleteQueue::class)->delete($queue);
Toast::success('Queue is being deleted.');
return back();
}
public function logs(Server $server, Site $site, Queue $queue): RedirectResponse
{
$this->authorize('manage', $server);
return back()->with('content', app(GetQueueLogs::class)->getLogs($queue));
}
}

@ -1,68 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\SshKey\CreateSshKey;
use App\Actions\SshKey\DeleteKeyFromServer;
use App\Actions\SshKey\DeployKeyToServer;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Server;
use App\Models\SshKey;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class SSHKeyController extends Controller
{
public function index(Server $server): View
{
$this->authorize('manage', $server);
return view('server-ssh-keys.index', [
'server' => $server,
'keys' => $server->sshKeys,
]);
}
public function store(Server $server, Request $request): HtmxResponse
{
$this->authorize('manage', $server);
/** @var SshKey $key */
$key = app(CreateSshKey::class)->create(
$request->user(),
$request->input()
);
$request->merge(['key_id' => $key->id]);
return $this->deploy($server, $request);
}
public function destroy(Server $server, SshKey $sshKey): RedirectResponse
{
$this->authorize('manage', $server);
app(DeleteKeyFromServer::class)->delete($server, $sshKey);
Toast::success('SSH Key has been deleted.');
return back();
}
public function deploy(Server $server, Request $request): HtmxResponse
{
$this->authorize('manage', $server);
app(DeployKeyToServer::class)->deploy(
$request->user(),
$server,
$request->input()
);
Toast::success('SSH Key has been deployed to the server.');
return htmx()->back();
}
}

@ -1,50 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\SSL\CreateSSL;
use App\Actions\SSL\DeleteSSL;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Server;
use App\Models\Site;
use App\Models\Ssl;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class SSLController extends Controller
{
public function index(Server $server, Site $site): View
{
$this->authorize('manage', $server);
return view('ssls.index', [
'server' => $server,
'site' => $site,
'ssls' => $site->ssls,
]);
}
public function store(Server $server, Site $site, Request $request): HtmxResponse
{
$this->authorize('manage', $server);
app(CreateSSL::class)->create($site, $request->input());
Toast::success('SSL certificate is being created.');
return htmx()->back();
}
public function destroy(Server $server, Site $site, Ssl $ssl): RedirectResponse
{
$this->authorize('manage', $server);
app(DeleteSSL::class)->delete($ssl);
Toast::success('SSL certificate has been deleted.');
return back();
}
}

@ -1,111 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\Script\CreateScript;
use App\Actions\Script\EditScript;
use App\Actions\Script\ExecuteScript;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Script;
use App\Models\ScriptExecution;
use App\Models\Server;
use App\Models\User;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class ScriptController extends Controller
{
public function index(Request $request): View
{
$this->authorize('viewAny', Script::class);
/** @var User $user */
$user = auth()->user();
$data = [
'scripts' => $user->scripts,
];
if ($request->has('edit')) {
$data['editScript'] = $user->scripts()->findOrFail($request->input('edit'));
}
if ($request->has('execute')) {
$data['executeScript'] = $user->scripts()->findOrFail($request->input('execute'));
}
return view('scripts.index', $data);
}
public function show(Script $script): View
{
$this->authorize('view', $script);
return view('scripts.show', [
'script' => $script,
'executions' => $script->executions()->latest()->paginate(20),
]);
}
public function store(Request $request): HtmxResponse
{
$this->authorize('create', Script::class);
/** @var User $user */
$user = auth()->user();
app(CreateScript::class)->create($user, $request->input());
Toast::success('Script created.');
return htmx()->redirect(route('scripts.index'));
}
public function edit(Request $request, Script $script): HtmxResponse
{
$this->authorize('update', $script);
app(EditScript::class)->edit($script, $request->input());
Toast::success('Script updated.');
return htmx()->redirect(route('scripts.index'));
}
public function execute(Script $script, Request $request): HtmxResponse
{
$this->validate($request, [
'server' => 'required|exists:servers,id',
]);
$server = Server::findOrFail($request->input('server'));
$this->authorize('execute', [$script, $server]);
app(ExecuteScript::class)->execute($script, $server, $request->input());
Toast::success('Executing the script...');
return htmx()->redirect(route('scripts.show', $script));
}
public function delete(Script $script): RedirectResponse
{
$this->authorize('delete', $script);
$script->delete();
Toast::success('Script deleted.');
return redirect()->route('scripts.index');
}
public function log(Script $script, ScriptExecution $execution): RedirectResponse
{
$this->authorize('view', $script);
return back()->with('content', $execution->serverLog?->getContent());
}
}

@ -1,71 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Models\Server;
use App\Models\Site;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class SearchController extends Controller
{
/**
* @throws ValidationException
*/
public function search(Request $request): JsonResponse
{
$this->validate($request, [
'q' => 'required',
]);
$servers = Server::query()
->where(function ($query) use ($request) {
$query->where('name', 'like', '%'.$request->input('q').'%')
->orWhere('ip', 'like', '%'.$request->input('q').'%');
})
->whereHas('project', function (Builder $projectQuery) {
$projectQuery->whereHas('users', function (Builder $userQuery) {
$userQuery->where('user_id', auth()->user()->id);
});
})
->get();
$sites = Site::query()
->where('domain', 'like', '%'.$request->input('q').'%')
->whereHas('server', function (Builder $serverQuery) {
$serverQuery->whereHas('project', function (Builder $projectQuery) {
$projectQuery->whereHas('users', function (Builder $userQuery) {
$userQuery->where('user_id', auth()->user()->id);
});
});
})
->get();
$result = [];
/** @var Server $server */
foreach ($servers as $server) {
$result[] = [
'type' => 'server',
'url' => route('servers.show', ['server' => $server]),
'text' => $server->name,
'project' => $server->project->name,
];
}
/** @var Site $site */
foreach ($sites as $site) {
$result[] = [
'type' => 'site',
'url' => route('servers.sites.show', ['server' => $site->server, 'site' => $site]),
'text' => $site->domain,
'project' => $site->server->project->name,
];
}
return response()->json([
'results' => $result,
]);
}
}

@ -1,87 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\Server\CreateServer;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Server;
use App\Models\ServerProvider;
use App\Models\User;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Throwable;
class ServerController extends Controller
{
public function index(): View
{
/** @var User $user */
$user = auth()->user();
$this->authorize('viewAny', [Server::class, $user->currentProject]);
$servers = $user->currentProject->servers()->orderByDesc('created_at')->get();
return view('servers.index', compact('servers'));
}
public function create(Request $request): View
{
/** @var User $user */
$user = auth()->user();
$this->authorize('create', [Server::class, $user->currentProject]);
$provider = $request->query('provider', old('provider', \App\Enums\ServerProvider::CUSTOM));
$serverProviders = ServerProvider::getByProjectId(auth()->user()->current_project_id)
->where('provider', $provider)
->get();
return view('servers.create', [
'serverProviders' => $serverProviders,
'provider' => $provider,
]);
}
/**
* @throws Throwable
*/
public function store(Request $request): HtmxResponse
{
/** @var User $user */
$user = auth()->user();
$this->authorize('create', [Server::class, $user->currentProject]);
$server = app(CreateServer::class)->create(
$user,
$request->input()
);
Toast::success('Server created successfully.');
return htmx()->redirect(route('servers.show', ['server' => $server]));
}
public function show(Server $server): View
{
$this->authorize('view', $server);
return view('servers.show', [
'server' => $server,
]);
}
public function delete(Server $server): RedirectResponse
{
$this->authorize('delete', $server);
$server->delete();
Toast::success('Server deleted successfully.');
return redirect()->route('servers');
}
}

@ -1,70 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\Server\CreateServerLog;
use App\Facades\Toast;
use App\Models\Server;
use App\Models\ServerLog;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class ServerLogController extends Controller
{
public function index(Server $server): View
{
$this->authorize('manage', $server);
return view('server-logs.index', [
'server' => $server,
'pageTitle' => __('Vito Logs'),
]);
}
public function show(Server $server, ServerLog $serverLog): RedirectResponse
{
$this->authorize('manage', $server);
if ($server->id != $serverLog->server_id) {
abort(404);
}
return back()->with([
'content' => $serverLog->getContent(),
]);
}
public function remote(Server $server): View
{
$this->authorize('manage', $server);
return view('server-logs.remote-logs', [
'server' => $server,
'remote' => true,
'pageTitle' => __('Remote Logs'),
]);
}
public function store(Server $server, Request $request): \App\Helpers\HtmxResponse
{
$this->authorize('manage', $server);
app(CreateServerLog::class)->create($server, $request->input());
Toast::success('Log added successfully.');
return htmx()->redirect(route('servers.logs.remote', ['server' => $server]));
}
public function destroy(Server $server, ServerLog $serverLog): RedirectResponse
{
$this->authorize('manage', $server);
$serverLog->delete();
Toast::success('Remote log deleted successfully.');
return redirect()->route('servers.logs.remote', ['server' => $server]);
}
}

@ -1,88 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\Server\EditServer;
use App\Actions\Server\RebootServer;
use App\Actions\Server\Update;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Server;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class ServerSettingController extends Controller
{
public function index(Server $server): View
{
$this->authorize('manage', $server);
return view('server-settings.index', compact('server'));
}
public function checkConnection(Server $server): RedirectResponse|HtmxResponse
{
$this->authorize('manage', $server);
$oldStatus = $server->status;
$server = $server->checkConnection();
if ($server->status == 'disconnected') {
Toast::error('Server is disconnected.');
}
if ($server->status == 'ready') {
Toast::success('Server is ready.');
}
if ($oldStatus != $server->status) {
return htmx()->redirect(back()->getTargetUrl());
}
return back();
}
public function reboot(Server $server): HtmxResponse
{
$this->authorize('manage', $server);
app(RebootServer::class)->reboot($server);
Toast::info('Server is rebooting.');
return htmx()->redirect(back()->getTargetUrl());
}
public function edit(Request $request, Server $server): RedirectResponse
{
$this->authorize('manage', $server);
app(EditServer::class)->edit($server, $request->input());
Toast::success('Server updated.');
return back();
}
public function checkUpdates(Server $server): RedirectResponse
{
$this->authorize('manage', $server);
$server->checkForUpdates();
return back();
}
public function update(Server $server): HtmxResponse
{
$this->authorize('manage', $server);
app(Update::class)->update($server);
Toast::info('Updating server. This may take a few minutes.');
return htmx()->back();
}
}

@ -1,103 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\Service\Install;
use App\Actions\Service\Uninstall;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Server;
use App\Models\Service;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class ServiceController extends Controller
{
public function index(Server $server): View
{
$this->authorize('manage', $server);
return view('services.index', [
'server' => $server,
'services' => $server->services,
]);
}
public function start(Server $server, Service $service): RedirectResponse
{
$this->authorize('manage', $server);
$service->start();
Toast::success('Service is being started!');
return back();
}
public function stop(Server $server, Service $service): RedirectResponse
{
$this->authorize('manage', $server);
$service->stop();
Toast::success('Service is being stopped!');
return back();
}
public function restart(Server $server, Service $service): RedirectResponse
{
$this->authorize('manage', $server);
$service->restart();
Toast::success('Service is being restarted!');
return back();
}
public function enable(Server $server, Service $service): RedirectResponse
{
$this->authorize('manage', $server);
$service->enable();
Toast::success('Service is being enabled!');
return back();
}
public function disable(Server $server, Service $service): RedirectResponse
{
$this->authorize('manage', $server);
$service->disable();
Toast::success('Service is being disabled!');
return back();
}
public function install(Server $server, Request $request): HtmxResponse
{
$this->authorize('manage', $server);
app(Install::class)->install($server, $request->input());
Toast::success('Service is being installed!');
return htmx()->back();
}
public function uninstall(Server $server, Service $service): HtmxResponse
{
$this->authorize('manage', $server);
app(Uninstall::class)->uninstall($service);
Toast::success('Service is being uninstalled!');
return htmx()->back();
}
}

@ -1,65 +0,0 @@
<?php
namespace App\Http\Controllers\Settings;
use App\Actions\NotificationChannels\AddChannel;
use App\Actions\NotificationChannels\EditChannel;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Http\Controllers\Controller;
use App\Models\NotificationChannel;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class NotificationChannelController extends Controller
{
public function index(Request $request): View
{
$data = [
'channels' => NotificationChannel::getByProjectId(auth()->user()->current_project_id)->get(),
];
if ($request->has('edit')) {
$data['editChannel'] = NotificationChannel::find($request->input('edit'));
}
return view('settings.notification-channels.index', $data);
}
public function add(Request $request): HtmxResponse
{
app(AddChannel::class)->add(
$request->user(),
$request->input()
);
Toast::success('Channel added successfully');
return htmx()->redirect(route('settings.notification-channels'));
}
public function update(NotificationChannel $notificationChannel, Request $request): HtmxResponse
{
app(EditChannel::class)->edit(
$notificationChannel,
$request->user(),
$request->input(),
);
Toast::success('Channel updated.');
return htmx()->redirect(route('settings.notification-channels'));
}
public function delete(int $id): RedirectResponse
{
$channel = NotificationChannel::query()->findOrFail($id);
$channel->delete();
Toast::success('Channel deleted successfully');
return redirect()->route('settings.notification-channels');
}
}

@ -1,91 +0,0 @@
<?php
namespace App\Http\Controllers\Settings;
use App\Actions\Projects\CreateProject;
use App\Actions\Projects\DeleteProject;
use App\Actions\Projects\UpdateProject;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Http\Controllers\Controller;
use App\Models\Project;
use App\Models\User;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
class ProjectController extends Controller
{
public function index(): View
{
$this->authorize('viewAny', Project::class);
return view('settings.projects.index', [
'projects' => Project::all(),
]);
}
public function create(Request $request): HtmxResponse
{
$this->authorize('create', Project::class);
app(CreateProject::class)->create($request->user(), $request->input());
Toast::success('Project created.');
return htmx()->redirect(route('settings.projects'));
}
public function update(Request $request, Project $project): HtmxResponse
{
$this->authorize('update', $project);
app(UpdateProject::class)->update($project, $request->input());
Toast::success('Project updated.');
return htmx()->redirect(route('settings.projects'));
}
public function delete(Project $project): RedirectResponse
{
$this->authorize('delete', $project);
/** @var User $user */
$user = auth()->user();
try {
app(DeleteProject::class)->delete($user, $project);
} catch (ValidationException $e) {
Toast::error($e->getMessage());
return back();
}
Toast::success('Project deleted.');
return back();
}
public function switch(Request $request, $projectId): RedirectResponse
{
/** @var User $user */
$user = auth()->user();
/** @var Project $project */
$project = $user->projects()->findOrFail($projectId);
$this->authorize('view', $project);
$user->current_project_id = $project->id;
$user->save();
// check if the referer is settings/*
if (str_contains($request->headers->get('referer'), 'settings')) {
return redirect()->to($request->headers->get('referer'));
}
return redirect()->route('servers');
}
}

@ -1,45 +0,0 @@
<?php
namespace App\Http\Controllers\Settings;
use App\Actions\SshKey\CreateSshKey;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Http\Controllers\Controller;
use App\Models\SshKey;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class SSHKeyController extends Controller
{
public function index(): View
{
return view('settings.ssh-keys.index', [
'keys' => SshKey::query()->latest()->get(),
]);
}
public function add(Request $request): HtmxResponse
{
app(CreateSshKey::class)->create(
$request->user(),
$request->input()
);
Toast::success('SSH Key added');
return htmx()->redirect(route('settings.ssh-keys'));
}
public function delete(int $id): RedirectResponse
{
$key = SshKey::query()->findOrFail($id);
$key->delete();
Toast::success('SSH Key deleted');
return redirect()->route('settings.ssh-keys');
}
}

@ -1,70 +0,0 @@
<?php
namespace App\Http\Controllers\Settings;
use App\Actions\ServerProvider\CreateServerProvider;
use App\Actions\ServerProvider\DeleteServerProvider;
use App\Actions\ServerProvider\EditServerProvider;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Http\Controllers\Controller;
use App\Models\ServerProvider;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class ServerProviderController extends Controller
{
public function index(Request $request): View
{
$data = [
'providers' => ServerProvider::getByProjectId(auth()->user()->current_project_id)->get(),
];
if ($request->has('edit')) {
$data['editProvider'] = ServerProvider::find($request->input('edit'));
}
return view('settings.server-providers.index', $data);
}
public function connect(Request $request): HtmxResponse
{
app(CreateServerProvider::class)->create(
$request->user(),
$request->input()
);
Toast::success('Server provider connected.');
return htmx()->redirect(route('settings.server-providers'));
}
public function update(ServerProvider $serverProvider, Request $request): HtmxResponse
{
app(EditServerProvider::class)->edit(
$serverProvider,
$request->user(),
$request->input(),
);
Toast::success('Provider updated.');
return htmx()->redirect(route('settings.server-providers'));
}
public function delete(ServerProvider $serverProvider): RedirectResponse
{
try {
app(DeleteServerProvider::class)->delete($serverProvider);
} catch (\Exception $e) {
Toast::error($e->getMessage());
return back();
}
Toast::success('Server provider deleted.');
return back();
}
}

@ -1,70 +0,0 @@
<?php
namespace App\Http\Controllers\Settings;
use App\Actions\SourceControl\ConnectSourceControl;
use App\Actions\SourceControl\DeleteSourceControl;
use App\Actions\SourceControl\EditSourceControl;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Http\Controllers\Controller;
use App\Models\SourceControl;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class SourceControlController extends Controller
{
public function index(Request $request): View
{
$data = [
'sourceControls' => SourceControl::getByProjectId(auth()->user()->current_project_id)->get(),
];
if ($request->has('edit')) {
$data['editSourceControl'] = SourceControl::find($request->input('edit'));
}
return view('settings.source-controls.index', $data);
}
public function connect(Request $request): HtmxResponse
{
app(ConnectSourceControl::class)->connect(
$request->user(),
$request->input(),
);
Toast::success('Source control connected.');
return htmx()->redirect(route('settings.source-controls'));
}
public function update(SourceControl $sourceControl, Request $request): HtmxResponse
{
app(EditSourceControl::class)->edit(
$sourceControl,
$request->user(),
$request->input(),
);
Toast::success('Source control updated.');
return htmx()->redirect(route('settings.source-controls'));
}
public function delete(SourceControl $sourceControl): RedirectResponse
{
try {
app(DeleteSourceControl::class)->delete($sourceControl);
} catch (\Exception $e) {
Toast::error($e->getMessage());
return back();
}
Toast::success('Source control deleted.');
return redirect()->route('settings.source-controls');
}
}

@ -1,70 +0,0 @@
<?php
namespace App\Http\Controllers\Settings;
use App\Actions\StorageProvider\CreateStorageProvider;
use App\Actions\StorageProvider\DeleteStorageProvider;
use App\Actions\StorageProvider\EditStorageProvider;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Http\Controllers\Controller;
use App\Models\StorageProvider;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class StorageProviderController extends Controller
{
public function index(Request $request): View
{
$data = [
'providers' => StorageProvider::getByProjectId(auth()->user()->current_project_id)->get(),
];
if ($request->has('edit')) {
$data['editProvider'] = StorageProvider::find($request->input('edit'));
}
return view('settings.storage-providers.index', $data);
}
public function connect(Request $request): HtmxResponse
{
app(CreateStorageProvider::class)->create(
$request->user(),
$request->input()
);
Toast::success('Storage provider connected.');
return htmx()->redirect(route('settings.storage-providers'));
}
public function update(StorageProvider $storageProvider, Request $request): HtmxResponse
{
app(EditStorageProvider::class)->edit(
$storageProvider,
$request->user(),
$request->input(),
);
Toast::success('Provider updated.');
return htmx()->redirect(route('settings.storage-providers'));
}
public function delete(StorageProvider $storageProvider): RedirectResponse
{
try {
app(DeleteStorageProvider::class)->delete($storageProvider);
} catch (\Exception $e) {
Toast::error($e->getMessage());
return back();
}
Toast::success('Storage provider deleted.');
return back();
}
}

@ -1,90 +0,0 @@
<?php
namespace App\Http\Controllers\Settings;
use App\Actions\Tag\AttachTag;
use App\Actions\Tag\CreateTag;
use App\Actions\Tag\DeleteTag;
use App\Actions\Tag\DetachTag;
use App\Actions\Tag\EditTag;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Http\Controllers\Controller;
use App\Models\Tag;
use App\Models\User;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class TagController extends Controller
{
public function index(Request $request): View
{
$data = [
'tags' => Tag::getByProjectId(auth()->user()->current_project_id)->get(),
];
if ($request->has('edit')) {
$data['editTag'] = Tag::find($request->input('edit'));
}
return view('settings.tags.index', $data);
}
public function create(Request $request): HtmxResponse
{
/** @var User $user */
$user = $request->user();
app(CreateTag::class)->create(
$user,
$request->input(),
);
Toast::success('Tag created.');
return htmx()->redirect(route('settings.tags'));
}
public function update(Tag $tag, Request $request): HtmxResponse
{
app(EditTag::class)->edit(
$tag,
$request->input(),
);
Toast::success('Tag updated.');
return htmx()->redirect(route('settings.tags'));
}
public function attach(Request $request): RedirectResponse
{
/** @var User $user */
$user = $request->user();
app(AttachTag::class)->attach($user, $request->input());
return back()->with([
'status' => 'tag-created',
]);
}
public function detach(Request $request, Tag $tag): RedirectResponse
{
app(DetachTag::class)->detach($tag, $request->input());
return back()->with([
'status' => 'tag-detached',
]);
}
public function delete(Tag $tag): RedirectResponse
{
app(DeleteTag::class)->delete($tag);
Toast::success('Tag deleted.');
return back();
}
}

@ -1,71 +0,0 @@
<?php
namespace App\Http\Controllers\Settings;
use App\Actions\User\CreateUser;
use App\Actions\User\UpdateProjects;
use App\Actions\User\UpdateUser;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class UserController extends Controller
{
public function index(): View
{
$users = User::query()->paginate(20);
return view('settings.users.index', compact('users'));
}
public function store(Request $request): HtmxResponse
{
$user = app(CreateUser::class)->create($request->input());
return htmx()->redirect(route('settings.users.show', $user));
}
public function show(User $user): View
{
return view('settings.users.show', [
'user' => $user,
]);
}
public function update(User $user, Request $request): RedirectResponse
{
app(UpdateUser::class)->update($user, $request->input());
Toast::success('User updated successfully');
return back();
}
public function updateProjects(User $user, Request $request): HtmxResponse
{
app(UpdateProjects::class)->update($user, $request->input());
Toast::success('Projects updated successfully');
return htmx()->redirect(route('settings.users.show', $user));
}
public function destroy(User $user): RedirectResponse
{
if ($user->is(request()->user())) {
Toast::error('You cannot delete your own account');
return back();
}
$user->delete();
Toast::success('User deleted successfully');
return redirect()->route('settings.users.index');
}
}

@ -1,98 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\Site\CreateSite;
use App\Actions\Site\DeleteSite;
use App\Enums\SiteStatus;
use App\Enums\SiteType;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Server;
use App\Models\Site;
use App\Models\SourceControl;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class SiteController extends Controller
{
public function index(Server $server): View
{
$this->authorize('manage', $server);
return view('sites.index', [
'server' => $server,
'sites' => $server->sites()->orderByDesc('id')->get(),
]);
}
public function store(Server $server, Request $request): HtmxResponse
{
$this->authorize('manage', $server);
$site = app(CreateSite::class)->create($server, $request->input());
Toast::success('Site created');
return htmx()->redirect(route('servers.sites.show', [$server, $site]));
}
public function create(Server $server): View
{
$this->authorize('manage', $server);
return view('sites.create', [
'server' => $server,
'type' => old('type', request()->query('type', SiteType::LARAVEL)),
'sourceControls' => SourceControl::all(),
]);
}
public function show(Server $server, Site $site, Request $request): View|RedirectResponse|HtmxResponse
{
$this->authorize('manage', $server);
if (in_array($site->status, [SiteStatus::INSTALLING, SiteStatus::INSTALLATION_FAILED])) {
if ($request->hasHeader('HX-Request')) {
return htmx()->redirect(route('servers.sites.installing', [$server, $site]));
}
return redirect()->route('servers.sites.installing', [$server, $site]);
}
return view('sites.show', [
'server' => $server,
'site' => $site,
]);
}
public function installing(Server $server, Site $site, Request $request): View|RedirectResponse|HtmxResponse
{
$this->authorize('manage', $server);
if (! in_array($site->status, [SiteStatus::INSTALLING, SiteStatus::INSTALLATION_FAILED])) {
if ($request->hasHeader('HX-Request')) {
return htmx()->redirect(route('servers.sites.show', [$server, $site]));
}
return redirect()->route('servers.sites.show', [$server, $site]);
}
return view('sites.installing', [
'server' => $server,
'site' => $site,
]);
}
public function destroy(Server $server, Site $site): RedirectResponse
{
$this->authorize('manage', $server);
app(DeleteSite::class)->delete($site);
Toast::success('Site is being deleted');
return redirect()->route('servers.sites', $server);
}
}

@ -1,21 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Models\Server;
use App\Models\Site;
use Illuminate\Contracts\View\View;
class SiteLogController extends Controller
{
public function index(Server $server, Site $site): View
{
$this->authorize('manage', $server);
return view('site-logs.index', [
'server' => $server,
'site' => $site,
'pageTitle' => __('Vito Logs'),
]);
}
}

@ -1,104 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Actions\Site\UpdateAliases;
use App\Actions\Site\UpdateSourceControl;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Server;
use App\Models\Site;
use App\SSH\Services\Webserver\Webserver;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Throwable;
class SiteSettingController extends Controller
{
public function index(Server $server, Site $site): View
{
$this->authorize('manage', $server);
return view('site-settings.index', [
'server' => $server,
'site' => $site,
]);
}
public function getVhost(Server $server, Site $site): RedirectResponse
{
$this->authorize('manage', $server);
/** @var Webserver $handler */
$handler = $server->webserver()->handler();
return back()->with('vhost', $handler->getVHost($site));
}
public function updateVhost(Server $server, Site $site, Request $request): RedirectResponse
{
$this->authorize('manage', $server);
$this->validate($request, [
'vhost' => 'required|string',
]);
try {
/** @var Webserver $handler */
$handler = $server->webserver()->handler();
$handler->updateVHost($site, false, $request->input('vhost'));
Toast::success('VHost updated successfully!');
} catch (Throwable $e) {
Toast::error($e->getMessage());
}
return back();
}
public function updatePHPVersion(Server $server, Site $site, Request $request): HtmxResponse
{
$this->authorize('manage', $server);
$this->validate($request, [
'version' => [
'required',
Rule::exists('services', 'version')->where('type', 'php'),
],
]);
try {
$site->changePHPVersion($request->input('version'));
Toast::success('PHP version updated successfully!');
} catch (Throwable $e) {
Toast::error($e->getMessage());
}
return htmx()->back();
}
public function updateSourceControl(Server $server, Site $site, Request $request): HtmxResponse
{
$this->authorize('manage', $server);
app(UpdateSourceControl::class)->update($site, $request->input());
Toast::success('Source control updated successfully!');
return htmx()->back();
}
public function updateAliases(Server $server, Site $site, Request $request): HtmxResponse
{
$this->authorize('manage', $server);
app(UpdateAliases::class)->update($site, $request->input());
Toast::success('Aliases updated successfully!');
return htmx()->back();
}
}

@ -2,9 +2,6 @@
namespace App\Http;
use App\Http\Middleware\HandleSSHErrors;
use App\Http\Middleware\SelectCurrentProject;
use App\Http\Middleware\ServerIsReadyMiddleware;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
@ -65,10 +62,5 @@ class Kernel extends HttpKernel
'signed' => \App\Http\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'server-is-ready' => ServerIsReadyMiddleware::class,
'handle-ssh-errors' => HandleSSHErrors::class,
'select-current-project' => SelectCurrentProject::class,
'is-admin' => \App\Http\Middleware\IsAdmin::class,
'must-have-current-project' => \App\Http\Middleware\MustHaveCurrentProject::class,
];
}

@ -1,25 +0,0 @@
<?php
namespace App\Http\Middleware;
use App\Enums\UserRole;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class IsAdmin
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
if (auth()->user()->role !== UserRole::ADMIN) {
abort(403, 'You are not authorized to access this page.');
}
return $next($request);
}
}

@ -1,31 +0,0 @@
<?php
namespace App\Http\Middleware;
use App\Facades\Toast;
use App\Models\User;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class MustHaveCurrentProject
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
/** @var User $user */
$user = $request->user();
if (! $user->currentProject) {
Toast::warning('Please select a project to continue');
return redirect()->route('profile');
}
return $next($request);
}
}

@ -1,32 +0,0 @@
<?php
namespace App\Http\Middleware;
use App\Models\User;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class SelectCurrentProject
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
/** @var Server $server */
$server = $request->route('server');
/** @var User $user */
$user = $request->user();
if ($server->project_id != $user->current_project_id && $user->can('view', $server)) {
$user->current_project_id = $server->project_id;
$user->save();
}
return $next($request);
}
}

@ -1,26 +0,0 @@
<?php
namespace App\Http\Middleware;
use App\Enums\ServerStatus;
use App\Facades\Toast;
use App\Models\Server;
use Closure;
use Illuminate\Http\Request;
class ServerIsReadyMiddleware
{
public function handle(Request $request, Closure $next)
{
/** @var Server $server */
$server = $request->route('server');
if ($server->status !== ServerStatus::READY) {
Toast::error('Server is not ready yet');
return redirect()->route('servers.show', ['server' => $server]);
}
return $next($request);
}
}

@ -44,7 +44,7 @@ public function boot(): void
);
FilamentView::registerRenderHook(
PanelsRenderHook::SIDEBAR_FOOTER,
fn () => view('web.components.app-version')
fn () => view('components.app-version')
);
FilamentAsset::register([
Js::make('app', Vite::asset('resources/js/app.js'))->module(),
@ -86,7 +86,7 @@ public function panel(Panel $panel): Panel
'primary' => Color::Indigo,
])
->viteTheme('resources/css/filament/app/theme.css')
->brandLogo(fn () => view('web.components.brand'))
->brandLogo(fn () => view('components.brand'))
->brandLogoHeight('30px')
->discoverPages(in: app_path('Web/Pages'), for: 'App\\Web\\Pages')
->middleware([

@ -1,14 +0,0 @@
<?php
namespace App\View\Components;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class AppLayout extends Component
{
public function render(): View
{
return view('layouts.app');
}
}

@ -1,47 +0,0 @@
<?php
namespace App\View\Components;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Str;
use Illuminate\View\Component;
class Editor extends Component
{
public string $id;
public string $name;
public ?string $value;
public array $options;
public function __construct(
string $name,
?string $value,
public string $lang,
public bool $readonly = false,
public bool $lineNumbers = true,
) {
$this->id = $name.'-'.Str::random(8);
$this->name = $name;
$this->value = json_encode($value ?? '');
$this->options = $this->getOptions();
}
private function getOptions(): array
{
return [
'id' => $this->id,
'name' => $this->name,
'lang' => $this->lang,
'value' => $this->value,
];
}
public function render(): View|Closure|string
{
return view('components.editor');
}
}

@ -1,14 +0,0 @@
<?php
namespace App\View\Components;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class GuestLayout extends Component
{
public function render(): View
{
return view('layouts.guest');
}
}

@ -1,26 +0,0 @@
<?php
namespace App\View\Components;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class Heroicon extends Component
{
/**
* Create a new component instance.
*/
public function __construct(public string $name)
{
//
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.heroicons.'.$this->name);
}
}

@ -1,17 +0,0 @@
<?php
namespace App\View\Components;
use App\Models\Server;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class ServerLayout extends Component
{
public function __construct(public Server $server) {}
public function render(): View
{
return view('layouts.server');
}
}

@ -1,14 +0,0 @@
<?php
namespace App\View\Components;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class SettingsLayout extends Component
{
public function render(): View
{
return view('layouts.settings');
}
}

@ -1,17 +0,0 @@
<?php
namespace App\View\Components;
use App\Models\Site;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class SiteLayout extends Component
{
public function __construct(public Site $site) {}
public function render(): View
{
return view('layouts.site');
}
}

@ -12,7 +12,7 @@ public function __construct(public string $href, public string $text, public boo
public function render(): View
{
return view('web.components.link');
return view('components.link');
}
public function toHtml(): View|string

@ -7,7 +7,7 @@
abstract class Page extends BasePage
{
protected static string $view = 'web.components.page';
protected static string $view = 'components.page';
protected ?string $live = '5s';

@ -6,7 +6,7 @@
class AlertField extends Field
{
protected string $view = 'web.fields.alert';
protected string $view = 'fields.alert';
public string $color = 'blue';

@ -6,7 +6,7 @@
class CodeEditorField extends Field
{
protected string $view = 'web.fields.code-editor';
protected string $view = 'fields.code-editor';
public string $lang = '';

@ -6,5 +6,5 @@
class ProviderField extends Field
{
protected string $view = 'web.fields.provider';
protected string $view = 'fields.provider';
}

@ -12,7 +12,7 @@ class Console extends Component
public function render(): View
{
return view('web.components.console', [
return view('components.console', [
'server' => $this->server,
]);
}

@ -48,7 +48,7 @@ protected function getHeaderActions(): array
->form([
TextInput::make('command')
->rules(fn (callable $get) => CreateCronJob::rules($get())['command'])
->helperText(fn () => view('web.components.link', [
->helperText(fn () => view('components.link', [
'href' => 'https://vitodeploy.com/servers/cronjobs.html',
'external' => true,
'text' => 'How the command should look like?',

@ -65,7 +65,7 @@ public function getTable(): Table
->color('gray')
->tooltip('Show backup files')
->authorize(fn (Backup $record) => auth()->user()->can('viewAny', [BackupFile::class, $record]))
->modalContent(fn (Backup $record) => view('web.components.dynamic-widget', [
->modalContent(fn (Backup $record) => view('components.dynamic-widget', [
'widget' => BackupFilesList::class,
'params' => [
'backup' => $record,

@ -18,7 +18,7 @@ class FilterForm extends Widget implements HasForms
{
use InteractsWithForms;
protected static string $view = 'web.components.form';
protected static string $view = 'components.form';
public ?array $data = [
'period' => '1h',
@ -73,7 +73,7 @@ public function form(Form $form): Form
]),
ViewField::make('data')
->reactive()
->view('web.components.dynamic-widget', [
->view('components.dynamic-widget', [
'widget' => Metrics::class,
'params' => [
'server' => $this->server,

@ -24,7 +24,7 @@ class MetricDetails extends Widget implements HasForms, HasInfolists
protected static bool $isLazy = false;
protected static string $view = 'web.components.infolist';
protected static string $view = 'components.infolist';
public Server $server;

@ -22,7 +22,7 @@ class Installing extends Widget implements HasForms, HasInfolists
protected static bool $isLazy = false;
protected static string $view = 'web.components.infolist';
protected static string $view = 'components.infolist';
public Site $site;

@ -32,7 +32,7 @@ class SiteDetails extends Widget implements HasForms, HasInfolists
protected static bool $isLazy = false;
protected static string $view = 'web.components.infolist';
protected static string $view = 'components.infolist';
public Site $site;

@ -22,7 +22,7 @@ class SiteSummary extends Widget implements HasForms, HasInfolists
protected static bool $isLazy = false;
protected static string $view = 'web.components.infolist';
protected static string $view = 'components.infolist';
public Site $site;

@ -22,7 +22,7 @@ class Installing extends Widget implements HasForms, HasInfolists
protected static bool $isLazy = false;
protected static string $view = 'web.components.infolist';
protected static string $view = 'components.infolist';
public Server $server;

@ -1,101 +0,0 @@
<?php
namespace App\Web\Pages\Servers\Widgets;
use App\Models\Server;
use App\Web\Resources\Server\Pages\CreateServer;
use Filament\Forms\Components\Actions\Action;
use Filament\Forms\Components\Select;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Widgets\Widget;
use Illuminate\Database\Eloquent\Builder;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class SelectServer extends Widget implements HasForms
{
use InteractsWithForms;
protected static string $view = 'web.components.form';
public int|string|null $server = null;
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function mount(): void
{
$server = Server::query()
->where('project_id', auth()->user()->current_project_id)
->find(session()->get('current_server_id'));
if ($server && auth()->user()->can('view', $server)) {
$this->server = $server->id;
}
}
protected function getFormSchema(): array
{
$options = $this->query()
->limit(10)
->pluck('name', 'id')
->toArray();
return [
Select::make('server')
->name('server')
->model($this->server)
->searchable()
->options($options)
->searchPrompt('Search...')
->getSearchResultsUsing(function ($search) {
return $this->query()
->where('name', 'like', "%{$search}%")
->limit(10)
->pluck('name', 'id')
->toArray();
})
->extraAttributes(['class' => '-mx-2 pointer-choices'])
->live()
->hintIcon('heroicon-o-question-mark-circle')
->hintIconTooltip('Filter resources by default based on a server')
->suffixAction(
Action::make('create')
->icon('heroicon-o-plus')
->tooltip('Create a new server')
->url(CreateServer::getUrl())
),
];
}
private function query(): Builder
{
return Server::query()
->where(function (Builder $query) {
$query->where('project_id', auth()->user()->current_project_id);
});
}
public function updatedServer($value): void
{
if (! $value) {
session()->forget('current_server_id');
$this->redirect(url()->previous());
return;
}
$server = Server::query()->find($value);
if (! $server) {
session()->forget('current_server_id');
return;
}
$this->authorize('view', $server);
session()->put('current_server_id', $value);
$this->redirect(url()->previous());
}
}

@ -25,7 +25,7 @@ class ServerDetails extends Widget implements HasForms, HasInfolists
protected static bool $isLazy = false;
protected static string $view = 'web.components.infolist';
protected static string $view = 'components.infolist';
public Server $server;

@ -25,7 +25,7 @@ class ServerSummary extends Widget implements HasForms, HasInfolists
protected static bool $isLazy = false;
protected static string $view = 'web.components.infolist';
protected static string $view = 'components.infolist';
public Server $server;

@ -19,7 +19,7 @@ class UpdateServerInfo extends Widget implements HasForms
protected static bool $isLazy = false;
protected static string $view = 'web.components.form';
protected static string $view = 'components.form';
public Server $server;

@ -18,7 +18,7 @@ class ProfileInformation extends Widget implements HasForms
protected static bool $isLazy = false;
protected static string $view = 'web.components.form';
protected static string $view = 'components.form';
public string $name;

@ -26,7 +26,7 @@ class TwoFactor extends Widget implements HasForms, HasInfolists
protected static bool $isLazy = false;
protected static string $view = 'web.components.infolist';
protected static string $view = 'components.infolist';
public bool $enabled = false;
@ -52,7 +52,7 @@ public function infolist(Infolist $infolist): Infolist
->visible(! $this->enabled),
ViewEntry::make('qr_code')
->hiddenLabel()
->view('web.components.container', [
->view('components.container', [
'content' => $this->enabled ? auth()->user()->twoFactorQrCodeSvg() : null,
])
->visible($this->enabled && $this->showCodes),
@ -69,7 +69,7 @@ public function infolist(Infolist $infolist): Infolist
ViewEntry::make('recovery_codes')
->hiddenLabel()
->extraAttributes(['class' => 'rounded-lg border border-gray-100 p-2 dark:border-gray-700'])
->view('web.components.container', [
->view('components.container', [
'content' => $this->enabled ? implode('</br>', json_decode(decrypt(auth()->user()->two_factor_recovery_codes), true)) : null,
])
->visible($this->enabled),

@ -17,7 +17,7 @@ class UpdatePassword extends Widget implements HasForms
protected static bool $isLazy = false;
protected static string $view = 'web.components.form';
protected static string $view = 'components.form';
public string $current_password = '';

@ -16,7 +16,7 @@ class AddUser extends Widget implements HasForms
{
use InteractsWithForms;
protected static string $view = 'web.components.form';
protected static string $view = 'components.form';
public Project $project;

@ -9,7 +9,7 @@
class SelectProject extends Widget
{
protected static string $view = 'web.widgets.select-project';
protected static string $view = 'widgets.select-project';
public ?Project $currentProject;

@ -15,7 +15,7 @@ class UpdateProject extends Widget implements HasForms
{
use InteractsWithForms;
protected static string $view = 'web.components.form';
protected static string $view = 'components.form';
public Project $project;

@ -1 +0,0 @@
.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;white-space:normal;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1}

File diff suppressed because one or more lines are too long

@ -1,24 +0,0 @@
{
"resources/css/app.css": {
"file": "assets/app-852e0e7b.css",
"isEntry": true,
"src": "resources/css/app.css"
},
"resources/css/filament/app/theme.css": {
"file": "assets/theme-98a3afe7.css",
"isEntry": true,
"src": "resources/css/filament/app/theme.css"
},
"resources/js/app.css": {
"file": "assets/app-a1ae07b3.css",
"src": "resources/js/app.css"
},
"resources/js/app.js": {
"css": [
"assets/app-a1ae07b3.css"
],
"file": "assets/app-d9a3bf01.js",
"isEntry": true,
"src": "resources/js/app.js"
}
}

@ -1,119 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg height="383.5975" id="svg3430" version="1.1" viewBox="0 0 711.20123 383.5975" width="711.20123"
xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg">
<title id="title3510">Official PHP Logo</title>
<metadata id="metadata3436">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title>Official PHP Logo</dc:title>
<dc:creator>
<cc:Agent>
<dc:title>Colin Viebrock</dc:title>
</cc:Agent>
</dc:creator>
<dc:description/>
<dc:contributor>
<cc:Agent>
<dc:title/>
</cc:Agent>
</dc:contributor>
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/"/>
<dc:rights>
<cc:Agent>
<dc:title>Copyright Colin Viebrock 1997 - All rights reserved.</dc:title>
</cc:Agent>
</dc:rights>
<dc:date>1997</dc:date>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike"/>
</cc:License>
</rdf:RDF>
</metadata>
<defs id="defs3434">
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath3444">
<path
d="M 11.52,162 C 11.52,81.677 135.307,16.561 288,16.561 l 0,0 c 152.693,0 276.481,65.116 276.481,145.439 l 0,0 c 0,80.322 -123.788,145.439 -276.481,145.439 l 0,0 C 135.307,307.439 11.52,242.322 11.52,162"
id="path3446"/>
</clipPath>
<radialGradient cx="0" cy="0" fx="0" fy="0"
gradientTransform="matrix(363.05789,0,0,-363.05789,177.52002,256.30713)"
gradientUnits="userSpaceOnUse" id="radialGradient3452" r="1" spreadMethod="pad">
<stop id="stop3454" offset="0" style="stop-opacity:1;stop-color:#aeb2d5"/>
<stop id="stop3456" offset="0.3" style="stop-opacity:1;stop-color:#aeb2d5"/>
<stop id="stop3458" offset="0.75" style="stop-opacity:1;stop-color:#484c89"/>
<stop id="stop3460" offset="1" style="stop-opacity:1;stop-color:#484c89"/>
</radialGradient>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath3468">
<path d="M 0,324 576,324 576,0 0,0 0,324 Z" id="path3470"/>
</clipPath>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath3480">
<path d="M 0,324 576,324 576,0 0,0 0,324 Z" id="path3482"/>
</clipPath>
</defs>
<g id="g3438" transform="matrix(1.25,0,0,-1.25,-4.4,394.29875)">
<g id="g3440">
<g clip-path="url(#clipPath3444)" id="g3442">
<g id="g3448">
<g id="g3450">
<path
d="M 11.52,162 C 11.52,81.677 135.307,16.561 288,16.561 l 0,0 c 152.693,0 276.481,65.116 276.481,145.439 l 0,0 c 0,80.322 -123.788,145.439 -276.481,145.439 l 0,0 C 135.307,307.439 11.52,242.322 11.52,162"
id="path3462" style="fill:url(#radialGradient3452);stroke:none"/>
</g>
</g>
</g>
</g>
<g id="g3464">
<g clip-path="url(#clipPath3468)" id="g3466">
<g id="g3472" transform="translate(288,27.3594)">
<path
d="M 0,0 C 146.729,0 265.68,60.281 265.68,134.641 265.68,209 146.729,269.282 0,269.282 -146.729,269.282 -265.68,209 -265.68,134.641 -265.68,60.281 -146.729,0 0,0"
id="path3474" style="fill:#777bb3;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
</g>
</g>
</g>
<g id="g3476">
<g clip-path="url(#clipPath3480)" id="g3478">
<g id="g3484" transform="translate(161.7344,145.3066)">
<path
d="m 0,0 c 12.065,0 21.072,2.225 26.771,6.611 5.638,4.341 9.532,11.862 11.573,22.353 1.903,9.806 1.178,16.653 -2.154,20.348 C 32.783,53.086 25.417,55 14.297,55 L -4.984,55 -15.673,0 0,0 Z m -63.063,-67.75 c -0.895,0 -1.745,0.4 -2.314,1.092 -0.57,0.691 -0.801,1.601 -0.63,2.48 L -37.679,81.573 C -37.405,82.982 -36.17,84 -34.734,84 L 26.32,84 C 45.508,84 59.79,78.79 68.767,68.513 77.792,58.182 80.579,43.741 77.05,25.592 75.614,18.198 73.144,11.331 69.709,5.183 66.27,-0.972 61.725,-6.667 56.198,-11.747 49.582,-17.939 42.094,-22.429 33.962,-25.071 25.959,-27.678 15.681,-29 3.414,-29 l -24.722,0 -7.06,-36.322 c -0.274,-1.41 -1.508,-2.428 -2.944,-2.428 l -31.751,0 z"
id="path3486" style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
</g>
<g id="g3488" transform="translate(159.2236,197.3071)">
<path
d="m 0,0 16.808,0 c 13.421,0 18.083,-2.945 19.667,-4.7 2.628,-2.914 3.124,-9.058 1.435,-17.767 C 36.012,-32.217 32.494,-39.13 27.452,-43.012 22.29,-46.986 13.898,-49 2.511,-49 L -9.523,-49 0,0 Z m 28.831,35 -61.055,0 c -2.872,0 -5.341,-2.036 -5.889,-4.855 l -28.328,-145.751 c -0.342,-1.759 0.12,-3.578 1.259,-4.961 1.14,-1.383 2.838,-2.183 4.63,-2.183 l 31.75,0 c 2.873,0 5.342,2.036 5.89,4.855 l 6.588,33.895 22.249,0 c 12.582,0 23.174,1.372 31.479,4.077 8.541,2.775 16.399,7.48 23.354,13.984 5.752,5.292 10.49,11.232 14.08,17.657 3.591,6.427 6.171,13.594 7.668,21.302 3.715,19.104 0.697,34.402 -8.969,45.466 C 63.965,29.444 48.923,35 28.831,35 m -45.633,-90 19.313,0 c 12.801,0 22.336,2.411 28.601,7.234 6.266,4.824 10.492,12.875 12.688,24.157 2.101,10.832 1.144,18.476 -2.871,22.929 C 36.909,3.773 28.87,6 16.808,6 L -4.946,6 -16.802,-55 M 28.831,29 C 47.198,29 60.597,24.18 69.019,14.539 77.44,4.898 79.976,-8.559 76.616,-25.836 75.233,-32.953 72.894,-39.46 69.601,-45.355 66.304,-51.254 61.999,-56.648 56.679,-61.539 50.339,-67.472 43.296,-71.7 35.546,-74.218 27.796,-76.743 17.925,-78 5.925,-78 l -27.196,0 -7.531,-38.75 -31.75,0 28.328,145.75 61.055,0"
id="path3490" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
</g>
<g id="g3492" transform="translate(311.583,116.3066)">
<path
d="m 0,0 c -0.896,0 -1.745,0.4 -2.314,1.092 -0.571,0.691 -0.802,1.6 -0.631,2.48 L 9.586,68.061 C 10.778,74.194 10.484,78.596 8.759,80.456 7.703,81.593 4.531,83.5 -4.848,83.5 L -27.55,83.5 -43.305,2.428 C -43.579,1.018 -44.814,0 -46.25,0 l -31.5,0 c -0.896,0 -1.745,0.4 -2.315,1.092 -0.57,0.691 -0.801,1.601 -0.63,2.48 l 28.328,145.751 c 0.274,1.409 1.509,2.427 2.945,2.427 l 31.5,0 c 0.896,0 1.745,-0.4 2.315,-1.091 0.57,-0.692 0.801,-1.601 0.63,-2.481 L -21.813,113 2.609,113 c 18.605,0 31.221,-3.28 38.569,-10.028 7.49,-6.884 9.827,-17.891 6.947,-32.719 L 34.945,2.428 C 34.671,1.018 33.437,0 32,0 L 0,0 Z"
id="path3494" style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
</g>
<g id="g3496" transform="translate(293.6611,271.0571)">
<path
d="m 0,0 -31.5,0 c -2.873,0 -5.342,-2.036 -5.89,-4.855 l -28.328,-145.751 c -0.342,-1.759 0.12,-3.578 1.26,-4.961 1.14,-1.383 2.838,-2.183 4.63,-2.183 l 31.5,0 c 2.872,0 5.342,2.036 5.89,4.855 l 15.283,78.645 20.229,0 c 9.363,0 11.328,-2 11.407,-2.086 0.568,-0.611 1.315,-3.441 0.082,-9.781 l -12.531,-64.489 c -0.342,-1.759 0.12,-3.578 1.26,-4.961 1.14,-1.383 2.838,-2.183 4.63,-2.183 l 32,0 c 2.872,0 5.342,2.036 5.89,4.855 l 13.179,67.825 c 3.093,15.921 0.447,27.864 -7.861,35.5 -7.928,7.281 -21.208,10.82 -40.599,10.82 l -20.784,0 6.143,31.605 C 6.231,-5.386 5.77,-3.566 4.63,-2.184 3.49,-0.801 1.792,0 0,0 m 0,-6 -7.531,-38.75 28.062,0 c 17.657,0 29.836,-3.082 36.539,-9.238 6.703,-6.16 8.711,-16.141 6.032,-29.938 l -13.18,-67.824 -32,0 12.531,64.488 c 1.426,7.336 0.902,12.34 -1.574,15.008 -2.477,2.668 -7.746,4.004 -15.805,4.004 l -25.176,0 -16.226,-83.5 -31.5,0 L -31.5,-6 0,-6"
id="path3498" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
</g>
<g id="g3500" transform="translate(409.5498,145.3066)">
<path
d="m 0,0 c 12.065,0 21.072,2.225 26.771,6.611 5.638,4.34 9.532,11.861 11.574,22.353 1.903,9.806 1.178,16.653 -2.155,20.348 C 32.783,53.086 25.417,55 14.297,55 L -4.984,55 -15.673,0 0,0 Z m -63.062,-67.75 c -0.895,0 -1.745,0.4 -2.314,1.092 -0.57,0.691 -0.802,1.601 -0.631,2.48 L -37.679,81.573 C -37.404,82.982 -36.17,84 -34.733,84 L 26.32,84 C 45.509,84 59.79,78.79 68.768,68.513 77.793,58.183 80.579,43.742 77.051,25.592 75.613,18.198 73.144,11.331 69.709,5.183 66.27,-0.972 61.725,-6.667 56.198,-11.747 49.582,-17.939 42.094,-22.429 33.962,-25.071 25.959,-27.678 15.681,-29 3.414,-29 l -24.723,0 -7.057,-36.322 c -0.275,-1.41 -1.509,-2.428 -2.946,-2.428 l -31.75,0 z"
id="path3502" style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
</g>
<g id="g3504" transform="translate(407.0391,197.3071)">
<path
d="M 0,0 16.808,0 C 30.229,0 34.891,-2.945 36.475,-4.7 39.104,-7.614 39.6,-13.758 37.91,-22.466 36.012,-32.217 32.493,-39.13 27.452,-43.012 22.29,-46.986 13.898,-49 2.511,-49 L -9.522,-49 0,0 Z m 28.831,35 -61.054,0 c -2.872,0 -5.341,-2.036 -5.889,-4.855 L -66.44,-115.606 c -0.342,-1.759 0.12,-3.578 1.259,-4.961 1.14,-1.383 2.838,-2.183 4.63,-2.183 l 31.75,0 c 2.872,0 5.342,2.036 5.89,4.855 l 6.587,33.895 22.249,0 c 12.582,0 23.174,1.372 31.479,4.077 8.541,2.775 16.401,7.481 23.356,13.986 5.752,5.291 10.488,11.23 14.078,17.655 3.591,6.427 6.171,13.594 7.668,21.302 3.715,19.105 0.697,34.403 -8.969,45.467 C 63.965,29.444 48.924,35 28.831,35 m -45.632,-90 19.312,0 c 12.801,0 22.336,2.411 28.601,7.234 6.267,4.824 10.492,12.875 12.688,24.157 2.102,10.832 1.145,18.476 -2.871,22.929 C 36.909,3.773 28.87,6 16.808,6 L -4.946,6 -16.801,-55 M 28.831,29 C 47.198,29 60.597,24.18 69.019,14.539 77.441,4.898 79.976,-8.559 76.616,-25.836 75.233,-32.953 72.894,-39.46 69.601,-45.355 66.304,-51.254 61.999,-56.648 56.679,-61.539 50.339,-67.472 43.296,-71.7 35.546,-74.218 27.796,-76.743 17.925,-78 5.925,-78 l -27.196,0 -7.53,-38.75 -31.75,0 28.328,145.75 61.054,0"
id="path3506" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
</g>
</g>
</g>
</g>
</svg>

Before

(image error) Size: 10 KiB

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<svg width="256px" height="220px" viewBox="0 0 256 220" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
<g>
<path d="M245.969687,168.943256 C232.308259,176.064479 161.536048,205.163388 146.468577,213.017633 C131.402107,220.873879 123.031844,220.797876 111.129473,215.107699 C99.2271007,209.417521 23.9127473,178.99557 10.3463234,172.511368 C3.56511141,169.270267 0,166.535181 0,163.9511 L0,138.075292 C0,138.075292 98.0490639,116.729625 113.878559,111.051447 C129.707053,105.372269 135.199225,105.167264 148.669646,110.101418 C162.141067,115.036572 242.686583,129.569026 256,134.445178 C256,134.445178 255.993999,157.5559 255.993999,159.954975 C255.996,162.513055 252.923904,165.319143 245.969687,168.943256" fill="#912626"></path>
<path d="M245.964922,143.220067 C232.303935,150.33806 161.534003,179.438032 146.467017,187.292024 C131.401031,195.149018 123.031039,195.072017 111.12905,189.382023 C99.2260618,183.696028 23.9151336,153.269057 10.3491466,146.788063 C-3.21684053,140.303069 -3.50184026,135.840074 9.82514705,130.622079 C23.1511343,125.402084 98.0490629,96.0171117 113.880047,90.3381172 C129.708033,84.6611226 135.199028,84.4541228 148.669014,89.3901181 C162.140002,94.3241134 232.487935,122.325087 245.799922,127.200082 C259.11491,132.081078 259.625908,136.099073 245.964922,143.220067" fill="#C6302B"></path>
<path d="M245.969687,127.074354 C232.308259,134.195577 161.536048,163.294486 146.468577,171.151732 C131.402107,179.004977 123.031844,178.928975 111.129473,173.238797 C99.2261007,167.551619 23.9127473,137.126668 10.3463234,130.642465 C3.56511141,127.401364 0,124.669279 0,122.085199 L0,96.2063895 C0,96.2063895 98.0490639,74.8617226 113.878559,69.182545 C129.707053,63.5043676 135.199225,63.2983612 148.669646,68.2325154 C162.141067,73.1676697 242.686583,87.6971237 256,92.5742761 C256,92.5742761 255.993999,115.684998 255.993999,118.087073 C255.996,120.644153 252.923904,123.450241 245.969687,127.074354" fill="#912626"></path>
<path d="M245.964922,101.351164 C232.303935,108.471157 161.534003,137.569129 146.467017,145.426122 C131.401031,153.280114 123.031039,153.203114 111.12905,147.51312 C99.2260618,141.827125 23.9151336,111.401154 10.3491466,104.91916 C-3.21684053,98.4361664 -3.50184026,93.9721706 9.82514705,88.7521756 C23.1511343,83.5351806 98.0490629,54.1482087 113.880047,48.4702141 C129.708033,42.7922195 135.199028,42.5862197 148.669014,47.521215 C162.140002,52.4552102 232.487935,80.4541835 245.799922,85.3311789 C259.11491,90.2101742 259.625908,94.2301704 245.964922,101.350163 L245.964922,101.351164" fill="#C6302B"></path>
<path d="M245.969687,83.6525661 C232.308259,90.7737887 161.536048,119.873698 146.468577,127.730944 C131.402107,135.585189 123.031844,135.508187 111.129473,129.818008 C99.2261007,124.130831 23.9127473,93.7048802 10.3463234,87.2226777 C3.56511141,83.9805764 0,81.2474909 0,78.6654102 L0,52.7856015 C0,52.7856015 98.0490639,31.4419345 113.878559,25.7637571 C129.707053,20.0845797 135.199225,19.8795733 148.669646,24.8137275 C162.141067,29.7488817 242.686583,44.2783357 256,49.1554881 C256,49.1554881 255.993999,72.2662103 255.993999,74.6672853 C255.996,77.2223652 252.923904,80.0284528 245.969687,83.6525661" fill="#912626"></path>
<path d="M245.964922,57.929387 C232.303935,65.0493802 161.534003,94.1493524 146.467017,102.004345 C131.401031,109.858338 123.031039,109.781338 111.12905,104.093343 C99.2270617,98.4053484 23.9151336,67.9813773 10.3491466,61.4983836 C-3.21684053,55.0153898 -3.50184026,50.550394 9.82514705,45.331399 C23.1511343,40.113404 98.0490629,10.729432 113.880047,5.04943744 C129.708033,-0.629557148 135.199028,-0.833556953 148.669014,4.10143834 C162.140002,9.03643363 232.487935,37.0354069 245.799922,41.9124022 C259.11491,46.7883976 259.625908,50.8093938 245.964922,57.929387" fill="#C6302B"></path>
<path d="M159.282977,32.7570853 L137.273922,35.0422326 L132.346419,46.8976124 L124.387597,33.667969 L98.973147,31.383814 L117.936992,24.5452403 L112.247442,14.0472558 L130.001736,20.9910078 L146.739969,15.5108217 L142.21631,26.3660155 L159.282977,32.7570853" fill="#FFFFFF"></path>
<path d="M131.03169,90.2747287 L89.9546047,73.2378295 L148.815752,64.2034109 L131.03169,90.2747287" fill="#FFFFFF"></path>
<path d="M74.0816124,39.3466047 C91.4568682,39.3466047 105.541829,44.8069457 105.541829,51.5413333 C105.541829,58.2767132 91.4568682,63.736062 74.0816124,63.736062 C56.7073488,63.736062 42.6213953,58.2767132 42.6213953,51.5413333 C42.6213953,44.8069457 56.7073488,39.3466047 74.0816124,39.3466047" fill="#FFFFFF"></path>
<path d="M185.29476,35.9977674 L220.130605,49.7642171 L185.324527,63.5167752 L185.29476,35.9977674" fill="#621B1C"></path>
<path d="M146.754853,51.2426667 L185.29476,35.9977674 L185.324527,63.5167752 L181.546047,64.9952248 L146.754853,51.2426667" fill="#9A2928"></path>
</g>
</svg>

Before

(image error) Size: 4.9 KiB

@ -1,5 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="#4f46e5"
class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round"
d="m6.75 7.5 3 2.25-3 2.25m4.5 0h3m-9 8.25h13.5A2.25 2.25 0 0 0 21 18V6a2.25 2.25 0 0 0-2.25-2.25H5.25A2.25 2.25 0 0 0 3 6v12a2.25 2.25 0 0 0 2.25 2.25Z" />
</svg>

Before

(image error) Size: 357 B

@ -1,39 +0,0 @@
<div>
@if ($site->deploymentScript)
<x-dropdown>
<x-slot name="trigger">
<x-secondary-button>
{{ __("Auto Deployment") }}
<x-heroicon name="o-chevron-down" class="ml-1 h-4 w-4" />
</x-secondary-button>
</x-slot>
<x-slot name="content">
<div id="auto-deployment">
<x-dropdown-link
class="cursor-pointer"
hx-post="{{ route('servers.sites.application.auto-deployment', ['server' => $server, 'site' => $site]) }}"
hx-swap="outerHTML"
hx-target="#auto-deployment"
hx-select="#auto-deployment"
>
{{ __("Enable") }}
@if ($site->isAutoDeployment())
<x-heroicon name="o-check" class="ml-1 h-5 w-5 text-green-600" />
@endif
</x-dropdown-link>
<x-dropdown-link
class="cursor-pointer"
hx-delete="{{ route('servers.sites.application.auto-deployment', ['server' => $server, 'site' => $site]) }}"
hx-swap="outerHTML"
hx-target="#auto-deployment"
>
{{ __("Disable") }}
@if (! $site->isAutoDeployment())
<x-heroicon name="o-check" class="ml-1 h-5 w-5 text-green-600" />
@endif
</x-dropdown-link>
</div>
</x-slot>
</x-dropdown>
@endif
</div>

@ -1,39 +0,0 @@
<div x-data="">
<x-modal name="change-branch">
<form
id="change-branch-form"
hx-post="{{ route("servers.sites.application.branch", ["server" => $server, "site" => $site]) }}"
hx-select="#change-branch-form"
hx-swap="outerHTML"
class="p-6"
>
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __("Change Branch") }}
</h2>
<div class="mt-6">
<x-input-label for="branch" :value="__('Branch')" />
<x-text-input
value="{{ old('branch', $site->branch) }}"
id="branch"
name="branch"
type="text"
class="mt-1 w-full"
/>
@error("branch")
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6 flex items-center justify-end">
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __("Cancel") }}
</x-secondary-button>
<x-primary-button class="ml-3" hx-disable>
{{ __("Save") }}
</x-primary-button>
</div>
</form>
</x-modal>
</div>

@ -1,26 +0,0 @@
<div>
@php
$hasDeploymentScript = (bool) $site->deploymentScript;
@endphp
<form
id="deploy"
@if ($hasDeploymentScript)
hx-post="{{ route("servers.sites.application.deploy", ["server" => $server, "site" => $site]) }}"
hx-swap="outerHTML"
hx-select="#deploy"
@else
data-tooltip="Click the Manage button to add a deployment script first"
@endif
>
<x-primary-button
class="flex items-center justify-between"
:active="true"
hx-disable
:disabled="(bool) !$hasDeploymentScript"
>
{{ __("Deploy") }}
<x-heroicon name="o-play-circle" class="ml-1 h-5 w-5" />
</x-primary-button>
</form>
</div>

@ -1,58 +0,0 @@
<div x-data="">
<x-modal name="deployment-script" max-width="3xl">
<form
id="deployment-script-form"
hx-post="{{ route("servers.sites.application.deployment-script", ["server" => $server, "site" => $site]) }}"
hx-select="#deployment-script-form"
hx-target="#deployment-script-form"
hx-swap="outerHTML"
class="p-6"
>
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __("Deployment Script") }}
</h2>
<div class="mt-6">A bash script that will be executed when you run the deployment process.</div>
<div class="mt-6">
<x-input-label for="script" :value="__('Script')" />
@php($value = old("script", $site->deploymentScript?->content))
<x-editor id="script" name="script" lang="sh" :value="$value" />
@error("script")
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6">
<div class="flex items-center">
<x-input-label class="mr-1" :value="__('Available Variables')" />
(
<a
href="https://vitodeploy.com/sites/application.html#deployment-script"
target="_blank"
class="text-primary-500"
>
{{ __("How to use?") }}
</a>
)
</div>
<div class="mt-1 rounded-lg bg-gray-100 p-4 dark:bg-gray-700">
@foreach ($site->environmentVariables() as $key => $variable)
{{ $key }}={{ $variable }}
<br />
@endforeach
</div>
</div>
<div class="mt-6 flex items-center justify-end">
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __("Cancel") }}
</x-secondary-button>
<x-primary-button class="ml-3" hx-disable>
{{ __("Save") }}
</x-primary-button>
</div>
</form>
</x-modal>
</div>

@ -1,75 +0,0 @@
@php
$deployments = $site
->deployments()
->latest()
->paginate(10);
@endphp
<div x-data="">
<x-card-header>
<x-slot name="title">{{ __("Deployments") }}</x-slot>
</x-card-header>
<x-live id="live-deployments">
<x-table>
<x-thead>
<x-tr>
<x-th>{{ __("Commit") }}</x-th>
<x-th>{{ __("Date") }}</x-th>
<x-th>{{ __("Status") }}</x-th>
<x-th></x-th>
</x-tr>
</x-thead>
<x-tbody>
@foreach ($deployments as $deployment)
<x-tr>
<x-td class="truncate">
<a
href="{{ $deployment->commit_data["url"] ?? "#" }}"
target="_blank"
class="block max-w-[500px] truncate font-semibold text-primary-600"
>
{{ $deployment->commit_data["message"] ?? "No message" }}
</a>
</x-td>
<x-td>
<x-datetime :value="$deployment->created_at" />
</x-td>
<x-td>
<div class="inline-flex">
@include("application.partials.deployment-status", ["status" => $deployment->status])
</div>
</x-td>
<x-td>
<x-icon-button
x-on:click="$dispatch('open-modal', 'show-log')"
id="show-log-{{ $deployment->id }}"
hx-get="{{ route('servers.sites.application.deployment.log', ['server' => $server, 'site' => $site, 'deployment' => $deployment]) }}"
hx-target="#show-log-content"
hx-select="#show-log-content"
hx-swap="outerHTML"
>
<x-heroicon name="o-eye" class="h-5 w-5" />
</x-icon-button>
</x-td>
</x-tr>
@endforeach
</x-tbody>
</x-table>
</x-live>
<div class="mt-5">
{{ $deployments->withQueryString()->links() }}
</div>
<x-modal name="show-log" max-width="4xl">
<div class="p-6" id="show-log-content">
<h2 class="mb-5 text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __("View Log") }}
</h2>
<x-console-view>{{ session()->get("content") }}</x-console-view>
<div class="mt-6 flex justify-end">
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __("Close") }}
</x-secondary-button>
</div>
</div>
</x-modal>
</div>

@ -1,43 +0,0 @@
<div x-data="">
<x-modal name="update-env" max-width="3xl">
<form
id="update-env-form"
hx-post="{{ route("servers.sites.application.env", [$server, $site]) }}"
hx-swap="outerHTML"
hx-select="#update-env-form"
class="p-6"
>
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __("Update .env File") }}
</h2>
<div
class="mt-6"
hx-get="{{ route("servers.sites.application.env", [$server, $site]) }}"
hx-trigger="load"
hx-target="#env-content"
hx-select="#env-content"
hx-swap="outerHTML"
>
<x-input-label for="env" :value="__('.env')" />
<div id="env-content">
@php($envValue = old("env", session()->get("env") ?? "Loading..."))
<x-editor id="env" name="env" lang="env" :value="$envValue" />
</div>
@error("env")
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6 flex items-center justify-end">
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __("Cancel") }}
</x-secondary-button>
<x-primary-button class="ml-3" hx-disable>
{{ __("Save") }}
</x-primary-button>
</div>
</form>
</x-modal>
</div>

@ -1 +0,0 @@
@include("application.php-app")

@ -1,11 +0,0 @@
@if ($status == \App\Enums\DeploymentStatus::DEPLOYING)
<x-status status="warning">{{ $status }}</x-status>
@endif
@if ($status == \App\Enums\DeploymentStatus::FINISHED)
<x-status status="success">{{ $status }}</x-status>
@endif
@if ($status == \App\Enums\DeploymentStatus::FAILED)
<x-status status="danger">{{ $status }}</x-status>
@endif

@ -1,57 +0,0 @@
<div>
<x-card-header>
<x-slot name="title">{{ __("Application") }}</x-slot>
<x-slot name="description">
{{ __("Here you can manage your application") }}
</x-slot>
<x-slot name="aside">
<div class="flex flex-col items-end lg:flex-row lg:items-center">
<div class="mb-2 lg:mb-0 lg:mr-2">
@include("application.deploy")
</div>
@if ($site->source_control_id)
<div class="mb-2 lg:mb-0 lg:mr-2">
@include("application.auto-deployment")
</div>
@endif
<x-dropdown>
<x-slot name="trigger">
<x-secondary-button>
{{ __("Manage") }}
<x-heroicon name="o-chevron-down" class="ml-1 h-4 w-4" />
</x-secondary-button>
</x-slot>
<x-slot name="content">
@if ($site->source_control_id)
<x-dropdown-link
class="cursor-pointer"
x-on:click="$dispatch('open-modal', 'change-branch')"
>
{{ __("Branch") }}
</x-dropdown-link>
@endif
<x-dropdown-link
class="cursor-pointer"
x-on:click="$dispatch('open-modal', 'deployment-script')"
>
{{ __("Deployment Script") }}
</x-dropdown-link>
<x-dropdown-link class="cursor-pointer" x-on:click="$dispatch('open-modal', 'update-env')">
{{ __(".env") }}
</x-dropdown-link>
</x-slot>
</x-dropdown>
@if ($site->source_control_id)
@include("application.change-branch")
@endif
@include("application.deployment-script")
@include("application.env")
</div>
</x-slot>
</x-card-header>
@include("application.deployments-list")
</div>

@ -1 +0,0 @@
@include("application.php-app")

@ -1,6 +0,0 @@
<div>
<x-simple-card class="flex items-center justify-between">
<span>PHPMyAdmin is installed and ready to use!</span>
<x-secondary-button :href="$site->getUrl()" target="_blank">Open</x-secondary-button>
</x-simple-card>
</div>

@ -1,10 +0,0 @@
<div>
<x-simple-card class="flex items-center justify-between">
<span>
{{ __("Your Wordpress site is installed and ready to use! ") }}
</span>
<x-secondary-button :href="$site->getUrl()" target="_blank">
{{ __("Open Website") }}
</x-secondary-button>
</x-simple-card>
</div>

@ -1,31 +0,0 @@
<x-guest-layout>
<div class="mb-4 text-sm text-gray-600 dark:text-gray-400">
{{ __("This is a secure area of the application. Please confirm your password before continuing.") }}
</div>
<form method="POST" action="{{ route("password.confirm") }}">
@csrf
<!-- Password -->
<div>
<x-input-label for="password" :value="__('Password')" />
<x-text-input
id="password"
class="mt-1 block w-full"
type="password"
name="password"
required
autocomplete="current-password"
/>
<x-input-error :messages="$errors->get('password')" class="mt-2" />
</div>
<div class="mt-4 flex justify-end">
<x-primary-button>
{{ __("Confirm") }}
</x-primary-button>
</div>
</form>
</x-guest-layout>

@ -1,33 +0,0 @@
<x-guest-layout>
<div class="mb-4 text-sm text-gray-600 dark:text-gray-400">
{{ __("Forgot your password? No problem. Just let us know your email address and we will email you a password reset link that will allow you to choose a new one.") }}
</div>
<!-- Session Status -->
<x-auth-session-status class="mb-4" :status="session('status')" />
<form method="POST" action="{{ route("password.email") }}">
@csrf
<!-- Email Address -->
<div>
<x-input-label for="email" :value="__('Email')" />
<x-text-input
id="email"
class="mt-1 block w-full"
type="email"
name="email"
:value="old('email')"
required
autofocus
/>
<x-input-error :messages="$errors->get('email')" class="mt-2" />
</div>
<div class="mt-4 flex items-center justify-end">
<x-primary-button>
{{ __("Email Password Reset Link") }}
</x-primary-button>
</div>
</form>
</x-guest-layout>

@ -1,71 +0,0 @@
<x-guest-layout>
<!-- Session Status -->
<x-auth-session-status class="mb-4" :status="session('status')" />
<form method="POST" action="{{ route("login") }}">
@csrf
<div>
<!-- Email Address -->
<div>
<x-input-label for="email" :value="__('Email')" />
<x-text-input
id="email"
class="mt-1 block w-full"
type="email"
name="email"
:value="old('email')"
required
autofocus
autocomplete="username"
/>
<x-input-error :messages="$errors->get('email')" class="mt-2" />
</div>
<!-- Password -->
<div class="mt-4">
<x-input-label for="password" :value="__('Password')" />
<x-text-input
id="password"
class="mt-1 block w-full"
type="password"
name="password"
required
autocomplete="current-password"
/>
<x-input-error :messages="$errors->get('password')" class="mt-2" />
</div>
<div class="flex items-center justify-between">
<!-- Remember Me -->
<div class="mt-4 block">
<label for="remember_me" class="inline-flex items-center">
<input
id="remember_me"
type="checkbox"
class="rounded border-gray-300 text-indigo-600 shadow-sm focus:ring-indigo-500 dark:border-gray-700 dark:bg-gray-900 dark:focus:ring-indigo-600 dark:focus:ring-offset-gray-800"
name="remember"
/>
<span class="ml-2 text-sm text-gray-600 dark:text-gray-400">
{{ __("Remember me") }}
</span>
</label>
</div>
</div>
<div class="mt-4 flex items-center justify-end">
@if (Route::has("password.request"))
<a
class="rounded-md text-sm text-gray-600 underline hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:text-gray-400 dark:hover:text-gray-100 dark:focus:ring-offset-gray-800"
href="{{ route("password.request") }}"
>
{{ __("Forgot your password?") }}
</a>
@endif
<x-primary-button class="ml-3">
{{ __("Log in") }}
</x-primary-button>
</div>
</div>
</form>
</x-guest-layout>

@ -1,60 +0,0 @@
<x-guest-layout>
<form method="POST" action="{{ route("password.update") }}">
@csrf
<!-- Password Reset Token -->
<input type="hidden" name="token" value="{{ $token }}" />
<!-- Email Address -->
<div>
<x-input-label for="email" :value="__('Email')" />
<x-text-input
id="email"
class="mt-1 block w-full"
type="email"
name="email"
:value="old('email', $email)"
required
autofocus
autocomplete="username"
/>
<x-input-error :messages="$errors->get('email')" class="mt-2" />
</div>
<!-- Password -->
<div class="mt-4">
<x-input-label for="password" :value="__('Password')" />
<x-text-input
id="password"
class="mt-1 block w-full"
type="password"
name="password"
required
autocomplete="new-password"
/>
<x-input-error :messages="$errors->get('password')" class="mt-2" />
</div>
<!-- Confirm Password -->
<div class="mt-4">
<x-input-label for="password_confirmation" :value="__('Confirm Password')" />
<x-text-input
id="password_confirmation"
class="mt-1 block w-full"
type="password"
name="password_confirmation"
required
autocomplete="new-password"
/>
<x-input-error :messages="$errors->get('password_confirmation')" class="mt-2" />
</div>
<div class="mt-4 flex items-center justify-end">
<x-primary-button>
{{ __("Reset Password") }}
</x-primary-button>
</div>
</form>
</x-guest-layout>

@ -1,66 +0,0 @@
<x-guest-layout>
<div x-data="{recover: @if($errors->has('recovery_code')) true @else false @endif}">
<div x-show="recover">
<form method="POST">
@csrf
<div class="mb-4 text-sm text-gray-600 dark:text-gray-400">
{{ __("Please enter your recovery code") }}
</div>
<div>
<x-input-label for="recovery_code" :value="__('Recovery Code')" />
<x-text-input
id="recovery_code"
class="mt-1 block w-full"
type="text"
name="recovery_code"
required
autofocus
autocomplete="recovery_code"
/>
<x-input-error :messages="$errors->get('recovery_code')" class="mt-2" />
</div>
<div class="mt-4 flex items-center justify-end">
<x-secondary-button class="mr-2" x-on:click="recover = false">
{{ __("Login") }}
</x-secondary-button>
<x-primary-button type="submit">
{{ __("Recover") }}
</x-primary-button>
</div>
</form>
</div>
<div x-show="!recover">
<form method="POST">
@csrf
<div class="mb-4 text-sm text-gray-600 dark:text-gray-400">
{{ __("Please confirm access to your account by entering the authentication code provided by your authenticator application.") }}
</div>
<div>
<x-input-label for="code" :value="__('Code')" />
<x-text-input
id="code"
class="mt-1 block w-full"
type="text"
name="code"
required
autofocus
autocomplete="code"
/>
<x-input-error :messages="$errors->get('code')" class="mt-2" />
</div>
<div class="mt-4 flex items-center justify-end">
<x-secondary-button class="mr-2" x-on:click="recover = true">
{{ __("Recover") }}
</x-secondary-button>
<x-primary-button type="submit">
{{ __("Login") }}
</x-primary-button>
</div>
</form>
</div>
</div>
</x-guest-layout>

@ -1,5 +0,0 @@
<div
class="rounded-lg border-2 border-red-500 border-opacity-50 bg-red-50 p-4 text-red-500 dark:bg-red-500 dark:bg-opacity-10 dark:text-white"
>
{{ $slot }}
</div>

@ -1,5 +0,0 @@
<div
class="rounded-lg border-2 border-green-500 border-opacity-50 bg-green-50 p-4 text-green-500 dark:bg-green-500 dark:bg-opacity-10 dark:text-white"
>
{{ $slot }}
</div>

@ -1,5 +0,0 @@
<div
class="rounded-lg border border-l-4 border-yellow-500 bg-yellow-100 px-4 py-3 text-yellow-700 dark:bg-yellow-500 dark:bg-opacity-10 dark:text-yellow-500"
>
{{ $slot }}
</div>

@ -1,5 +0,0 @@
<div
class="rounded-lg border-2 border-gray-500 border-opacity-50 bg-gray-50 p-4 text-gray-500 dark:bg-gray-500 dark:bg-opacity-10 dark:text-white"
>
{{ $slot }}
</div>

File diff suppressed because one or more lines are too long

@ -1,9 +0,0 @@
@props([
"status",
])
@if ($status)
<div {{ $attributes->merge(["class" => "font-medium text-sm text-green-600 dark:text-green-400"]) }}>
{{ $status }}
</div>
@endif

@ -1,64 +0,0 @@
@props([
"id",
"name",
"placeholder" => "Search...",
"items" => [],
"maxResults" => 5,
"value" => "",
])
<script>
window['items_' + @js($id)] = @json($items);
</script>
<div
x-data="{
q: @js($value),
items: window['items_' + @js($id)],
resultItems: window['items_' + @js($id)],
maxResults: @js($maxResults),
init() {
this.search()
},
search() {
if (! this.q) {
this.resultItems = this.items.slice(0, this.maxResults)
return
}
this.resultItems = this.items
.filter((item) => item.toLowerCase().includes(this.q.toLowerCase()))
.slice(0, this.maxResults)
},
}"
>
<input type="hidden" name="{{ $name }}" x-ref="input" x-model="q" />
<x-dropdown width="full" :hide-if-empty="true">
<x-slot name="trigger">
<x-text-input
id="$id . '-q"
x-model="q"
type="text"
class="mt-1 w-full"
:placeholder="$placeholder"
autocomplete="off"
x-on:input.debounce.100ms="search"
/>
</x-slot>
<x-slot name="content">
<div
id="{{ $id }}-items-list"
x-bind:class="
resultItems.length > 0
? 'py-1 border border-gray-200 dark:border-gray-600 rounded-md'
: ''
"
>
<template x-for="item in resultItems">
<x-dropdown-link class="cursor-pointer" x-on:click="q = item">
<span x-text="item"></span>
</x-dropdown-link>
</template>
</div>
</x-slot>
</x-dropdown>
</div>

@ -1,21 +0,0 @@
<div class="@if(isset($aside)) flex justify-between @endif mb-6">
<div>
@if (isset($title))
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-300">
{{ $title }}
</h3>
@endif
@if (isset($description))
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
{{ $description }}
</p>
@endif
</div>
<div>
@if (isset($aside))
{{ $aside }}
@endif
</div>
</div>

@ -1,31 +0,0 @@
<div {{ $attributes->merge(["class" => "mx-auto mb-10"]) }}>
<x-card-header>
@if (isset($title))
<x-slot name="title">{{ $title }}</x-slot>
@endif
@if (isset($description))
<x-slot name="description">{{ $description }}</x-slot>
@endif
@if (isset($aside))
<x-slot name="aside">{{ $aside }}</x-slot>
@endif
</x-card-header>
<div class="mt-5">
<div
class="{{ isset($actions) ? "sm:rounded-tl-md sm:rounded-tr-md" : "sm:rounded-md" }} border border-gray-200 bg-white px-4 py-5 dark:border-gray-700 dark:bg-gray-800 sm:p-6"
>
{{ $slot }}
</div>
@if (isset($actions))
<div
class="flex items-center justify-end border border-b border-l border-r border-gray-200 border-t-transparent bg-gray-50 px-4 py-3 text-right dark:border-gray-700 dark:border-t-transparent dark:bg-gray-800 dark:bg-opacity-70 sm:rounded-bl-md sm:rounded-br-md sm:px-6"
>
{{ $actions }}
</div>
@endif
</div>
</div>

Some files were not shown because too many files have changed in this diff Show More