This commit is contained in:
Saeed Vaziry
2023-07-02 12:47:50 +02:00
commit 5c72f12490
825 changed files with 41659 additions and 0 deletions

View File

@ -0,0 +1,32 @@
<div x-data="">
<x-secondary-button x-on:click="$dispatch('open-modal', 'change-branch')">{{ __("Branch") }}</x-secondary-button>
<x-modal name="change-branch">
<form wire:submit.prevent="change" 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 wire:model.defer="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">
@if (session('status') === 'updating-branch')
<p class="mr-2">{{ __('Updating branch...') }}</p>
@endif
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __('Cancel') }}
</x-secondary-button>
<x-primary-button class="ml-3">
{{ __('Save') }}
</x-primary-button>
</div>
</form>
</x-modal>
</div>

View File

@ -0,0 +1,5 @@
<div>
@if($site->deploymentScript && $site->deploymentScript->content)
<x-primary-button wire:click="deploy" wire:loading.attr="disabled">{{ __("Deploy") }}</x-primary-button>
@endif
</div>

View File

@ -0,0 +1,32 @@
<div x-data="">
<x-secondary-button x-on:click="$dispatch('open-modal', 'deployment-script')">{{ __("Deployment Script") }}</x-secondary-button>
<x-modal name="deployment-script">
<form wire:submit.prevent="save" class="p-6">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('Deployment Script') }}
</h2>
<div class="mt-6">
<x-input-label for="script" :value="__('Script')" />
<x-textarea wire:model.defer="script" rows="10" id="script" name="script" class="mt-1 w-full" />
@error('script')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6 flex items-center justify-end">
@if (session('status') === 'script-updated')
<p class="mr-2">{{ __('Saved') }}</p>
@endif
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __('Cancel') }}
</x-secondary-button>
<x-primary-button class="ml-3">
{{ __('Save') }}
</x-primary-button>
</div>
</form>
</x-modal>
</div>

View File

@ -0,0 +1,51 @@
<div x-data="">
<x-card-header>
<x-slot name="title">{{ __("Deployments") }}</x-slot>
</x-card-header>
<x-table>
<tr>
<x-th>{{ __("Commit") }}</x-th>
<x-th>{{ __("Date") }}</x-th>
<x-th>{{ __("Status") }}</x-th>
<x-th></x-th>
</tr>
@foreach($deployments as $deployment)
<tr>
<x-td>
<a href="{{ $deployment->commit_data['url'] }}" target="_blank" class="text-primary-600 font-semibold">{{ $deployment->commit_data['message'] }}</a>
</x-td>
<x-td>
<x-datetime :value="$deployment->created_at" />
</x-td>
<x-td>
<div class="inline-flex">
@include('livewire.application.partials.deployment-status', ['status' => $deployment->status])
</div>
</x-td>
<x-td>
@if($deployment->status != \App\Enums\DeploymentStatus::DEPLOYING)
<x-icon-button wire:click="showLog({{ $deployment->id }})" wire:loading.attr="disabled">
<x-heroicon-o-eye class="w-6 h-6" />
</x-icon-button>
@endif
</x-td>
</tr>
@endforeach
</x-table>
<div class="mt-5">
{{ $deployments->withQueryString()->links() }}
</div>
<x-modal name="show-log" max-width="4xl">
<div class="p-6">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-5">
{{ __('View Log') }}
</h2>
<x-console-view>{{ $logContent }}</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>

View File

@ -0,0 +1,21 @@
<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 items-center">
<div class="mr-2">
<livewire:application.change-branch :site="$site" />
</div>
<div class="mr-2">
<livewire:application.deployment-script :site="$site" />
</div>
<div>
<livewire:application.deploy :site="$site" />
</div>
</div>
</x-slot>
</x-card-header>
<livewire:application.deployments-list :site="$site" />
</div>

View File

@ -0,0 +1,9 @@
@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

View File

@ -0,0 +1,3 @@
<div>
</div>

View File

@ -0,0 +1,3 @@
<div>
</div>

View File

@ -0,0 +1,69 @@
<div>
<x-primary-button x-data="" x-on:click.prevent="$dispatch('open-modal', 'create-cronjob')">
{{ __('Create Cronjob') }}
</x-primary-button>
<x-modal name="create-cronjob">
<form wire:submit.prevent="create" class="p-6">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('Create Cronjob') }}
</h2>
<div class="mt-6">
<x-input-label for="command" :value="__('Command')" />
<x-text-input wire:model.defer="command" id="command" name="command" type="text" class="mt-1 w-full" />
@error('command')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6">
<x-input-label for="user" :value="__('User')" />
<x-select-input wire:model.defer="user" id="user" name="user" class="mt-1 w-full">
<option value="" selected disabled>{{ __("Select") }}</option>
<option value="root" @if($user === 'root') selected @endif>root</option>
<option value="{{ $server->ssh_user }}" @if($user === $server->ssh_user) selected @endif>{{ $server->ssh_user }}</option>
</x-select-input>
@error('user')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6">
<x-input-label for="frequency" :value="__('Frequency')" />
<x-select-input wire:model="frequency" id="frequency" name="frequency" class="mt-1 w-full">
<option value="" selected disabled>{{ __("Select") }}</option>
<option value="* * * * *" @if($frequency === '* * * * *') selected @endif>{{ __("Every minute") }}</option>
<option value="0 * * * *" @if($frequency === '0 * * * *') selected @endif>{{ __("Hourly") }}</option>
<option value="0 0 * * *" @if($frequency === '0 0 * * *') selected @endif>{{ __("Daily") }}</option>
<option value="0 0 * * 0" @if($frequency === '0 0 * * 0') selected @endif>{{ __("Weekly") }}</option>
<option value="0 0 1 * *" @if($frequency === '0 0 1 * *') selected @endif>{{ __("Monthly") }}</option>
<option value="custom">{{ __("Custom") }}</option>
</x-select-input>
@error('frequency')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
@if($frequency === 'custom')
<div class="mt-6">
<x-input-label for="custom" :value="__('Custom Frequency')" />
<x-text-input wire:model.defer="custom" id="custom" name="custom" type="text" class="mt-1 w-full" placeholder="* * * * *" />
@error('custom')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
@endif
<div class="mt-6 flex justify-end">
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __('Cancel') }}
</x-secondary-button>
<x-primary-button class="ml-3" @created.window="$dispatch('close')">
{{ __('Create') }}
</x-primary-button>
</div>
</form>
</x-modal>
</div>

View File

@ -0,0 +1,45 @@
<div>
<x-card-header>
<x-slot name="title">{{ __("Cronjobs") }}</x-slot>
<x-slot name="description">{{ __("Your server's Cronjobs are here. You can manage them") }}</x-slot>
<x-slot name="aside">
<livewire:cronjobs.create-cronjob :server="$server" />
</x-slot>
</x-card-header>
<div x-data="" class="space-y-3">
@if(count($cronjobs) > 0)
@foreach($cronjobs as $cronjob)
<x-item-card>
<div class="flex flex-grow flex-col items-start justify-center">
<span class="mb-1 flex items-center lowercase text-red-600">
{{ $cronjob->command }}
</span>
<span class="text-sm text-gray-400">
{{ $cronjob->frequency_label }}
</span>
</div>
<div class="flex items-center">
@include('livewire.cronjobs.partials.status', ['status' => $cronjob->status])
<div class="inline">
<x-icon-button x-on:click="$wire.deleteId = '{{ $cronjob->id }}'; $dispatch('open-modal', 'delete-cronjob')">
<x-heroicon-o-trash class="w-4 h-4" />
</x-icon-button>
</div>
</div>
</x-item-card>
@endforeach
<x-confirm-modal
name="delete-cronjob"
:title="__('Confirm')"
:description="__('Are you sure that you want to delete this cronjob?')"
method="delete"
/>
@else
<x-simple-card>
<div class="text-center">
{{ __("You haven't connected to any server providers yet!") }}
</div>
</x-simple-card>
@endif
</div>
</div>

View File

@ -0,0 +1,9 @@
@if($status == \App\Enums\CronjobStatus::READY)
<x-status status="success">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\CronjobStatus::CREATING)
<x-status status="warning">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\CronjobStatus::DELETING)
<x-status status="danger">{{ $status }}</x-status>
@endif

View File

@ -0,0 +1,46 @@
<div x-data="">
<x-card-header>
<x-slot name="title">{{ __("Databases") }}</x-slot>
<x-slot name="description">{{ __("You can see and manage your databases here") }}</x-slot>
<x-slot name="aside">
<div>
<x-primary-button x-data="" x-on:click.prevent="$dispatch('open-modal', 'create-database')">
{{ __('Create Database') }}
</x-primary-button>
@include('livewire.databases.partials.create-database-modal')
</div>
</x-slot>
</x-card-header>
@if(count($databases) > 0)
<x-table>
<tr>
<x-td>{{ __("Name") }}</x-td>
<x-td>{{ __("Created") }}</x-td>
<x-td>{{ __("Status") }}</x-td>
<x-td></x-td>
</tr>
@foreach($databases as $database)
<tr>
<x-td>{{ $database->name }}</x-td>
<x-td>
<x-datetime :value="$database->created_at"/>
</x-td>
<x-td>
<div class="inline-flex">
@include('livewire.databases.partials.database-status', ['status' => $database->status])
</div>
</x-td>
<x-td class="flex w-full justify-end">
<x-icon-button x-on:click="$wire.deleteId = '{{ $database->id }}'; $dispatch('open-modal', 'delete-database')">
<x-heroicon-o-trash class="w-4 h-4" />
</x-icon-button>
</x-td>
</tr>
@endforeach
</x-table>
@include('livewire.databases.partials.delete-database-modal')
@else
<x-simple-card class="text-center">{{ __("You don't have any databases yet") }}</x-simple-card>
@endif
</div>

View File

@ -0,0 +1,56 @@
<div x-data="">
<x-card-header>
<x-slot name="title">{{ __("Database Users") }}</x-slot>
<x-slot name="description">{{ __("You can see and manage your database users here") }}</x-slot>
<x-slot name="aside">
<div>
<x-primary-button x-data="" x-on:click.prevent="$dispatch('open-modal', 'create-database-user')">
{{ __('Create Database User') }}
</x-primary-button>
@include('livewire.databases.partials.create-database-user-modal')
</div>
</x-slot>
</x-card-header>
@if(count($databaseUsers) > 0)
<x-table>
<tr>
<x-td>{{ __("Username") }}</x-td>
<x-td>{{ __("Created") }}</x-td>
<x-td>{{ __("Linked Databases") }}</x-td>
<x-td>{{ __("Status") }}</x-td>
<x-td></x-td>
</tr>
@foreach($databaseUsers as $databaseUser)
<tr>
<x-td>{{ $databaseUser->username }}</x-td>
<x-td>
<x-datetime :value="$databaseUser->created_at" />
</x-td>
<x-td>[{{ $databaseUser->databases ? implode(', ', $databaseUser->databases) : '-' }}]</x-td>
<x-td>
<div class="inline-flex">
@include('livewire.databases.partials.database-user-status', ['status' => $databaseUser->status])
</div>
</x-td>
<x-td class="flex w-full justify-end">
<x-icon-button x-on:click="$wire.deleteId = '{{ $databaseUser->id }}'; $dispatch('open-modal', 'delete-database-user')">
<x-heroicon-o-trash class="w-4 h-4" />
</x-icon-button>
<x-icon-button wire:click="viewPassword({{ $databaseUser->id }})">
<x-heroicon-o-eye class="w-4 h-4" />
</x-icon-button>
<x-icon-button wire:click="showLink({{ $databaseUser->id }})">
<x-heroicon-o-link class="w-4 h-4" />
</x-icon-button>
</x-td>
</tr>
@endforeach
</x-table>
@include('livewire.databases.partials.delete-database-user-modal')
@include('livewire.databases.partials.database-user-password-modal')
@include('livewire.databases.partials.link-database-user-modal')
@else
<x-simple-card class="text-center">{{ __("You don't have any database users yet") }}</x-simple-card>
@endif
</div>

View File

@ -0,0 +1,68 @@
<x-modal name="create-database">
<form wire:submit.prevent="create" class="p-6" x-data="{user: false, remote: false}">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('Create Database') }}
</h2>
<div class="mt-6">
<x-input-label for="name" :value="__('Name')" />
<x-text-input wire:model.defer="name" id="name" name="name" type="text" class="mt-1 w-full" />
@error('name')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6">
<label for="create_user" class="inline-flex items-center">
<input id="create_user" wire:model.defer="user" type="checkbox" x-model="user" class="rounded dark:bg-gray-900 border-gray-300 dark:border-gray-700 text-indigo-600 shadow-sm focus:ring-indigo-500 dark:focus:ring-indigo-600 dark:focus:ring-offset-gray-800" name="create_user">
<span class="ml-2 text-sm text-gray-600 dark:text-gray-400">{{ __('Create a user for this database') }}</span>
</label>
</div>
<div x-show="user">
<div class="mt-6">
<x-input-label for="db-username" :value="__('Username')" />
<x-text-input wire:model.defer="username" id="db-username" name="username" type="text" class="mt-1 w-full" />
@error('username')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6">
<x-input-label for="db-password" :value="__('Password')" />
<x-text-input wire:model.defer="password" id="db-password" name="password" type="text" class="mt-1 w-full" />
@error('password')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6">
<label for="db-remote" class="inline-flex items-center">
<input id="db-remote" wire:model="remote" type="checkbox" x-model="remote" class="rounded dark:bg-gray-900 border-gray-300 dark:border-gray-700 text-indigo-600 shadow-sm focus:ring-indigo-500 dark:focus:ring-indigo-600 dark:focus:ring-offset-gray-800" name="remote">
<span class="ml-2 text-sm text-gray-600 dark:text-gray-400">{{ __('Enable remote access') }}</span>
</label>
</div>
<div x-show="remote">
<div class="mt-6">
<x-input-label for="db-host" :value="__('Host')" />
<x-text-input wire:model.defer="host" id="db-host" name="host" type="text" class="mt-1 w-full" />
<x-input-label for="db-host" :value="__('You might also need to open the database port in Firewall')" class="mt-1"/>
@error('host')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
</div>
</div>
<div class="mt-6 flex justify-end">
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __('Cancel') }}
</x-secondary-button>
<x-primary-button class="ml-3" @database-created.window="$dispatch('close')">
{{ __('Create') }}
</x-primary-button>
</div>
</form>
</x-modal>

View File

@ -0,0 +1,51 @@
<x-modal name="create-database-user">
<form wire:submit.prevent="create" class="p-6" x-data="{remote: false}">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('Create Database User') }}
</h2>
<div class="mt-6">
<x-input-label for="user-username" :value="__('Username')" />
<x-text-input wire:model.defer="username" id="user-username" name="username" type="text" class="mt-1 w-full" />
@error('username')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6">
<x-input-label for="user-password" :value="__('Password')" />
<x-text-input wire:model.defer="password" id="user-password" name="password" type="text" class="mt-1 w-full" />
@error('password')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6">
<label for="user-remote" class="inline-flex items-center">
<input id="user-remote" wire:model="remote" type="checkbox" x-model="remote" class="rounded dark:bg-gray-900 border-gray-300 dark:border-gray-700 text-indigo-600 shadow-sm focus:ring-indigo-500 dark:focus:ring-indigo-600 dark:focus:ring-offset-gray-800" name="remote">
<span class="ml-2 text-sm text-gray-600 dark:text-gray-400">{{ __('Enable remote access') }}</span>
</label>
</div>
<div x-show="remote">
<div class="mt-6">
<x-input-label for="user-host" :value="__('Host')" />
<x-text-input wire:model.defer="host" id="user-host" name="host" type="text" class="mt-1 w-full" />
<x-input-label for="user-host" :value="__('You might also need to open the database port in Firewall')" class="mt-1"/>
@error('host')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
</div>
<div class="mt-6 flex justify-end">
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __('Cancel') }}
</x-secondary-button>
<x-primary-button class="ml-3" @database-user-created.window="$dispatch('close')">
{{ __('Create') }}
</x-primary-button>
</div>
</form>
</x-modal>

View File

@ -0,0 +1,12 @@
@if($status == \App\Enums\DatabaseStatus::READY)
<x-status status="success">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\DatabaseStatus::CREATING)
<x-status status="warning">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\DatabaseStatus::DELETING)
<x-status status="danger">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\DatabaseStatus::FAILED)
<x-status status="danger">{{ $status }}</x-status>
@endif

View File

@ -0,0 +1,23 @@
<x-modal name="database-user-password">
<form wire:submit.prevent="create" class="p-6" x-data="{remote: false}">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('View Password') }}
</h2>
<div class="mt-6">
<x-input-label :value="__('Password')" />
<x-text-input wire:model.defer="viewPassword" type="text" class="mt-1 w-full" disabled />
</div>
<div class="mt-6 flex justify-end">
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __('Close') }}
</x-secondary-button>
<x-primary-button x-data="{ copied: false }" x-clipboard.raw="{{ $viewPassword }}" class="ml-2">
<div x-show="copied" class="flex items-center">{{ __("Copied") }}</div>
<div x-show="!copied" x-on:click="copied = true; setTimeout(() => {copied = false}, 2000)">{{ __("Copy") }}</div>
</x-primary-button>
</div>
</form>
</x-modal>

View File

@ -0,0 +1,12 @@
@if($status == \App\Enums\DatabaseUserStatus::READY)
<x-status status="success">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\DatabaseUserStatus::CREATING)
<x-status status="warning">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\DatabaseUserStatus::DELETING)
<x-status status="danger">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\DatabaseUserStatus::FAILED)
<x-status status="danger">{{ $status }}</x-status>
@endif

View File

@ -0,0 +1,6 @@
<x-confirm-modal
name="delete-database"
:title="__('Confirm')"
:description="__('Are you sure that you want to delete this database?')"
method="delete"
/>

View File

@ -0,0 +1,6 @@
<x-confirm-modal
name="delete-database-user"
:title="__('Confirm')"
:description="__('Are you sure that you want to delete this database?')"
method="delete"
/>

View File

@ -0,0 +1,28 @@
<x-modal name="link-database-user">
<form wire:submit.prevent="link" class="p-6">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('Link User to Databases') }}
</h2>
<div class="mt-6">
@foreach($databases as $database)
<div class="mb-2">
<label for="db-{{ $database->id }}" class="inline-flex items-center">
<input id="db-{{ $database->id }}" wire:model.defer="link" value="{{ $database->name }}" type="checkbox" class="rounded dark:bg-gray-900 border-gray-300 dark:border-gray-700 text-indigo-600 shadow-sm focus:ring-indigo-500 dark:focus:ring-indigo-600 dark:focus:ring-offset-gray-800" name="link">
<span class="ml-2 text-sm text-gray-600 dark:text-gray-400">{{ $database->name }}</span>
</label>
</div>
@endforeach
</div>
<div class="mt-6 flex justify-end">
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __('Close') }}
</x-secondary-button>
<x-primary-button class="ml-2" @linked.window="$dispatch('close')">
{{ __('Save') }}
</x-primary-button>
</div>
</form>
</x-modal>

View File

@ -0,0 +1,72 @@
<div>
<x-primary-button x-data="" x-on:click.prevent="$dispatch('open-modal', 'create-rule')">
{{ __('Create new Rule') }}
</x-primary-button>
<x-modal name="create-rule">
<form wire:submit.prevent="create" class="p-6">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('Create new Rule') }}
</h2>
<div class="mt-6">
<x-input-label for="type" :value="__('Rule Type')" />
<x-select-input wire:model.defer="type" id="type" name="type" class="mt-1 w-full">
<option value="allow" @if($type === 'allow') selected @endif>{{ __("Allow") }}</option>
<option value="deny" @if($type === 'deny') selected @endif>{{ __("Deny") }}</option>
</x-select-input>
@error('type')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6 grid grid-cols-1 lg:grid-cols-2 gap-3">
<div>
<x-input-label for="protocol" :value="__('Protocol')" />
<x-select-input wire:model="protocol" id="protocol" name="protocol" class="mt-1 w-full">
@foreach(config('core.firewall_protocols_port') as $key => $value)
<option value="{{ $key }}" @if($key === $protocol) selected @endif>{{ $key }}</option>
@endforeach
</x-select-input>
@error('protocol')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div>
<x-input-label for="port" :value="__('Port')" />
<x-text-input wire:model.defer="port" id="port" name="port" type="text" class="mt-1 w-full" />
@error('port')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div>
<x-input-label for="source" :value="__('Source')" />
<x-text-input wire:model.defer="source" id="source" name="source" type="text" class="mt-1 w-full" />
@error('source')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div>
<x-input-label for="mask" :value="__('Mask')" />
<x-text-input wire:model.defer="mask" id="mask" name="mask" type="text" class="mt-1 w-full" />
@error('mask')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
</div>
<div class="mt-6 flex justify-end">
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __('Cancel') }}
</x-secondary-button>
<x-primary-button class="ml-3" @created.window="$dispatch('close')">
{{ __('Create') }}
</x-primary-button>
</div>
</form>
</x-modal>
</div>

View File

@ -0,0 +1,52 @@
<div>
<x-card-header>
<x-slot name="title">{{ __("Firewall Rules") }}</x-slot>
<x-slot name="description">{{ __("Your server's firewall rules are here. You can manage them") }}</x-slot>
<x-slot name="aside">
<livewire:firewall.create-firewall-rule :server="$server" />
</x-slot>
</x-card-header>
<div x-data="" class="space-y-3">
@foreach($rules as $rule)
<x-item-card>
<div class="flex flex-grow flex-col items-start justify-center">
<span class="mb-1 flex items-center uppercase">
{{ $rule->protocol }}
<x-status :status="$rule->type == 'allow' ? 'success' : 'danger'" class="ml-1">{{ $rule->type }}</x-status>
</span>
<span class="text-sm text-gray-400">
{{ __("From") }} {{ $rule->source }}/{{ $rule->mask }} {{ __("Port") }} {{ $rule->port }}
</span>
</div>
<div class="flex items-center">
@include('livewire.firewall.partials.status', ['status' => $rule->status])
<div class="inline">
<x-icon-button x-on:click="$wire.deleteId = '{{ $rule->id }}'; $dispatch('open-modal', 'delete-rule')">
<x-heroicon-o-trash class="w-4 h-4" />
</x-icon-button>
</div>
</div>
</x-item-card>
@endforeach
<x-item-card>
<div class="flex flex-grow flex-col items-start justify-center">
<span class="mb-1 flex items-center uppercase">
{{ __("All") }}
<x-status status="danger" class="ml-1">{{ __("Deny") }}</x-status>
</span>
<span class="text-sm text-gray-400">
{{ __("From") }} 0.0.0.0/0
</span>
</div>
<div class="flex items-center">
{{ __("Default") }}
</div>
</x-item-card>
<x-confirm-modal
name="delete-rule"
:title="__('Confirm')"
:description="__('Are you sure that you want to delete this rule?')"
method="delete"
/>
</div>
</div>

View File

@ -0,0 +1,9 @@
@if($status == \App\Enums\FirewallRuleStatus::READY)
<x-status status="success">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\FirewallRuleStatus::CREATING)
<x-status status="warning">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\FirewallRuleStatus::DELETING)
<x-status status="danger">{{ $status }}</x-status>
@endif

View File

@ -0,0 +1,66 @@
<div>
<x-primary-button x-data="" x-on:click.prevent="$dispatch('open-modal', 'add-channel')">
{{ __('Add new Channel') }}
</x-primary-button>
<x-modal name="add-channel">
<form wire:submit.prevent="add" class="p-6">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('Add new Channel') }}
</h2>
<div class="mt-6">
<x-input-label for="provider" value="Provider" />
<x-select-input wire:model="provider" id="provider" name="provider" class="mt-1 w-full">
<option value="" selected disabled>{{ __("Select") }}</option>
@foreach(config('core.notification_channels_providers') as $p)
@if($p !== 'custom')
<option value="{{ $p }}" @if($provider === $p) selected @endif>{{ $p }}</option>
@endif
@endforeach
</x-select-input>
@error('provider')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6">
<x-input-label for="label" :value="__('Label')" />
<x-text-input wire:model.defer="label" id="label" name="label" type="text" class="mt-1 w-full" />
@error('label')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
@if($provider == \App\Enums\NotificationChannel::EMAIL)
<div class="mt-6">
<x-input-label for="email" :value="__('Email')" />
<x-text-input wire:model.defer="email" id="email" name="email" type="text" class="mt-1 w-full" />
@error('email')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
@endif
@if(in_array($provider, [\App\Enums\NotificationChannel::SLACK, \App\Enums\NotificationChannel::DISCORD]))
<div class="mt-6">
<x-input-label for="webhook_url" :value="__('Webhook URL')" />
<x-text-input wire:model.defer="webhook_url" id="webhook_url" name="webhook_url" type="text" class="mt-1 w-full" />
@error('webhook_url')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
@endif
<div class="mt-6 flex justify-end">
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __('Cancel') }}
</x-secondary-button>
<x-primary-button class="ml-3" @added.window="$dispatch('close')">
{{ __('Add') }}
</x-primary-button>
</div>
</form>
</x-modal>
</div>

View File

@ -0,0 +1,45 @@
<div>
<x-card-header>
<x-slot name="title">{{ __("Notification Channels") }}</x-slot>
<x-slot name="description">{{ __("Add or modify your notification channels") }}</x-slot>
<x-slot name="aside">
<livewire:notification-channels.add-channel />
</x-slot>
</x-card-header>
<div x-data="" class="space-y-3">
@if(count($channels) > 0)
@foreach($channels as $channel)
<x-item-card>
<div class="flex-none">
<img src="{{ asset('static/images/' . $channel->provider . '.svg') }}" class="h-10 w-10" alt="">
</div>
<div class="ml-3 flex flex-grow flex-col items-start justify-center">
<span class="mb-1">{{ $channel->label }}</span>
<span class="text-sm text-gray-400">
<x-datetime :value="$channel->created_at" />
</span>
</div>
<div class="flex items-center">
<div class="inline">
<x-icon-button x-on:click="$wire.deleteId = '{{ $channel->id }}'; $dispatch('open-modal', 'delete-channel')">
<x-heroicon-o-trash class="w-4 h-4" />
</x-icon-button>
</div>
</div>
</x-item-card>
@endforeach
<x-confirm-modal
name="delete-channel"
:title="__('Confirm')"
:description="__('Are you sure that you want to delete this channel?')"
method="delete"
/>
@else
<x-simple-card>
<div class="text-center">
{{ __("You haven't connected to any channels yet!") }}
</div>
</x-simple-card>
@endif
</div>
</div>

View File

@ -0,0 +1,43 @@
<div>
@if ($paginator->hasPages())
<nav role="navigation" aria-label="Pagination Navigation" class="flex justify-between">
<span>
{{-- Previous Page Link --}}
@if ($paginator->onFirstPage())
<x-secondary-button href="javascript:" disabled>
{!! __('pagination.previous') !!}
</x-secondary-button>
@else
@if(method_exists($paginator,'getCursorName'))
<x-secondary-button type="button" dusk="previousPage" wire:click="setPage('{{$paginator->previousCursor()->encode()}}','{{ $paginator->getCursorName() }}')" wire:loading.attr="disabled">
{!! __('pagination.previous') !!}
</x-secondary-button>
@else
<x-secondary-button type="button" wire:click="previousPage('{{ $paginator->getPageName() }}')" wire:loading.attr="disabled" dusk="previousPage{{ $paginator->getPageName() == 'page' ? '' : '.' . $paginator->getPageName() }}">
{!! __('pagination.previous') !!}
</x-secondary-button>
@endif
@endif
</span>
<span>
{{-- Next Page Link --}}
@if ($paginator->hasMorePages())
@if(method_exists($paginator,'getCursorName'))
<x-secondary-button type="button" dusk="nextPage" wire:click="setPage('{{$paginator->nextCursor()->encode()}}','{{ $paginator->getCursorName() }}')" wire:loading.attr="disabled">
{!! __('pagination.next') !!}
</x-secondary-button>
@else
<x-secondary-button type="button" wire:click="nextPage('{{ $paginator->getPageName() }}')" wire:loading.attr="disabled" dusk="nextPage{{ $paginator->getPageName() == 'page' ? '' : '.' . $paginator->getPageName() }}">
{!! __('pagination.next') !!}
</x-secondary-button>
@endif
@else
<x-secondary-button href="javascript:" disabled>
{!! __('pagination.next') !!}
</x-secondary-button>
@endif
</span>
</nav>
@endif
</div>

View File

@ -0,0 +1,41 @@
<div>
<x-card-header>
<x-slot name="title">{{ __("Default PHP Cli") }}</x-slot>
<x-slot name="description">{{ __("You can see and manage your PHP installations") }}</x-slot>
</x-card-header>
<a class="block">
<x-item-card>
<div class="flex items-start justify-center">
<span class="mr-2">PHP {{ $defaultPHP->version }}</span>
@include('livewire.services.partials.status', ['status' => $defaultPHP->status])
</div>
<div class="flex items-center">
<div class="inline">
<x-dropdown>
<x-slot name="trigger">
<x-secondary-button>
{{ __("Change") }}
<x-heroicon-m-chevron-down class="w-4 ml-1" />
</x-secondary-button>
</x-slot>
<x-slot name="content">
@foreach($phps as $php)
@if($php->version != $defaultPHP->version)
<x-dropdown-link class="cursor-pointer" wire:click="change('{{ $php->version }}')">
PHP {{ $php->version }}
</x-dropdown-link>
@endif
@endforeach
@if(count($phps) == 1)
<x-dropdown-link>
{{ __("No other versions") }}
</x-dropdown-link>
@endif
</x-slot>
</x-dropdown>
</div>
</div>
</x-item-card>
</a>
</div>

View File

@ -0,0 +1,61 @@
<div>
<x-card-header>
<x-slot name="title">{{ __("Installed PHPs") }}</x-slot>
<x-slot name="description">{{ __("You can see and manage your PHP installations") }}</x-slot>
<x-slot name="aside">
@include('livewire.php.partials.install-new-php')
</x-slot>
</x-card-header>
@if(count($phps) > 0)
<div class="space-y-3">
@foreach($phps as $php)
<a class="block">
<x-item-card>
<div class="flex items-start justify-center">
<span class="mr-2">PHP {{ $php->version }}</span>
@include('livewire.services.partials.status', ['status' => $php->status])
</div>
<div class="flex items-center">
<div class="inline">
<x-dropdown>
<x-slot name="trigger">
<x-secondary-button>
{{ __("Actions") }}
<x-heroicon-m-chevron-down class="w-4 ml-1" />
</x-secondary-button>
</x-slot>
<x-slot name="content">
{{--<x-dropdown-link class="cursor-pointer">--}}
{{-- {{ __("Install Extension") }}--}}
{{--</x-dropdown-link>--}}
<x-dropdown-link class="cursor-pointer" x-on:click="$dispatch('open-modal', 'update-php-ini')" wire:click="loadIni({{ $php->id }})">
{{ __("Edit php.ini") }}
</x-dropdown-link>
<x-dropdown-link class="cursor-pointer" wire:click="restart({{ $php->id }})">
{{ __("Restart FPM") }}
</x-dropdown-link>
<x-dropdown-link class="cursor-pointer" x-on:click="$wire.uninstallId = {{ $php->id }}; $dispatch('open-modal', 'uninstall-php')">
<span class="text-red-600">
{{ __("Uninstall") }}
</span>
</x-dropdown-link>
</x-slot>
</x-dropdown>
</div>
</div>
</x-item-card>
</a>
@endforeach
</div>
@include('livewire.php.partials.uninstall-php')
@include('livewire.php.partials.update-php-ini')
@else
<x-simple-card>
<div class="text-center">
{{ __("You don't have any PHP version installed!") }}
</div>
</x-simple-card>
@endif
</div>

View File

@ -0,0 +1,18 @@
<x-dropdown>
<x-slot name="trigger">
<x-primary-button>
{{ __("Install") }}
<x-heroicon-m-chevron-down class="w-4 ml-1" />
</x-primary-button>
</x-slot>
<x-slot name="content">
@foreach(config('core.php_versions') as $php)
@if(!$phps->whereIn('version', $php)->first() && $php !== 'none')
<x-dropdown-link class="cursor-pointer" wire:click="install('{{ $php }}')">
PHP {{ $php }}
</x-dropdown-link>
@endif
@endforeach
</x-slot>
</x-dropdown>

View File

@ -0,0 +1,6 @@
<x-confirm-modal
name="uninstall-php"
:title="__('Uninstall PHP')"
:description="__('Are you sure you want to uninstall this version?')"
method="uninstall"
/>

View File

@ -0,0 +1,25 @@
<x-modal name="update-php-ini">
<form wire:submit.prevent="saveIni" class="p-6">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('Update php.ini') }}
</h2>
<div class="mt-6">
<x-input-label for="ini" value="php.ini" />
<x-textarea wire:model.defer="ini" id="ini" name="ini" class="mt-1 w-full" rows="15" />
@error('ini')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6 flex justify-end">
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __('Cancel') }}
</x-secondary-button>
<x-primary-button class="ml-3">
{{ __('Save') }}
</x-primary-button>
</div>
</form>
</x-modal>

View File

@ -0,0 +1,45 @@
<x-card>
<x-slot name="title">
{{ __('Update Password') }}
</x-slot>
<x-slot name="description">
{{ __('Ensure your account is using a long, random password to stay secure.') }}
</x-slot>
<form id="update-password" wire:submit.prevent="update" class="mt-6 space-y-6">
@csrf
@method('put')
<div>
<x-input-label for="current_password" :value="__('Current Password')" />
<x-text-input wire:model.defer="current_password" id="current_password" name="current_password" type="password" class="mt-1 block w-full" autocomplete="current-password" />
@error('current_password')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div>
<x-input-label for="password" :value="__('New Password')" />
<x-text-input wire:model.defer="password" id="password" name="password" type="password" class="mt-1 block w-full" autocomplete="new-password" />
@error('password')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div>
<x-input-label for="password_confirmation" :value="__('Confirm Password')" />
<x-text-input wire:model.defer="password_confirmation" id="password_confirmation" name="password_confirmation" type="password" class="mt-1 block w-full" autocomplete="new-password" />
@error('password_confirmation')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
</form>
<x-slot name="actions">
@if (session('status') === 'password-updated')
<p class="mr-2">{{ __('Saved') }}</p>
@endif
<x-primary-button form="update-password" wire:loading.attr="disabled">{{ __('Save') }}</x-primary-button>
</x-slot>
</x-card>

View File

@ -0,0 +1,56 @@
@php
$user = auth()->user();
@endphp
<x-card>
<x-slot name="title">
{{ __('Profile Information') }}
</x-slot>
<x-slot name="description">
{{ __("Update your account's profile information and email address.") }}
</x-slot>
<form id="send-verification" wire:submit.prevent="sendVerificationEmail">
</form>
<form id="update-profile-information" wire:submit.prevent="submit" class="mt-6 space-y-6">
<div>
<x-input-label for="name" :value="__('Name')" />
<x-text-input wire:model.defer="name" id="name" name="name" type="text" class="mt-1 block w-full" required autocomplete="name" />
@error('name')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div>
<x-input-label for="email" :value="__('Email')" />
<x-text-input wire:model.defer="email" id="email" name="email" type="email" class="mt-1 block w-full" required autocomplete="username" />
@error('email')
<x-input-error class="mt-2" :messages="$message" />
@enderror
@if ($user instanceof \Illuminate\Contracts\Auth\MustVerifyEmail && ! $user->hasVerifiedEmail())
<div>
<p class="text-sm mt-2 text-gray-800 dark:text-gray-200">
{{ __('Your email address is unverified.') }}
<button form="send-verification" class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800">
{{ __('Click here to re-send the verification email.') }}
</button>
</p>
@if (session('status') === 'verification-link-sent')
<p class="mt-2 font-medium text-sm text-green-600 dark:text-green-400">
{{ __('A new verification link has been sent to your email address.') }}
</p>
@endif
</div>
@endif
</div>
</form>
<x-slot name="actions">
@if (session('status') === 'profile-updated')
<p class="mr-2">{{ __('Saved') }}</p>
@endif
<x-primary-button form="update-profile-information" wire:loading.attr="disabled">{{ __('Save') }}</x-primary-button>
</x-slot>
</x-card>

View File

@ -0,0 +1,75 @@
<div>
<x-primary-button x-data="" x-on:click.prevent="$dispatch('open-modal', 'create-queue')">
{{ __('Create Queue') }}
</x-primary-button>
<x-modal name="create-queue">
<form wire:submit.prevent="create" class="p-6">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('Create Queue') }}
</h2>
<div class="mt-6">
<x-input-label for="command" :value="__('Command')" />
<x-text-input wire:model.defer="command" id="command" name="command" type="text" class="mt-1 w-full" />
@error('command')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6">
<x-input-label for="user" :value="__('User')" />
<x-select-input wire:model.defer="user" id="user" name="user" class="mt-1 w-full">
<option value="" selected disabled>{{ __("Select") }}</option>
<option value="root" @if($user === 'root') selected @endif>root</option>
<option value="{{ $site->server->ssh_user }}" @if($user === $site->server->ssh_user) selected @endif>{{ $site->server->ssh_user }}</option>
</x-select-input>
@error('user')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6">
<x-input-label for="auto_start" :value="__('Auto Start')" />
<x-select-input wire:model="auto_start" id="auto_start" name="auto_start" class="mt-1 w-full">
<option value="" selected disabled>{{ __("Select") }}</option>
<option value="1" @if($auto_start) selected @endif>{{ __("Yes") }}</option>
<option value="0" @if(!$auto_start) selected @endif>{{ __("No") }}</option>
</x-select-input>
@error('auto_start')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6">
<x-input-label for="auto_restart" :value="__('Auto Restart')" />
<x-select-input wire:model="auto_restart" id="auto_restart" name="auto_restart" class="mt-1 w-full">
<option value="" selected disabled>{{ __("Select") }}</option>
<option value="1" @if($auto_restart) selected @endif>{{ __("Yes") }}</option>
<option value="0" @if(!$auto_restart) selected @endif>{{ __("No") }}</option>
</x-select-input>
@error('auto_restart')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6">
<x-input-label for="numprocs" :value="__('Numprocs')" />
<x-text-input wire:model.defer="numprocs" id="numprocs" name="numprocs" type="text" class="mt-1 w-full" placeholder="2" />
@error('numprocs')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6 flex justify-end">
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __('Cancel') }}
</x-secondary-button>
<x-primary-button class="ml-3" @created.window="$dispatch('close')">
{{ __('Create') }}
</x-primary-button>
</div>
</form>
</x-modal>
</div>

View File

@ -0,0 +1,27 @@
@if($status == \App\Enums\QueueStatus::RUNNING)
<x-status status="success">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\QueueStatus::CREATING)
<x-status status="warning">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\QueueStatus::FAILED)
<x-status status="danger">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\QueueStatus::RESTARTING)
<x-status status="warning">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\QueueStatus::STARTING)
<x-status status="warning">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\QueueStatus::STOPPING)
<x-status status="warning">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\QueueStatus::STOPPED)
<x-status status="danger">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\QueueStatus::FAILED)
<x-status status="danger">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\QueueStatus::DELETING)
<x-status status="danger">{{ $status }}</x-status>
@endif

View File

@ -0,0 +1,54 @@
<div>
<x-card-header>
<x-slot name="title">{{ __("Queues") }}</x-slot>
<x-slot name="description">{{ __("You can manage and create queues for your site") }}</x-slot>
<x-slot name="aside">
<livewire:queues.create-queue :site="$site" />
</x-slot>
</x-card-header>
<div x-data="" class="space-y-3">
@if(count($queues) > 0)
@foreach($queues as $queue)
<x-item-card>
<div class="flex flex-grow flex-col items-start justify-center">
<span class="mb-1 flex items-center lowercase text-red-600">
{{ $queue->command }}
</span>
<span class="text-sm text-gray-400">
{{ __("User:") }} {{ $queue->user }}
</span>
</div>
<div class="flex items-center">
@include('livewire.queues.partials.status', ['status' => $queue->status])
<div class="inline-flex">
<x-icon-button wire:click="start({{ $queue }})" wire:loading.attr="disabled">
<x-heroicon-o-play class="w-4 h-4" />
</x-icon-button>
<x-icon-button wire:click="stop({{ $queue }})" wire:loading.attr="disabled">
<x-heroicon-o-stop class="w-4 h-4" />
</x-icon-button>
<x-icon-button wire:click="restart({{ $queue }})" wire:loading.attr="disabled">
<x-heroicon-o-arrow-path class="w-4 h-4" />
</x-icon-button>
<x-icon-button x-on:click="$wire.deleteId = '{{ $queue->id }}'; $dispatch('open-modal', 'delete-queue')">
<x-heroicon-o-trash class="w-4 h-4" />
</x-icon-button>
</div>
</div>
</x-item-card>
@endforeach
<x-confirm-modal
name="delete-queue"
:title="__('Confirm')"
:description="__('Are you sure that you want to delete this queue?')"
method="delete"
/>
@else
<x-simple-card>
<div class="text-center">
{{ __("You don't have any queues yet!") }}
</div>
</x-simple-card>
@endif
</div>
</div>

View File

@ -0,0 +1,43 @@
<div x-data="">
<x-card-header>
<x-slot name="title">{{ __("Logs") }}</x-slot>
</x-card-header>
<x-table>
<tr>
<x-th>{{ __("Event") }}</x-th>
<x-th>{{ __("Date") }}</x-th>
<x-th></x-th>
</tr>
@foreach($logs as $log)
<tr>
<x-td>{{ $log->type }}</x-td>
<x-td>
<x-datetime :value="$log->created_at" />
</x-td>
<x-td>
<x-icon-button wire:click="showLog({{ $log->id }})" wire:loading.attr="disabled">
<x-heroicon-o-eye class="w-6 h-6" />
</x-icon-button>
</x-td>
</tr>
@endforeach
</x-table>
@if(is_null($count))
<div class="mt-5">
{{ $logs->withQueryString()->links() }}
</div>
@endif
<x-modal name="show-log" max-width="4xl">
<div class="p-6">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-5">
{{ __('View Log') }}
</h2>
<x-console-view>{{ $logContent }}</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>

View File

@ -0,0 +1,74 @@
<div>
<x-primary-button x-data="" x-on:click.prevent="$dispatch('open-modal', 'connect-provider')">
{{ __('Connect') }}
</x-primary-button>
<x-modal name="connect-provider" :show="$open">
<form wire:submit.prevent="connect" class="p-6">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('Connect to a Server Provider') }}
</h2>
<div class="mt-6">
<x-input-label for="provider" value="Provider" />
<x-select-input wire:model="provider" id="provider" name="provider" class="mt-1 w-full">
<option value="" selected disabled>{{ __("Select") }}</option>
@foreach(config('core.server_providers') as $p)
@if($p !== 'custom')
<option value="{{ $p }}" @if($provider === $p) selected @endif>{{ $p }}</option>
@endif
@endforeach
</x-select-input>
@error('provider')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6">
<x-input-label for="name" value="Name" />
<x-text-input wire:model.defer="name" id="name" name="name" type="text" class="mt-1 w-full" />
@error('name')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
@if($provider === 'aws')
<div class="mt-6">
<x-input-label for="key" value="Access Key" />
<x-text-input wire:model.defer="key" id="key" name="key" type="text" class="mt-1 w-full" />
@error('key')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6">
<x-input-label for="secret" value="Secret" />
<x-text-input wire:model.defer="secret" id="secret" name="secret" type="text" class="mt-1 w-full" />
@error('secret')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
@endif
@if(in_array($provider, ['hetzner', 'digitalocean', 'vultr', 'linode']))
<div class="mt-6">
<x-input-label for="token" value="API Key" />
<x-text-input wire:model.defer="token" id="token" name="token" type="text" class="mt-1 w-full" />
@error('token')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
@endif
<div class="mt-6 flex justify-end">
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __('Cancel') }}
</x-secondary-button>
<x-primary-button class="ml-3" @connected.window="$dispatch('close')">
{{ __('Connect') }}
</x-primary-button>
</div>
</form>
</x-modal>
</div>

View File

@ -0,0 +1,45 @@
<div>
<x-card-header>
<x-slot name="title">Server Providers</x-slot>
<x-slot name="description">You can connect to your server providers to create servers using their APIs</x-slot>
<x-slot name="aside">
<livewire:server-providers.connect-provider />
</x-slot>
</x-card-header>
<div x-data="" class="space-y-3">
@if(count($providers) > 0)
@foreach($providers as $provider)
<x-item-card>
<div class="flex-none">
<img src="{{ asset('static/images/' . $provider->provider . '.svg') }}" class="h-10 w-10" alt="">
</div>
<div class="ml-3 flex flex-grow flex-col items-start justify-center">
<span class="mb-1">{{ $provider->profile }}</span>
<span class="text-sm text-gray-400">
<x-datetime :value="$provider->created_at"/>
</span>
</div>
<div class="flex items-center">
<div class="inline">
<x-icon-button x-on:click="$wire.deleteId = '{{ $provider->id }}'; $dispatch('open-modal', 'delete-provider')">
<x-heroicon-o-trash class="w-4 h-4" />
</x-icon-button>
</div>
</div>
</x-item-card>
@endforeach
<x-confirm-modal
name="delete-provider"
:title="__('Confirm')"
:description="__('Are you sure that you want to delete this provider?')"
method="delete"
/>
@else
<x-simple-card>
<div class="text-center">
{{ __("You haven't connected to any server providers yet!") }}
</div>
</x-simple-card>
@endif
</div>
</div>

View File

@ -0,0 +1 @@
<x-primary-button wire:click="check">{{ __("Check Connection") }}</x-primary-button>

View File

@ -0,0 +1,38 @@
<x-card>
<x-slot name="title">{{ __("Edit Server") }}</x-slot>
<x-slot name="description">{{ __("You can edit your server's some of fields") }}</x-slot>
<form id="update-server" wire:submit.prevent="update" class="mt-6 space-y-6">
<div>
<x-input-label for="name" :value="__('Name')" />
<x-text-input wire:model.defer="name" id="name" name="name" type="text" class="mt-1 block w-full" required autocomplete="name" />
@error('name')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div>
<x-input-label for="ip" :value="__('IP Address')" />
<x-text-input wire:model.defer="ip" id="ip" name="ip" type="text" class="mt-1 block w-full" required autocomplete="ip" />
@error('ip')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div>
<x-input-label for="port" :value="__('SSH Port')" />
<x-text-input wire:model.defer="port" id="port" name="port" type="text" class="mt-1 block w-full" required autocomplete="port" />
@error('port')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
</form>
<x-slot name="actions">
@if (session('status') === 'server-updated')
<p class="mr-2">{{ __('Saved') }}</p>
@endif
<x-primary-button form="update-server" wire:loading.attr="disabled">{{ __('Save') }}</x-primary-button>
</x-slot>
</x-card>

View File

@ -0,0 +1 @@
<x-secondary-button wire:click="reboot" wire:loading.attr="disabled">{{ __("Reboot") }}</x-secondary-button>

View File

@ -0,0 +1,58 @@
<x-card>
<x-slot name="title">{{ __("Details") }}</x-slot>
<x-slot name="description">{{ __("More details about your server") }}</x-slot>
<div class="flex items-center justify-between">
<div>{{ __("Created At") }}</div>
<div>
<x-datetime :value="$server->created_at" />
</div>
</div>
<div>
<div class="py-5">
<div class="border-t border-gray-200 dark:border-gray-700"></div>
</div>
</div>
<div class="flex items-center justify-between">
<div>{{ __("Provider") }}</div>
<div class="capitalize">{{ $server->provider }}</div>
</div>
<div>
<div class="py-5">
<div class="border-t border-gray-200 dark:border-gray-700"></div>
</div>
</div>
{{--<div class="flex items-center justify-between">--}}
{{-- <div>{{ __("Server ID") }}</div>--}}
{{-- <div class="flex items-center">--}}
{{-- <span class="rounded-md bg-gray-100 p-1 dark:bg-gray-700">{{ $server->id }}</span>--}}
{{-- <span class="ml-2">{{ __("You will need this when you use the API") }}</span>--}}
{{-- </div>--}}
{{--</div>--}}
{{--<div>--}}
{{-- <div class="py-5">--}}
{{-- <div class="border-t border-gray-200 dark:border-gray-700"></div>--}}
{{-- </div>--}}
{{--</div>--}}
<div class="flex items-center justify-between">
<div>{{ __("Status") }}</div>
<div class="flex items-center">
@include('livewire.servers.partials.status', ['status' => $server->status])
<div class="inline-flex ml-2">
<livewire:server-settings.check-connection :server="$server" />
</div>
</div>
</div>
<div>
<div class="py-5">
<div class="border-t border-gray-200 dark:border-gray-700"></div>
</div>
</div>
<div class="flex items-center justify-between">
<div>{{ __("Reboot Server") }}</div>
<div class="flex items-center">
<div class="inline-flex">
<livewire:server-settings.reboot-server :server="$server" />
</div>
</div>
</div>
</x-card>

View File

@ -0,0 +1,36 @@
<div>
<x-secondary-button x-data="" x-on:click.prevent="$dispatch('open-modal', 'add-existing-key')">
{{ __('Add existing Key') }}
</x-secondary-button>
<x-modal name="add-existing-key">
<form wire:submit.prevent="add" class="p-6">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('Add existing Key') }}
</h2>
<div class="mt-6">
<x-input-label for="key_id" :value="__('SSH Key')" />
<x-select-input wire:model.defer="key_id" id="key_id" name="key_id" class="mt-1 w-full">
<option value="" selected disabled>{{ __("Select") }}</option>
@foreach($keys as $key)
<option value="{{ $key->id }}" @if($key->id === $key_id) selected @endif>{{ $key->name }}</option>
@endforeach
</x-select-input>
@error('key_id')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6 flex justify-end">
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __('Cancel') }}
</x-secondary-button>
<x-primary-button class="ml-3" @added.window="$dispatch('close')">
{{ __('Add') }}
</x-primary-button>
</div>
</form>
</x-modal>
</div>

View File

@ -0,0 +1,39 @@
<div>
<x-primary-button x-data="" x-on:click.prevent="$dispatch('open-modal', 'add-key')">
{{ __('Add new Key') }}
</x-primary-button>
<x-modal name="add-key">
<form wire:submit.prevent="add" class="p-6">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('Add new Key') }}
</h2>
<div class="mt-6">
<x-input-label for="name" :value="__('Name')" />
<x-text-input wire:model.defer="name" id="name" name="name" type="text" class="mt-1 w-full" />
@error('name')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6">
<x-input-label for="public_key" :value="__('Public Key')" />
<x-textarea wire:model.defer="public_key" id="public_key" name="public_key" class="mt-1 w-full" rows="5" />
@error('public_key')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6 flex justify-end">
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __('Cancel') }}
</x-secondary-button>
<x-primary-button class="ml-3" @added.window="$dispatch('close')">
{{ __('Add') }}
</x-primary-button>
</div>
</form>
</x-modal>
</div>

View File

@ -0,0 +1,9 @@
@if($status == \App\Enums\SshKeyStatus::ADDED)
<x-status status="success">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\SshKeyStatus::ADDING)
<x-status status="warning">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\SshKeyStatus::DELETING)
<x-status status="danger">{{ $status }}</x-status>
@endif

View File

@ -0,0 +1,50 @@
<div>
<x-card-header>
<x-slot name="title">{{ __("SSH Keys") }}</x-slot>
<x-slot name="description">{{ __("Add or modify your ssh keys") }}</x-slot>
<x-slot name="aside">
<div class="flex items-center">
<div>
<livewire:server-ssh-keys.add-new-key :server="$server" />
</div>
<div class="ml-2">
<livewire:server-ssh-keys.add-existing-key :server="$server" />
</div>
</div>
</x-slot>
</x-card-header>
<div x-data="" class="space-y-3">
@if(count($keys) > 0)
@foreach($keys as $key)
<x-item-card>
<div class="flex flex-grow flex-col items-start justify-center">
<span class="mb-1">{{ $key->name }}</span>
<span class="text-sm text-gray-400">
<x-datetime :value="$key->created_at" />
</span>
</div>
<div class="flex items-center">
@include('livewire.server-ssh-keys.partials.status', ['status' => $key->pivot->status])
<div class="inline">
<x-icon-button x-on:click="$wire.deleteId = '{{ $key->id }}'; $dispatch('open-modal', 'delete-key')">
<x-heroicon-o-trash class="w-4 h-4" />
</x-icon-button>
</div>
</div>
</x-item-card>
@endforeach
<x-confirm-modal
name="delete-key"
:title="__('Confirm')"
:description="__('Are you sure that you want to delete this key?')"
method="delete"
/>
@else
<x-simple-card>
<div class="text-center">
{{ __("You haven't connected to any keys yet!") }}
</div>
</x-simple-card>
@endif
</div>
</div>

View File

@ -0,0 +1,158 @@
<x-container x-data="">
<x-card>
<x-slot name="title">{{ __("Create new Server") }}</x-slot>
<x-slot name="description">{{ __("Use this form to create a new server") }}</x-slot>
<form id="create-server" wire:submit.prevent="submit" class="mt-6 space-y-6">
<div>
<x-input-label>{{ __("Select a server provider") }}</x-input-label>
<div class="grid grid-cols-6 gap-2 mt-1">
@foreach(config('core.server_providers') as $p)
<x-server-provider-item x-on:click="$wire.provider = '{{ $p }}'" :active="$provider === $p">
<div class="flex w-full flex-col items-center justify-center text-center">
<img src="{{ asset('static/images/' . $p . '.svg') }}" class="h-7" alt="Server">
<span class="md:text-normal mt-2 hidden text-sm md:block">{{ $p }}</span>
</div>
</x-server-provider-item>
@endforeach
</div>
@error('provider')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
@if($provider === 'custom')
@include('livewire.servers.partials.public-key')
@else
<div>
<x-input-label for="server_provider" value="Provider Profile" />
<div class="flex items-center mt-1">
<x-select-input wire:model="server_provider" id="server_provider" name="server_provider" class="w-full">
<option value="" disabled selected>{{ __("Select") }}</option>
@foreach($serverProviders as $sp)
<option value="{{ $sp->id }}" @if($sp->id === $server_provider) selected @endif>
{{ $sp->profile }}
</option>
@endforeach
</x-select-input>
<x-secondary-button :href="route('server-providers', ['provider' => $provider])" class="flex-none ml-2">{{ __('Connect') }}</x-secondary-button>
</div>
@error('server_provider')
<x-input-error class="mt-2" :messages="$message" />
@enderror
@if(count($serverProviders) == 0)
<x-input-error class="mt-2" :messages="__('You have not connected to any providers!')" />
@endif
</div>
@endif
<div>
<x-input-label for="name" :value="__('Name')" />
<x-text-input wire:model.defer="name" id="name" name="name" type="text" class="mt-1 block w-full" autocomplete="name" />
@error('name')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
@if($provider !== 'custom')
<div class="grid grid-cols-1 lg:grid-cols-2 gap-3">
<div>
<x-input-label for="plan" value="Plan" />
<x-select-input wire:model.defer="plan" id="plan" name="plan" class="mt-1 w-full">
<option value="" disabled selected>{{ __("Select") }}</option>
@foreach(config('serverproviders')[$provider]['plans'] as $value)
<option value="{{ $value['value'] }}" @if($value['value'] === $plan) selected @endif>{{ $value['title'] }}</option>
@endforeach
</x-select-input>
@error('plan')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div>
<x-input-label for="region" value="Region" />
<x-select-input wire:model.defer="region" id="region" name="region" class="mt-1 w-full">
<option value="" disabled selected>{{ __("Select") }}</option>
@foreach(config('serverproviders')[$provider]['regions'] as $key => $value)
<option value="{{ $value['value'] }}" @if($value['value'] === $plan) selected @endif>{{ $value['title'] }}</option>
@endforeach
</x-select-input>
@error('region')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
</div>
@endif
@if($provider === 'custom')
<div class="grid grid-cols-2 gap-3">
<div>
<x-input-label for="ip" :value="__('SSH IP Address')" />
<x-text-input wire:model.defer="ip" id="ip" name="ip" type="text" class="mt-1 block w-full" autocomplete="ip" />
@error('ip')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div>
<x-input-label for="port" :value="__('SSH Port')" />
<x-text-input wire:model.defer="port" id="port" name="port" type="text" class="mt-1 block w-full" autocomplete="port" />
@error('port')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
</div>
@endif
<div>
<x-input-label for="os" value="Operating System" />
<x-select-input wire:model.defer="os" id="os" name="os" class="mt-1 w-full">
@foreach(config('core.operating_systems') as $operatingSystem)
<option value="{{ $operatingSystem }}" @if($operatingSystem === $os) selected @endif>
{{ str($operatingSystem)->replace('_', ' ')->ucfirst() }} LTS
</option>
@endforeach
</x-select-input>
@error('os')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-3">
<div>
<x-input-label for="webserver" value="Webserver" />
<x-select-input wire:model.defer="webserver" id="webserver" name="webserver" class="mt-1 w-full">
@foreach(config('core.webservers') as $ws)
<option value="{{ $ws }}" @if($ws === $webserver) selected @endif>{{ $ws }}</option>
@endforeach
</x-select-input>
@error('webserver')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div>
<x-input-label for="database" value="Database" />
<x-select-input wire:model.defer="database" id="database" name="database" class="mt-1 w-full">
@foreach(config('core.databases') as $db)
<option value="{{ $db }}" @if($db === $database) selected @endif>{{ $db }}</option>
@endforeach
</x-select-input>
@error('database')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div>
<x-input-label for="php" value="PHP" />
<x-select-input wire:model.defer="php" id="php" name="php" class="mt-1 w-full">
@foreach(config('core.php_versions') as $p)
<option value="{{ $p }}" @if($p === $php) selected @endif>{{ $p }}</option>
@endforeach
</x-select-input>
@error('php')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
</div>
</form>
<x-slot name="actions">
<x-primary-button form="create-server" wire:loading.attr="disabled">{{ __('Create') }}</x-primary-button>
</x-slot>
</x-card>
</x-container>

View File

@ -0,0 +1,9 @@
<div x-data="">
<x-danger-button x-on:click="$dispatch('open-modal', 'delete-server')">{{ __("Delete Server") }}</x-danger-button>
<x-confirm-modal
name="delete-server"
:title="__('Confirm')"
:description="__('Are you sure that you want to delete this server?')"
method="delete"
/>
</div>

View File

@ -0,0 +1,14 @@
<x-card>
<x-slot name="title">
<span class="text-red-600">{{ __("Installation Failed!") }}</span>
</x-slot>
<x-slot name="description">{{ __("Your server installation failed") }}</x-slot>
<div class="text-center">
{{ __("The installation has been failed on step:") }}
<span class="font-bold">{{ $server->progress_step }} ({{ $server->progress }}%)</span>
</div>
<div class="mt-5 flex items-center justify-center">
<x-secondary-button :href="route('servers.logs', ['server' => $server])" class="mr-2">{{ __("View Logs") }}</x-secondary-button>
<livewire:servers.delete-server :server="$server" />
</div>
</x-card>

View File

@ -0,0 +1,16 @@
<x-card>
<x-slot name="title">{{ __("Installing") }}</x-slot>
<x-slot name="description">{{ __("The server is being installed") }}</x-slot>
<div class="relative flex h-6 overflow-hidden rounded bg-primary-200 text-xs dark:bg-primary-500 dark:bg-opacity-10">
<div
style="width:{{ $server->progress }}%;"
class="flex flex-col justify-center whitespace-nowrap bg-primary-500 text-center text-white shadow-none"
></div>
<span class="absolute left-0 right-0 top-1 font-semibold text-center {{ $server->progress >= 40 ? 'text-white' : 'text-black dark:text-white' }}">
{{ $server->progress }}%
</span>
</div>
<div class="text-center mt-3">
<span class="font-bold">{{ $server->progress_step }}</span>
</div>
</x-card>

View File

@ -0,0 +1,24 @@
<div>
<div>
<div class="rounded-sm border-l-4 border-yellow-500 bg-yellow-100 py-3 px-4 text-yellow-700 dark:bg-yellow-500 dark:bg-opacity-10 dark:text-yellow-500">
Your server needs to have a new unused installation of supported operation systems and must have a root
user. To get started, add our public key to /root/.ssh/authorized_keys file by running the bellow command on
your server as root.
</div>
</div>
</div>
<div>
<div class="flex items-center justify-between">
<x-input-label for="pk">
{{ __("Run this command on your server as root user") }}
</x-input-label>
<x-input-label class="cursor-pointer" x-data="{ copied: false }" x-clipboard.raw="{{ config('core.ssh_public_key') }}">
<div x-show="copied" class="flex items-center">
{{ __("Copied") }}
<x-heroicon-m-check class="ml-1 w-4 text-green-700" />
</div>
<div x-show="!copied" x-on:click="copied = true; setTimeout(() => {copied = false}, 2000)">{{ __("Copy") }}</div>
</x-input-label>
</div>
<x-textarea id="pk" name="pk" class="mt-1" disabled>{{ config('core.ssh_public_key') }}</x-textarea>
</div>

View File

@ -0,0 +1,34 @@
<div>
<x-card-header>
<x-slot name="title">
{{ __("Server Overview") }}
</x-slot>
<x-slot name="description">{{ __("You can see an overview about your server here") }}</x-slot>
<x-slot name="aside">
@include('livewire.servers.partials.status', ['status' => $server->status])
</x-slot>
</x-card-header>
<div class="mx-auto grid grid-cols-3 rounded-md bg-white border border-gray-200 dark:border-gray-700 dark:bg-gray-800">
<div class="p-5">
<div class="flex items-center justify-center md:justify-start">
<x-heroicon-o-globe-alt class="w-8 h-8 text-primary-500" />
<div class="ml-2 hidden md:block">{{ __("Sites") }}</div>
</div>
<div class="mt-3 text-center text-3xl font-bold text-gray-600 dark:text-gray-400 md:text-left">{{ $server->sites()->count() }}</div>
</div>
<div class="border-l border-r border-gray-200 p-5 dark:border-gray-900">
<div class="flex items-center justify-center md:justify-start">
<x-heroicon-o-circle-stack class="w-8 h-8 text-primary-500" />
<div class="ml-2 hidden md:block">{{ __("Databases") }}</div>
</div>
<div class="mt-3 text-center text-3xl font-bold text-gray-600 dark:text-gray-400 md:text-left">{{ $server->databases()->count() }}</div>
</div>
<div class="p-5">
<div class="flex items-center justify-center md:justify-start">
<x-heroicon-o-briefcase class="w-8 h-8 text-primary-500" />
<div class="ml-2 hidden md:block">{{ __("Cron Jobs") }}</div>
</div>
<div class="mt-3 text-center text-3xl font-bold text-gray-600 dark:text-gray-400 md:text-left">{{ $server->cronJobs()->count() }}</div>
</div>
</div>
</div>

View File

@ -0,0 +1,12 @@
@if($status == \App\Enums\ServerStatus::READY)
<x-status status="success">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\ServerStatus::INSTALLING)
<x-status status="warning">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\ServerStatus::DISCONNECTED)
<x-status status="disabled">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\ServerStatus::INSTALLATION_FAILED)
<x-status status="danger">{{ $status }}</x-status>
@endif

View File

@ -0,0 +1,42 @@
<x-container>
<x-card-header>
<x-slot name="title">Servers</x-slot>
<x-slot name="description">Here you can see your servers list and manage them</x-slot>
<x-slot name="aside">
<x-primary-button :href="route('servers.create')">
{{ __('Create a Server') }}
</x-primary-button>
</x-slot>
</x-card-header>
@if(count($servers) > 0)
<div class="space-y-3">
@foreach($servers as $server)
<a href="{{ route('servers.show', ['server' => $server]) }}" class="block">
<x-item-card>
<div class="flex-none">
<img src="{{ asset('static/images/' . $server->provider . '.svg') }}" class="h-10 w-10" alt="">
</div>
<div class="ml-3 flex flex-grow flex-col items-start justify-center">
<span class="mb-1">{{ $server->name }}</span>
<span class="text-sm text-gray-400">
{{ $server->ip }}
</span>
</div>
<div class="flex items-center">
<div class="inline">
@include('livewire.servers.partials.status', ['status' => $server->status])
</div>
</div>
</x-item-card>
</a>
@endforeach
</div>
@else
<x-simple-card>
<div class="text-center">
{{ __("You don't have any servers yet!") }}
</div>
</x-simple-card>
@endif
</x-container>

View File

@ -0,0 +1,16 @@
<div>
@if($server->status === \App\Enums\ServerStatus::INSTALLING)
@include('livewire.servers.partials.installing', ['server' => $server])
<livewire:server-logs.logs-list :server="$server" />
@endif
@if($server->status === \App\Enums\ServerStatus::INSTALLATION_FAILED)
@include('livewire.servers.partials.installation-failed', ['server' => $server])
<livewire:server-logs.logs-list :server="$server" />
@endif
@if(in_array($server->status, [\App\Enums\ServerStatus::READY, \App\Enums\ServerStatus::DISCONNECTED]))
<div class="space-y-10">
@include('livewire.servers.partials.server-overview', ['server' => $server])
<livewire:server-logs.logs-list :server="$server" :count="10" />
</div>
@endif
</div>

View File

@ -0,0 +1,27 @@
@if($status == \App\Enums\ServiceStatus::READY)
<x-status status="success">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\ServiceStatus::INSTALLING)
<x-status status="warning">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\ServiceStatus::INSTALLATION_FAILED)
<x-status status="danger">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\ServiceStatus::UNINSTALLING)
<x-status status="danger">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\ServiceStatus::FAILED)
<x-status status="danger">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\ServiceStatus::RESTARTING)
<x-status status="warning">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\ServiceStatus::STARTING)
<x-status status="warning">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\ServiceStatus::STOPPING)
<x-status status="warning">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\ServiceStatus::STOPPED)
<x-status status="danger">{{ $status }}</x-status>
@endif

View File

@ -0,0 +1,48 @@
<div>
<x-card-header>
<x-slot name="title">{{ __("Services") }}</x-slot>
<x-slot name="description">{{ __("All services that we installed on your server are here") }}</x-slot>
</x-card-header>
<div class="space-y-3">
@foreach($services as $service)
<x-item-card>
<div class="flex-none">
<img src="{{ asset('static/images/' . $service->name . '.svg') }}" class="h-10 w-10" alt="">
</div>
<div class="ml-3 flex flex-grow flex-col items-start justify-center">
<div class="flex items-center">
<div class="mr-2">{{ $service->name }}:{{ $service->version }}</div>
@include('livewire.services.partials.status', ['status' => $service->status])
</div>
</div>
<div class="flex items-center">
<x-dropdown>
<x-slot name="trigger">
<x-secondary-button>
{{ __("Actions") }}
<x-heroicon-m-chevron-down class="w-4 ml-1" />
</x-secondary-button>
</x-slot>
<x-slot name="content">
@if($service->status == \App\Enums\ServiceStatus::STOPPED)
<x-dropdown-link class="cursor-pointer" wire:click="start({{ $service->id }})">
{{ __("Start") }}
</x-dropdown-link>
@endif
@if($service->status == \App\Enums\ServiceStatus::READY)
<x-dropdown-link class="cursor-pointer" wire:click="stop({{ $service->id }})">
{{ __("Stop") }}
</x-dropdown-link>
@endif
<x-dropdown-link class="cursor-pointer" wire:click="restart({{ $service->id }})">
{{ __("Restart") }}
</x-dropdown-link>
</x-slot>
</x-dropdown>
</div>
</x-item-card>
@endforeach
</div>
</div>

View File

@ -0,0 +1,33 @@
<x-card>
<x-slot name="title">{{ __("Change PHP Version") }}</x-slot>
<x-slot name="description">{{ __("You can change your site's PHP version here") }}</x-slot>
<form id="change-php-version" wire:submit.prevent="change" class="space-y-6">
<div>
<x-input-label for="version" :value="__('PHP Version')" />
<x-select-input wire:model.defer="version" id="version" name="version" class="mt-1 w-full">
<option value="" disabled selected>{{ __("Select") }}</option>
@foreach($site->server->installedPHPVersions() as $php)
<option value="{{ $php }}" @if($php === $version) selected @endif>{{ $php }}</option>
@endforeach
</x-select-input>
@error('version')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
</form>
<x-slot name="actions">
@if (session('status') === 'changing-php-version')
<p class="mr-2">{{ __('Updating...') }}</p>
@endif
@if (session('status') === 'change-site-php-finished')
<p class="mr-2">{{ __('Updated!') }}</p>
@endif
@if (session('status') === 'change-site-php-failed')
<p class="mr-2">{{ __('Failed!') }}</p>
@endif
<x-primary-button form="change-php-version" wire:loading.attr="disabled">{{ __('Save') }}</x-primary-button>
</x-slot>
</x-card>

View File

@ -0,0 +1,104 @@
<div x-data="">
<x-card>
<x-slot name="title">{{ __("Create new site") }}</x-slot>
<x-slot name="description">{{ __("Use this form to create a new site") }}</x-slot>
<form id="create-site" wire:submit.prevent="create" class="space-y-6">
<div>
<x-input-label>{{ __("Select site type") }}</x-input-label>
<div class="grid grid-cols-6 gap-2 mt-1">
@foreach(config('core.site_types') as $t)
<x-site-type-item x-on:click="$wire.type = '{{ $t }}'" :active="$type === $t">
<div class="flex w-full flex-col items-center justify-center text-center">
<img src="{{ asset('static/images/' . $t . '.svg') }}" class="h-7" alt="Server">
<span class="md:text-normal mt-2 hidden text-sm md:block">{{ $t }}</span>
</div>
</x-site-type-item>
@endforeach
</div>
@error('type')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div>
<x-input-label for="domain" :value="__('Domain')" />
<x-text-input wire:model.defer="domain" id="domain" name="domain" type="text" class="mt-1 block w-full" autocomplete="domain" placeholder="example.com" />
@error('domain')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div>
<x-input-label for="alias" :value="__('Alias')" />
<x-text-input wire:model.defer="alias" id="alias" name="alias" type="text" class="mt-1 block w-full" autocomplete="alias" placeholder="www.example.com" />
@error('alias')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div>
<x-input-label for="php_version" :value="__('PHP Version')" />
<x-select-input wire:model.defer="php_version" id="php_version" name="php_version" class="mt-1 w-full">
<option value="" selected disabled>{{ __("Select") }}</option>
@foreach($server->installedPHPVersions() as $version)
<option value="{{ $version }}" @if($version === $php_version) selected @endif>
PHP {{ $version }}
</option>
@endforeach
</x-select-input>
@error('php_version')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div>
<x-input-label for="web_directory" :value="__('Web Directory')" />
<x-text-input wire:model.defer="web_directory" id="web_directory" name="web_directory" type="text" class="mt-1 block w-full" autocomplete="web_directory" />
@error('web_directory')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div>
<x-input-label for="source_control" :value="__('Source Control')" />
<x-select-input wire:model="source_control" id="source_control" name="source_control" class="mt-1 w-full">
<option value="" selected disabled>{{ __("Select") }}</option>
@foreach($sourceControls as $sourceControl)
<option value="{{ $sourceControl->provider }}" @if($sourceControl->provider === $source_control) selected @endif>
{{ ucfirst($sourceControl->provider) }}
</option>
@endforeach
</x-select-input>
@error('source_control')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div>
<x-input-label for="repository" :value="__('Repository')" />
<x-text-input wire:model.defer="repository" id="repository" name="repository" type="text" class="mt-1 block w-full" autocomplete="repository" placeholder="organization/repository" />
@error('repository')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div>
<x-input-label for="branch" :value="__('Branch')" />
<x-text-input wire:model.defer="branch" id="branch" name="branch" type="text" class="mt-1 block w-full" autocomplete="branch" placeholder="main" />
@error('branch')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6">
<label for="composer" class="inline-flex items-center">
<input id="composer" wire:model.defer="composer" type="checkbox" class="rounded dark:bg-gray-900 border-gray-300 dark:border-gray-700 text-indigo-600 shadow-sm focus:ring-indigo-500 dark:focus:ring-indigo-600 dark:focus:ring-offset-gray-800" name="composer">
<span class="ml-2 text-sm text-gray-600 dark:text-gray-400">{{ __('Run `composer install --no-dev`') }}</span>
</label>
</div>
</form>
<x-slot name="actions">
<x-primary-button form="create-site" wire:loading.attr="disabled">{{ __('Create') }}</x-primary-button>
</x-slot>
</x-card>
</div>

View File

@ -0,0 +1,9 @@
<div x-data="">
<x-danger-button x-on:click="$dispatch('open-modal', 'delete-site')">{{ __("Delete Site") }}</x-danger-button>
<x-confirm-modal
name="delete-site"
:title="__('Confirm')"
:description="__('Are you sure that you want to delete this site?')"
method="delete"
/>
</div>

View File

@ -0,0 +1,10 @@
<x-card>
<x-slot name="title">
<span class="text-red-600">{{ __("Installation Failed!") }}</span>
</x-slot>
<x-slot name="description">{{ __("Your site's installation failed") }}</x-slot>
<div class="mt-5 flex items-center justify-center">
<x-secondary-button :href="route('servers.logs', ['server' => $site->server])" class="mr-2">{{ __("View Logs") }}</x-secondary-button>
<livewire:sites.delete-site :site="$site" />
</div>
</x-card>

View File

@ -0,0 +1,13 @@
<x-card>
<x-slot name="title">{{ __("Installing") }}</x-slot>
<x-slot name="description">{{ __("The site is being installed") }}</x-slot>
<div class="relative flex h-6 overflow-hidden rounded bg-primary-200 text-xs dark:bg-primary-500 dark:bg-opacity-10">
<div
style="width:{{ $site->progress }}%;"
class="flex flex-col justify-center whitespace-nowrap bg-primary-500 text-center text-white shadow-none"
></div>
<span class="absolute left-0 right-0 top-1 font-semibold text-center {{ $site->progress >= 40 ? 'text-white' : 'text-black dark:text-white' }}">
{{ $site->progress }}%
</span>
</div>
</x-card>

View File

@ -0,0 +1,38 @@
<div>
<x-card-header>
<x-slot name="title">
{{ __("Site Overview") }}
</x-slot>
<x-slot name="description">
<a href="{{ $site->activeSsl ? 'https://' : 'http://' . $site->domain }}" target="_blank">{{ $site->domain }}</a>
</x-slot>
<x-slot name="aside">
@include('livewire.sites.partials.status', ['status' => $site->status])
</x-slot>
</x-card-header>
<div class="mx-auto grid grid-cols-3 rounded-md bg-white border border-gray-200 dark:border-gray-700 dark:bg-gray-800">
<div class="p-5">
<div class="flex items-center justify-center md:justify-start">
<x-heroicon-o-lock-closed class="w-8 h-8 text-primary-500" />
<div class="ml-2 hidden md:block">{{ __("SSL") }}</div>
</div>
<div class="mt-3 text-center text-3xl font-bold text-gray-600 dark:text-gray-400 md:text-left">
{{ $site->activeSsl ? __("Yes") : __("No") }}
</div>
</div>
<div class="border-l border-r border-gray-200 p-5 dark:border-gray-900">
<div class="flex items-center justify-center md:justify-start">
<x-heroicon-o-rectangle-stack class="w-8 h-8 text-primary-500" />
<div class="ml-2 hidden md:block">{{ __("Queues") }}</div>
</div>
<div class="mt-3 text-center text-3xl font-bold text-gray-600 dark:text-gray-400 md:text-left">{{ $site->queues()->count() }}</div>
</div>
<div class="p-5">
<div class="flex items-center justify-center md:justify-start">
<x-heroicon-o-code-bracket class="w-8 h-8 text-primary-500" />
<div class="ml-2 hidden md:block">{{ __("PHP") }}</div>
</div>
<div class="mt-3 text-center text-3xl font-bold text-gray-600 dark:text-gray-400 md:text-left">{{ $site->php_version }}</div>
</div>
</div>
</div>

View File

@ -0,0 +1,12 @@
@if($status == \App\Enums\SiteStatus::READY)
<x-status status="success">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\SiteStatus::INSTALLING)
<x-status status="warning">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\SiteStatus::INSTALLATION_FAILED)
<x-status status="danger">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\SiteStatus::DELETING)
<x-status status="danger">{{ $status }}</x-status>
@endif

View File

@ -0,0 +1,13 @@
<div>
@if($site->status === \App\Enums\SiteStatus::INSTALLING)
@include('livewire.sites.partials.installing', ['site' => $site])
@endif
@if($site->status === \App\Enums\SiteStatus::INSTALLATION_FAILED)
@include('livewire.sites.partials.installation-failed', ['site' => $site])
@endif
@if($site->status === \App\Enums\SiteStatus::READY)
<div class="space-y-10">
@include('livewire.sites.partials.site-overview', ['site' => $site])
</div>
@endif
</div>

View File

@ -0,0 +1,42 @@
<div>
<x-card-header>
<x-slot name="title">Sites</x-slot>
<x-slot name="description">Your sites will appear here. You can see the details and manage them</x-slot>
<x-slot name="aside">
<x-primary-button :href="route('servers.sites.create', ['server' => $server])">
{{ __('Create Site') }}
</x-primary-button>
</x-slot>
</x-card-header>
@if(count($sites) > 0)
<div class="space-y-3">
@foreach($sites as $site)
<a href="{{ route('servers.sites.show', ['server' => $server, 'site' => $site]) }}" class="block">
<x-item-card>
<div class="flex-none">
<img src="{{ asset('static/images/' . $site->type . '.svg') }}" class="h-10 w-10" alt="">
</div>
<div class="ml-3 flex flex-grow flex-col items-start justify-center">
<span class="mb-1">{{ $site->domain }}</span>
<span class="text-sm text-gray-400">
<x-datetime :value="$site->created_at"/>
</span>
</div>
<div class="flex items-center">
<div class="inline">
@include('livewire.sites.partials.status', ['status' => $site->status])
</div>
</div>
</x-item-card>
</a>
@endforeach
</div>
@else
<x-simple-card>
<div class="text-center">
{{ __("You don't have any sites yet!") }}
</div>
</x-simple-card>
@endif
</div>

View File

@ -0,0 +1,48 @@
<div x-data="">
<x-item-card>
<div class="flex-none">
@include('livewire.source-controls.partials.bitbucket-icon')
</div>
<div class="ml-3 flex flex-grow flex-col items-start justify-center">
<span class="mb-1">{{ __("Bitbucket") }}</span>
</div>
<div class="flex items-center">
<div class="inline">
@if($sourceControl)
<x-secondary-button x-on:click="$dispatch('open-modal', 'connect-bitbucket')">{{ __("Modify") }}</x-secondary-button>
@else
<x-primary-button x-on:click="$dispatch('open-modal', 'connect-bitbucket')">{{ __("Connect") }}</x-primary-button>
@endif
</div>
</div>
</x-item-card>
<x-modal name="connect-bitbucket">
<form wire:submit.prevent="connect" class="p-6">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('Connect to Bitbucket') }}
</h2>
<div class="mt-6">
<x-input-label for="token" :value="__('Access Token')" />
<x-text-input wire:model.defer="token" id="token" name="token" type="text" :value="$sourceControl ? $sourceControl->token : ''" class="mt-1 w-full" />
@error('token')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6 flex items-center justify-end">
@if (session('status') === 'bitbucket-updated')
<p class="mr-2">{{ __('Updated') }}</p>
@endif
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __('Cancel') }}
</x-secondary-button>
<x-primary-button class="ml-3" @connected.window="$dispatch('close')">
{{ __('Connect') }}
</x-primary-button>
</div>
</form>
</x-modal>
</div>

View File

@ -0,0 +1,48 @@
<div x-data="">
<x-item-card>
<div class="flex-none">
@include('livewire.source-controls.partials.github-icon')
</div>
<div class="ml-3 flex flex-grow flex-col items-start justify-center">
<span class="mb-1">{{ __("Github") }}</span>
</div>
<div class="flex items-center">
<div class="inline">
@if($sourceControl)
<x-secondary-button x-on:click="$dispatch('open-modal', 'connect-github')">{{ __("Modify") }}</x-secondary-button>
@else
<x-primary-button x-on:click="$dispatch('open-modal', 'connect-github')">{{ __("Connect") }}</x-primary-button>
@endif
</div>
</div>
</x-item-card>
<x-modal name="connect-github">
<form wire:submit.prevent="connect" class="p-6">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('Connect to Github') }}
</h2>
<div class="mt-6">
<x-input-label for="token" :value="__('Access Token')" />
<x-text-input wire:model.defer="token" id="token" name="token" type="text" :value="$sourceControl ? $sourceControl->token : ''" class="mt-1 w-full" />
@error('token')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6 flex items-center justify-end">
@if (session('status') === 'github-updated')
<p class="mr-2">{{ __('Updated') }}</p>
@endif
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __('Cancel') }}
</x-secondary-button>
<x-primary-button class="ml-3" @connected.window="$dispatch('close')">
{{ __('Connect') }}
</x-primary-button>
</div>
</form>
</x-modal>
</div>

View File

@ -0,0 +1,48 @@
<div x-data="">
<x-item-card>
<div class="flex-none">
@include('livewire.source-controls.partials.gitlab-icon')
</div>
<div class="ml-3 flex flex-grow flex-col items-start justify-center">
<span class="mb-1">{{ __("Gitlab") }}</span>
</div>
<div class="flex items-center">
<div class="inline">
@if($sourceControl)
<x-secondary-button x-on:click="$dispatch('open-modal', 'connect-gitlab')">{{ __("Modify") }}</x-secondary-button>
@else
<x-primary-button x-on:click="$dispatch('open-modal', 'connect-gitlab')">{{ __("Connect") }}</x-primary-button>
@endif
</div>
</div>
</x-item-card>
<x-modal name="connect-gitlab">
<form wire:submit.prevent="connect" class="p-6">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('Connect to Gitlab') }}
</h2>
<div class="mt-6">
<x-input-label for="token" :value="__('Access Token')" />
<x-text-input wire:model.defer="token" id="token" name="token" type="text" :value="$sourceControl ? $sourceControl->token : ''" class="mt-1 w-full" />
@error('token')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6 flex items-center justify-end">
@if (session('status') === 'gitlab-updated')
<p class="mr-2">{{ __('Updated') }}</p>
@endif
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __('Cancel') }}
</x-secondary-button>
<x-primary-button class="ml-3" @connected.window="$dispatch('close')">
{{ __('Connect') }}
</x-primary-button>
</div>
</form>
</x-modal>
</div>

View File

@ -0,0 +1,12 @@
<svg class="w-10 h-10" viewBox="0 0 256 231" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
<defs>
<linearGradient x1="108.63338%" y1="13.818022%" x2="46.9265964%" y2="78.7761408%" id="linearGradient-1">
<stop stop-color="#0052CC" offset="18%"></stop>
<stop stop-color="#2684FF" offset="100%"></stop>
</linearGradient>
</defs>
<g fill="none">
<polygon points="101.272088 152.561281 154.720712 152.561281 167.622105 77.2417255 87.0600784 77.2417255"></polygon>
<path d="M8.30813067,0.000683498206 C5.88502974,-0.0305685468 3.57212663,1.01125669 1.98985644,2.84669011 C0.407586248,4.68212353 -0.282086001,7.12328571 0.105843921,9.51533612 L34.9245512,220.888266 C35.8200362,226.227525 40.4199456,230.153012 45.8335925,230.197861 L212.873162,230.197861 C216.936516,230.250159 220.425595,227.319332 221.075449,223.30794 L255.894156,9.55634756 C256.282086,7.16429714 255.592414,4.72313497 254.010144,2.88770154 C252.427873,1.05226812 250.11497,0.0104428869 247.691869,0.0416949319 L8.30813067,0.000683498206 Z M154.924006,152.768274 L101.609142,152.768274 L87.1731177,77.3482475 L167.842608,77.3482475 L154.924006,152.768274 Z" fill="#2684FF"></path>
<path d="M244.610824,77.2417255 L167.693776,77.2417255 L154.78548,152.601582 L101.513151,152.601582 L38.6108235,227.264801 C40.6045494,228.988786 43.1464609,229.94745 45.7820986,229.969396 L212.729383,229.969396 C216.789495,230.021652 220.275791,227.093164 220.925126,223.084972 L244.610824,77.2417255 Z" fill="url(#linearGradient-1)"></path>
</g> </svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,3 @@
<svg class="fill-current w-10 h-10" viewBox="0 0 256 250" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
<g><path d="M128.00106,0 C57.3172926,0 0,57.3066942 0,128.00106 C0,184.555281 36.6761997,232.535542 87.534937,249.460899 C93.9320223,250.645779 96.280588,246.684165 96.280588,243.303333 C96.280588,240.251045 96.1618878,230.167899 96.106777,219.472176 C60.4967585,227.215235 52.9826207,204.369712 52.9826207,204.369712 C47.1599584,189.574598 38.770408,185.640538 38.770408,185.640538 C27.1568785,177.696113 39.6458206,177.859325 39.6458206,177.859325 C52.4993419,178.762293 59.267365,191.04987 59.267365,191.04987 C70.6837675,210.618423 89.2115753,204.961093 96.5158685,201.690482 C97.6647155,193.417512 100.981959,187.77078 104.642583,184.574357 C76.211799,181.33766 46.324819,170.362144 46.324819,121.315702 C46.324819,107.340889 51.3250588,95.9223682 59.5132437,86.9583937 C58.1842268,83.7344152 53.8029229,70.715562 60.7532354,53.0843636 C60.7532354,53.0843636 71.5019501,49.6441813 95.9626412,66.2049595 C106.172967,63.368876 117.123047,61.9465949 128.00106,61.8978432 C138.879073,61.9465949 149.837632,63.368876 160.067033,66.2049595 C184.49805,49.6441813 195.231926,53.0843636 195.231926,53.0843636 C202.199197,70.715562 197.815773,83.7344152 196.486756,86.9583937 C204.694018,95.9223682 209.660343,107.340889 209.660343,121.315702 C209.660343,170.478725 179.716133,181.303747 151.213281,184.472614 C155.80443,188.444828 159.895342,196.234518 159.895342,208.176593 C159.895342,225.303317 159.746968,239.087361 159.746968,243.303333 C159.746968,246.709601 162.05102,250.70089 168.53925,249.443941 C219.370432,232.499507 256,184.536204 256,128.00106 C256,57.3066942 198.691187,0 128.00106,0 Z M47.9405593,182.340212 C47.6586465,182.976105 46.6581745,183.166873 45.7467277,182.730227 C44.8183235,182.312656 44.2968914,181.445722 44.5978808,180.80771 C44.8734344,180.152739 45.876026,179.97045 46.8023103,180.409216 C47.7328342,180.826786 48.2627451,181.702199 47.9405593,182.340212 Z M54.2367892,187.958254 C53.6263318,188.524199 52.4329723,188.261363 51.6232682,187.366874 C50.7860088,186.474504 50.6291553,185.281144 51.2480912,184.70672 C51.8776254,184.140775 53.0349512,184.405731 53.8743302,185.298101 C54.7115892,186.201069 54.8748019,187.38595 54.2367892,187.958254 Z M58.5562413,195.146347 C57.7719732,195.691096 56.4895886,195.180261 55.6968417,194.042013 C54.9125733,192.903764 54.9125733,191.538713 55.713799,190.991845 C56.5086651,190.444977 57.7719732,190.936735 58.5753181,192.066505 C59.3574669,193.22383 59.3574669,194.58888 58.5562413,195.146347 Z M65.8613592,203.471174 C65.1597571,204.244846 63.6654083,204.03712 62.5716717,202.981538 C61.4524999,201.94927 61.1409122,200.484596 61.8446341,199.710926 C62.5547146,198.935137 64.0575422,199.15346 65.1597571,200.200564 C66.2704506,201.230712 66.6095936,202.705984 65.8613592,203.471174 Z M75.3025151,206.281542 C74.9930474,207.284134 73.553809,207.739857 72.1039724,207.313809 C70.6562556,206.875043 69.7087748,205.700761 70.0012857,204.687571 C70.302275,203.678621 71.7478721,203.20382 73.2083069,203.659543 C74.6539041,204.09619 75.6035048,205.261994 75.3025151,206.281542 Z M86.046947,207.473627 C86.0829806,208.529209 84.8535871,209.404622 83.3316829,209.4237 C81.8013,209.457614 80.563428,208.603398 80.5464708,207.564772 C80.5464708,206.498591 81.7483088,205.631657 83.2786917,205.606221 C84.8005962,205.576546 86.046947,206.424403 86.046947,207.473627 Z M96.6021471,207.069023 C96.7844366,208.099171 95.7267341,209.156872 94.215428,209.438785 C92.7295577,209.710099 91.3539086,209.074206 91.1652603,208.052538 C90.9808515,206.996955 92.0576306,205.939253 93.5413813,205.66582 C95.054807,205.402984 96.4092596,206.021919 96.6021471,207.069023 Z" fill="current"></path></g>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -0,0 +1,10 @@
<svg class="w-10 h-10" viewBox="0 0 256 236" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
<g>
<path d="M128.07485,236.074667 L128.07485,236.074667 L175.17885,91.1043048 L80.9708495,91.1043048 L128.07485,236.074667 L128.07485,236.074667 Z" fill="#E24329"></path>
<path d="M128.07485,236.074423 L80.9708495,91.104061 L14.9557638,91.104061 L128.07485,236.074423 L128.07485,236.074423 Z" fill="#FC6D26"></path>
<path d="M14.9558857,91.1044267 L14.9558857,91.1044267 L0.641828571,135.159589 C-0.663771429,139.17757 0.766171429,143.57955 4.18438095,146.06275 L128.074971,236.074789 L14.9558857,91.1044267 L14.9558857,91.1044267 Z" fill="#FCA326"></path>
<path d="M14.9558857,91.1045486 L80.9709714,91.1045486 L52.6000762,3.79026286 C51.1408762,-0.703146667 44.7847619,-0.701927619 43.3255619,3.79026286 L14.9558857,91.1045486 L14.9558857,91.1045486 Z" fill="#E24329"></path>
<path d="M128.07485,236.074423 L175.17885,91.104061 L241.193935,91.104061 L128.07485,236.074423 L128.07485,236.074423 Z" fill="#FC6D26"></path>
<path d="M241.193935,91.1044267 L241.193935,91.1044267 L255.507992,135.159589 C256.813592,139.17757 255.38365,143.57955 251.96544,146.06275 L128.07485,236.074789 L241.193935,91.1044267 L241.193935,91.1044267 Z" fill="#FCA326"></path>
<path d="M241.193935,91.1045486 L175.17885,91.1045486 L203.549745,3.79026286 C205.008945,-0.703146667 211.365059,-0.701927619 212.824259,3.79026286 L241.193935,91.1045486 L241.193935,91.1045486 Z" fill="#E24329"></path>
</g> </svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,39 @@
<div>
<x-primary-button x-data="" x-on:click.prevent="$dispatch('open-modal', 'add-key')">
{{ __('Add new Key') }}
</x-primary-button>
<x-modal name="add-key">
<form wire:submit.prevent="add" class="p-6">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('Add new Key') }}
</h2>
<div class="mt-6">
<x-input-label for="name" :value="__('Name')" />
<x-text-input wire:model.defer="name" id="name" name="name" type="text" class="mt-1 w-full" />
@error('name')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6">
<x-input-label for="public_key" :value="__('Public Key')" />
<x-textarea wire:model.defer="public_key" id="public_key" name="public_key" class="mt-1 w-full" rows="5" />
@error('public_key')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6 flex justify-end">
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __('Cancel') }}
</x-secondary-button>
<x-primary-button class="ml-3" @added.window="$dispatch('close')">
{{ __('Add') }}
</x-primary-button>
</div>
</form>
</x-modal>
</div>

View File

@ -0,0 +1,42 @@
<div>
<x-card-header>
<x-slot name="title">{{ __("SSH Keys") }}</x-slot>
<x-slot name="description">{{ __("Add or modify your ssh keys") }}</x-slot>
<x-slot name="aside">
<livewire:ssh-keys.add-key />
</x-slot>
</x-card-header>
<div x-data="" class="space-y-3">
@if(count($keys) > 0)
@foreach($keys as $key)
<x-item-card>
<div class="flex flex-grow flex-col items-start justify-center">
<span class="mb-1">{{ $key->name }}</span>
<span class="text-sm text-gray-400">
<x-datetime :value="$key->created_at" />
</span>
</div>
<div class="flex items-center">
<div class="inline">
<x-icon-button x-on:click="$wire.deleteId = '{{ $key->id }}'; $dispatch('open-modal', 'delete-key')">
<x-heroicon-o-trash class="w-4 h-4" />
</x-icon-button>
</div>
</div>
</x-item-card>
@endforeach
<x-confirm-modal
name="delete-key"
:title="__('Confirm')"
:description="__('Are you sure that you want to delete this key?')"
method="delete"
/>
@else
<x-simple-card>
<div class="text-center">
{{ __("You haven't connected to any keys yet!") }}
</div>
</x-simple-card>
@endif
</div>
</div>

View File

@ -0,0 +1,54 @@
<div>
<x-primary-button x-data="" x-on:click.prevent="$dispatch('open-modal', 'create-ssl')">
{{ __('Create SSL') }}
</x-primary-button>
<x-modal name="create-ssl">
<form wire:submit.prevent="create" class="p-6">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('Create SSL') }}
</h2>
<div class="mt-6">
<x-input-label for="type" :value="__('SSL Type')" />
<x-select-input wire:model="type" id="type" name="type" class="mt-1 w-full">
<option value="" selected disabled>{{ __("Select") }}</option>
@foreach(\App\Enums\SslType::getValues() as $t)
<option value="{{ $t }}" @if($t === $type) selected @endif>{{ $t }}</option>
@endforeach
</x-select-input>
@error('type')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
@if($type === \App\Enums\SslType::CUSTOM)
<div class="mt-6">
<x-input-label for="certificate" :value="__('Certificate')" />
<x-textarea wire:model.defer="certificate" id="certificate" name="certificate" type="text" class="mt-1 w-full" rows="5" />
@error('certificate')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
<div class="mt-6">
<x-input-label for="private" :value="__('Private Key')" />
<x-textarea wire:model.defer="private" id="private" name="private" type="text" class="mt-1 w-full" rows="5" />
@error('private')
<x-input-error class="mt-2" :messages="$message" />
@enderror
</div>
@endif
<div class="mt-6 flex justify-end">
<x-secondary-button type="button" x-on:click="$dispatch('close')">
{{ __('Cancel') }}
</x-secondary-button>
<x-primary-button class="ml-3" @created.window="$dispatch('close')">
{{ __('Create') }}
</x-primary-button>
</div>
</form>
</x-modal>
</div>

View File

@ -0,0 +1,12 @@
@if($status == \App\Enums\SslStatus::CREATED)
<x-status status="success">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\SslStatus::CREATING)
<x-status status="warning">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\SslStatus::DELETING)
<x-status status="danger">{{ $status }}</x-status>
@endif
@if($status == \App\Enums\SslStatus::FAILED)
<x-status status="danger">{{ $status }}</x-status>
@endif

View File

@ -0,0 +1,54 @@
<div>
<x-card-header>
<x-slot name="title">{{ __("SSLs") }}</x-slot>
<x-slot name="description">{{ __("Here you can manage your site's SSL certificates") }}</x-slot>
<x-slot name="aside">
<livewire:ssl.create-ssl :site="$site" />
</x-slot>
</x-card-header>
<div x-data="" class="space-y-3">
@if(count($ssls) > 0)
<x-table>
<tr>
<x-th>{{ __("Type") }}</x-th>
<x-th>{{ __("Created") }}</x-th>
<x-th>{{ __("Expires at") }}</x-th>
<x-th></x-th>
</tr>
@foreach($ssls as $ssl)
<tr>
<x-td>{{ $ssl->type }}</x-td>
<x-td>
<x-datetime :value="$ssl->created_at" />
</x-td>
<x-td>
<x-datetime :value="$ssl->expires_at" />
</x-td>
<x-td>
<div class="flex items-center">
@include('livewire.ssl.partials.status', ['status' => $ssl->status])
<div class="inline">
<x-icon-button x-on:click="$wire.deleteId = '{{ $ssl->id }}'; $dispatch('open-modal', 'delete-ssl')">
<x-heroicon-o-trash class="w-4 h-4" />
</x-icon-button>
</div>
</div>
</x-td>
</tr>
@endforeach
</x-table>
<x-confirm-modal
name="delete-ssl"
:title="__('Confirm')"
:description="__('Are you sure that you want to delete this SSL certificate?')"
method="delete"
/>
@else
<x-simple-card>
<div class="text-center">
{{ __("You don't have any SSL certificates yet!") }}
</div>
</x-simple-card>
@endif
</div>
</div>

View File

@ -0,0 +1,31 @@
<div class="hidden sm:flex sm:items-center sm:ml-6">
<x-dropdown align="right" width="48">
<x-slot name="trigger">
<button class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 dark:text-gray-400 bg-white dark:bg-gray-800 hover:text-gray-700 dark:hover:text-gray-300 focus:outline-none transition ease-in-out duration-150">
<div>{{ Auth::user()->name }}</div>
<div class="ml-1">
<svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</div>
</button>
</x-slot>
<x-slot name="content">
<x-dropdown-link :href="route('profile')">
<x-heroicon-o-user class="w-6 h-6 mr-1" />
{{ __('Profile') }}
</x-dropdown-link>
<!-- Authentication -->
<form method="POST" action="{{ route('logout') }}">
@csrf
<x-dropdown-link :href="route('logout')" onclick="event.preventDefault(); this.closest('form').submit();">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 mr-1">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15M12 9l-3 3m0 0l3 3m-3-3h12.75" />
</svg>
{{ __('Log Out') }}
</x-dropdown-link>
</form>
</x-slot>
</x-dropdown>
</div>