Merge branch 'main' into fix-typos
This commit is contained in:
@@ -1,3 +0,0 @@
|
||||
<x-layout-simple>
|
||||
<livewire:force-password-reset />
|
||||
</x-layout-simple>
|
||||
@@ -13,8 +13,8 @@
|
||||
href="{{ route('project.application.logs', $parameters) }}">
|
||||
<button>Logs</button>
|
||||
</a>
|
||||
<a class="{{ request()->routeIs('project.application.deployments') ? 'text-white' : '' }}"
|
||||
href="{{ route('project.application.deployments', $parameters) }}">
|
||||
<a class="{{ request()->routeIs('project.application.deployment.index') ? 'text-white' : '' }}"
|
||||
href="{{ route('project.application.deployment.index', $parameters) }}">
|
||||
<button>Deployments</button>
|
||||
</a>
|
||||
<x-applications.links :application="$application" />
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
$database->getMorphClass() === 'App\Models\StandaloneMongodb' ||
|
||||
$database->getMorphClass() === 'App\Models\StandaloneMysql' ||
|
||||
$database->getMorphClass() === 'App\Models\StandaloneMariadb')
|
||||
<a class="{{ request()->routeIs('project.database.backups.all') ? 'text-white' : '' }}"
|
||||
href="{{ route('project.database.backups.all', $parameters) }}">
|
||||
<a class="{{ request()->routeIs('project.database.backup.index') ? 'text-white' : '' }}"
|
||||
href="{{ route('project.database.backup.index', $parameters) }}">
|
||||
<button>Backups</button>
|
||||
</a>
|
||||
@endif
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<a class="text-xs truncate lg:text-sm"
|
||||
href="{{ route('project.resources', ['environment_name' => $this->parameters['environment_name'], 'project_uuid' => $this->parameters['project_uuid']]) }}">{{ $this->parameters['environment_name'] }}</a>
|
||||
href="{{ route('project.resource.index', ['environment_name' => $this->parameters['environment_name'], 'project_uuid' => $this->parameters['project_uuid']]) }}">{{ $this->parameters['environment_name'] }}</a>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<h1>Settings</h1>
|
||||
<div class="subtitle">Instance wide settings for Coolify.</div>
|
||||
<nav class="navbar-main">
|
||||
<a class="{{ request()->routeIs('settings.configuration') ? 'text-white' : '' }}"
|
||||
href="{{ route('settings.configuration') }}">
|
||||
<a class="{{ request()->routeIs('settings.index') ? 'text-white' : '' }}"
|
||||
href="{{ route('settings.index') }}">
|
||||
<button>Configuration</button>
|
||||
</a>
|
||||
@if (isCloud())
|
||||
|
||||
@@ -17,15 +17,15 @@
|
||||
<a class="{{ request()->routeIs('team.index') ? 'text-white' : '' }}" href="{{ route('team.index') }}">
|
||||
<button>General</button>
|
||||
</a>
|
||||
<a class="{{ request()->routeIs('team.members') ? 'text-white' : '' }}" href="{{ route('team.members') }}">
|
||||
<a class="{{ request()->routeIs('team.member.index') ? 'text-white' : '' }}" href="{{ route('team.member.index') }}">
|
||||
<button>Members</button>
|
||||
</a>
|
||||
<a class="{{ request()->routeIs('team.storages.all') ? 'text-white' : '' }}"
|
||||
href="{{ route('team.storages.all') }}">
|
||||
<a class="{{ request()->routeIs('team.storage.index') ? 'text-white' : '' }}"
|
||||
href="{{ route('team.storage.index') }}">
|
||||
<button>S3 Storages</button>
|
||||
</a>
|
||||
<a class="{{ request()->routeIs('team.notifications') ? 'text-white' : '' }}"
|
||||
href="{{ route('team.notifications') }}">
|
||||
<a class="{{ request()->routeIs('team.notification.index') ? 'text-white' : '' }}"
|
||||
href="{{ route('team.notification.index') }}">
|
||||
<button>Notifications</button>
|
||||
</a>
|
||||
<div class="flex-1"></div>
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<x-emails.layout>
|
||||
@if ($pull_request_id === 0)
|
||||
Failed to deploy a new version of {{ $name }} at [{{ $fqdn }}]({{ $fqdn }}) .
|
||||
@else
|
||||
Failed to deploy a pull request #{{ $pull_request_id }} of {{ $name }} at
|
||||
[{{ $fqdn }}]({{ $fqdn }}).
|
||||
@endif
|
||||
|
||||
[View Deployment Logs]({{ $deployment_url }})
|
||||
@if ($pull_request_id === 0)
|
||||
Failed to deploy a new version of {{ $name }} at [{{ $fqdn }}]({{ $fqdn }}) .
|
||||
@else
|
||||
Failed to deploy a pull request #{{ $pull_request_id }} of {{ $name }} at
|
||||
[{{ $fqdn }}]({{ $fqdn }}).
|
||||
@endif
|
||||
|
||||
[View Deployment Logs]({{ $deployment_url }})
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<x-emails.layout>
|
||||
@if ($pull_request_id === 0)
|
||||
A new version of {{ $name }} is available at [{{ $fqdn }}]({{ $fqdn }}) .
|
||||
@else
|
||||
Pull request #{{ $pull_request_id }} of {{ $name }} deployed successfully
|
||||
[{{ $fqdn }}]({{ $fqdn }}).
|
||||
@endif
|
||||
@if ($pull_request_id === 0)
|
||||
A new version of {{ $name }} is available at [{{ $fqdn }}]({{ $fqdn }}) .
|
||||
@else
|
||||
Pull request #{{ $pull_request_id }} of {{ $name }} deployed successfully
|
||||
[{{ $fqdn }}]({{ $fqdn }}).
|
||||
@endif
|
||||
|
||||
[View Deployment Logs]({{ $deployment_url }})
|
||||
[View Deployment Logs]({{ $deployment_url }})
|
||||
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
<x-emails.layout>
|
||||
{{ $name }} has been stopped.
|
||||
|
||||
{{ $name }} has been stopped.
|
||||
|
||||
If it was your intention to stop this application, you can ignore this email.
|
||||
|
||||
If not, [check what is going on]({{ $application_url }}).
|
||||
If it was your intention to stop this application, you can ignore this email.
|
||||
|
||||
If not, [check what is going on]({{ $application_url }}).
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<x-emails.layout>
|
||||
Database backup for {{ $name }} with frequency of {{ $frequency }} was FAILED.
|
||||
Database backup for {{ $name }} with frequency of {{ $frequency }} was FAILED.
|
||||
|
||||
### Reason
|
||||
|
||||
{{ $output }}
|
||||
### Reason
|
||||
|
||||
{{ $output }}
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<x-emails.layout>
|
||||
Database backup for {{ $name }} with frequency of {{ $frequency }} was successful.
|
||||
Database backup for {{ $name }} with frequency of {{ $frequency }} was successful.
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
<x-emails.layout>
|
||||
We would like to inform you that a {{ config('constants.limits.trial_period') }} days of trial has been added to all
|
||||
subscription plans.
|
||||
We would like to inform you that a {{ config('constants.limits.trial_period') }} days of trial has been added to all subscription plans.
|
||||
|
||||
You can try out Coolify, without payment information for free. If you like it, you can upgrade to a paid plan at any
|
||||
time.
|
||||
You can try out Coolify, without payment information for free. If you like it, you can upgrade to a paid plan at any time.
|
||||
|
||||
[Click here](https://app.coolify.io/subscription) to start your trial.
|
||||
[Click here](https://app.coolify.io/subscription) to start your trial.
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
<x-emails.layout>
|
||||
A resource ({{ $containerName }}) has been restarted automatically on {{ $serverName }}, because it was stopped unexpectedly.
|
||||
|
||||
A service ({{ $containerName }}) has been restarted automatically on {{ $serverName }}, because it was stopped
|
||||
unexpectedly.
|
||||
|
||||
@if ($containerName === 'coolify-proxy')
|
||||
Coolify Proxy should run on your server as you have FQDNs set up in one of your resources.
|
||||
|
||||
If you don't want to use Coolify Proxy, please remove FQDN from your resources or set Proxy type to
|
||||
Custom(None).
|
||||
@endif
|
||||
@if ($containerName === 'coolify-proxy')
|
||||
Coolify Proxy should run on your server as you have FQDNs set up in one of your resources.
|
||||
|
||||
If you don't want to use Coolify Proxy, please remove FQDN from your resources or set Proxy type to Custom(None).
|
||||
@endif
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
<x-emails.layout>
|
||||
A resource ({{ $containerName }}) has been stopped unexpectedly on {{ $serverName }}.
|
||||
|
||||
A service ({{ $containerName }}) has been stopped unexpectedly on {{ $serverName }}.
|
||||
|
||||
@if ($url)
|
||||
Please check what is going on [here]({{ $url }}).
|
||||
@endif
|
||||
|
||||
@if ($url)
|
||||
Please check what is going on [here]({{ $url }}).
|
||||
@endif
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<x-emails.layout>
|
||||
Verify your email [here]({{ $url }}).
|
||||
Verify your email [here]({{ $url }}).
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
<x-emails.layout>
|
||||
Your server ({{ $name }}) has high disk usage ({{ $disk_usage }}% used). Threshold is {{ $threshold }}%.
|
||||
|
||||
Your server ({{ $name }}) has high disk usage ({{ $disk_usage }}% used). Threshold is
|
||||
{{ $threshold }}%.
|
||||
|
||||
Please cleanup your disk to prevent data-loss. Here are some [tips](https://coolify.io/docs/automated-cleanup).
|
||||
|
||||
(You can change the threshold in the Server Settings menu.)
|
||||
Please cleanup your disk to prevent data-loss. Here are some [tips](https://coolify.io/docs/automated-cleanup).
|
||||
|
||||
(You can change the threshold in the Server Settings menu.)
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
<x-emails.layout>
|
||||
You have been invited to "{{ $team }}" on "{{ config('app.name') }}".
|
||||
|
||||
You have been invited to "{{ $team }}" on "{{ config('app.name') }}".
|
||||
Please [click here]({{ $invitation_link }}) to accept the invitation.
|
||||
|
||||
Please [click here]({{ $invitation_link }}) to accept the invitation.
|
||||
If you have any questions, please contact the team owner.<br><br>
|
||||
|
||||
If you have any questions, please contact the team owner.<br><br>
|
||||
|
||||
If it was not you who requested this invitation, please ignore this email.
|
||||
If it was not you who requested this invitation, please ignore this email.
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<x-emails.layout>
|
||||
A password reset has been requested for this email address.
|
||||
A password reset has been requested for this email address.
|
||||
|
||||
Click [here]({{ $url }}) to reset your password.
|
||||
Click [here]({{ $url }}) to reset your password.
|
||||
|
||||
This link will expire in {{ $count }} minutes.
|
||||
This link will expire in {{ $count }} minutes.
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<x-emails.layout>
|
||||
Connection could not be established with one of your S3 Storage ({{ $name }}). Please fix it
|
||||
[here]({{ $url }}).
|
||||
|
||||
{{ $reason }}
|
||||
Connection could not be established with one of your S3 Storage ({{ $name }}). Please fix it [here]({{ $url }}).
|
||||
|
||||
{{ $reason }}
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
<x-emails.layout>
|
||||
Coolify cannot connect to your server ({{ $name }}). Please check your server and make sure it is running.
|
||||
|
||||
Coolify cannot connect to your server ({{ $name }}). Please check your server and make sure it is running.
|
||||
All automations & integrations are turned off!
|
||||
|
||||
All automations & integrations are turned off!
|
||||
|
||||
IMPORTANT: We automatically try to revive your server. If your server is back online, we will automatically turn on
|
||||
all automations & integrations.
|
||||
|
||||
If you have any questions, please contact us.
|
||||
IMPORTANT: We automatically try to revive your server. If your server is back online, we will automatically turn onall automations & integrations.
|
||||
|
||||
If you have any questions, please contact us.
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
<x-emails.layout>
|
||||
|
||||
Your server ({{ $name }}) was offline for a while, but it is back online now. All automations & integrations
|
||||
are turned on again.
|
||||
|
||||
Your server ({{ $name }}) was offline for a while, but it is back online now. All automations & integrationsare turned on again.
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<x-emails.layout>
|
||||
Your last invoice has failed to be paid for Coolify Cloud.
|
||||
|
||||
Please update payment details [here]({{ $stripeCustomerPortal }}).
|
||||
Your last invoice has failed to be paid for Coolify Cloud.
|
||||
|
||||
Please update payment details [here]({{ $stripeCustomerPortal }}).
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<x-emails.layout>
|
||||
If you are seeing this, it means that your Email settings are correct.
|
||||
If you are seeing this, it means that your Email settings are correct.
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
<x-emails.layout>
|
||||
Your trial ended. All automations and integrations are disabled for all of your servers.
|
||||
|
||||
Your trial ended. All automations and integrations are disabled for all of your servers.
|
||||
|
||||
Please update payment details [here]({{ $stripeCustomerPortal }}) or in [Coolify Cloud](https://app.coolify.io) to
|
||||
continue using our services.
|
||||
|
||||
Please update payment details [here]({{ $stripeCustomerPortal }}) or in [Coolify Cloud](https://app.coolify.io) to continue using our services.
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
<x-emails.layout>
|
||||
Your trial ends soon. Please update payment details [here]({{ $stripeCustomerPortal }}),
|
||||
|
||||
Your trial ends soon. Please update payment details [here]({{ $stripeCustomerPortal }}),
|
||||
|
||||
Your servers & deployed resources will be untouched, but you won't be able to deploy new resources and lost all
|
||||
automations and integrations.
|
||||
|
||||
Your servers & deployed resources will be untouched, but you won't be able to deploy new resources and lost all automations and integrations.
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
<x-emails.layout>
|
||||
|
||||
<br><br>
|
||||
If you do not like to receive these emails, you can unsubscribe [here]({{ $unsubscribeUrl }}).
|
||||
If you do not like to receive these emails, you can unsubscribe [here]({{ $unsubscribeUrl }}).
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
<x-emails.layout>
|
||||
Someone added this email to the Coolify Cloud's waitlist. [Click here]({{ $confirmation_url }}) to confirm!
|
||||
Someone added this email to the Coolify Cloud's waitlist. [Click here]({{ $confirmation_url }}) to confirm!
|
||||
|
||||
The link will expire in {{ config('constants.waitlist.expiration') }} minutes.
|
||||
|
||||
|
||||
You have no idea what [Coolify Cloud](https://coolify.io) is or this waitlist? [Click here]({{ $cancel_url }}) to
|
||||
remove you from the waitlist.
|
||||
The link will expire in {{ config('constants.waitlist.expiration') }} minutes.
|
||||
|
||||
You have no idea what [Coolify Cloud](https://coolify.io) is or this waitlist? [Click here]({{ $cancel_url }}) to remove you from the waitlist.
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<x-emails.layout>
|
||||
You have been invited to join the Coolify Cloud: [Get Started]({{ $loginLink }})
|
||||
You have been invited to join the Coolify Cloud: [Get Started]({{ $loginLink }})
|
||||
</x-emails.layout>
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
<form wire:submit='submit' class="flex flex-col gap-2">
|
||||
<div>
|
||||
@if ($settings->is_resale_license_active)
|
||||
<div class="text-success">License is active</div>
|
||||
@else
|
||||
<div class="text-error">License is not active</div>
|
||||
@endif
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input type="password" id="settings.resale_license" placeholder="eg: BE558E91-0CC5-4AA2-B1C0-B6403C2988DD"
|
||||
label="License Key" />
|
||||
<x-forms.input type="password" id="instance_id" label="Instance Id (do not change this)" disabled />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.button type="submit">
|
||||
Check License
|
||||
</x-forms.button>
|
||||
</div>
|
||||
@if (session()->has('error'))
|
||||
<div class="text-error">
|
||||
{!! session('error') !!}
|
||||
</div>
|
||||
@endif
|
||||
</form>
|
||||
12
resources/views/livewire/command-center/index.blade.php
Normal file
12
resources/views/livewire/command-center/index.blade.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<div>
|
||||
<h1>Command Center</h1>
|
||||
<div class="subtitle">Execute commands on your servers without leaving the browser.</div>
|
||||
@if ($servers->count() > 0)
|
||||
<livewire:run-command :servers="$servers" />
|
||||
@else
|
||||
<div>
|
||||
<div>No servers found. Without a server, you won't be able to do much.</div>
|
||||
<x-use-magic-bar link="/server/new" />
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@@ -30,7 +30,7 @@
|
||||
<div class="gap-2 border border-transparent cursor-pointer box group">
|
||||
@if (data_get($project, 'environments.0.name'))
|
||||
<a class="flex flex-col flex-1 mx-6 hover:no-underline"
|
||||
href="{{ route('project.resources', ['project_uuid' => data_get($project, 'uuid'), 'environment_name' => data_get($project, 'environments.0.name', 'production')]) }}">
|
||||
href="{{ route('project.resource.index', ['project_uuid' => data_get($project, 'uuid'), 'environment_name' => data_get($project, 'environments.0.name', 'production')]) }}">
|
||||
<div class="font-bold text-white">{{ $project->name }}</div>
|
||||
<div class="description">
|
||||
{{ $project->description }}</div>
|
||||
@@ -45,7 +45,7 @@
|
||||
@endif
|
||||
<div class="flex items-center">
|
||||
<a class="mx-4 rounded group-hover:text-white hover:no-underline"
|
||||
href="{{ route('project.resources.new', ['project_uuid' => data_get($project, 'uuid'), 'environment_name' => data_get($project, 'environments.0.name', 'production')]) }}">
|
||||
href="{{ route('project.resource.create', ['project_uuid' => data_get($project, 'uuid'), 'environment_name' => data_get($project, 'environments.0.name', 'production')]) }}">
|
||||
<span class="font-bold hover:text-warning">+ New Resource</span>
|
||||
</a>
|
||||
<a class="mx-4 rounded group-hover:text-white"
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
<div x-data="{ showPrivateKey: false }">
|
||||
<x-modal yesOrNo modalId="deletePrivateKey" modalTitle="Delete Private Key">
|
||||
<x-slot:modalBody>
|
||||
<p>This private key will be deleted. It is not reversible. <br>Please think again.</p>
|
||||
</x-slot:modalBody>
|
||||
</x-modal>
|
||||
<form class="flex flex-col gap-2" wire:submit='changePrivateKey'>
|
||||
<div class="flex items-end gap-2">
|
||||
<h2>Private Key</h2>
|
||||
<x-forms.button type="submit">
|
||||
Save
|
||||
</x-forms.button>
|
||||
@if ($private_key->id > 0)
|
||||
<x-forms.button isError isModal modalId="deletePrivateKey">
|
||||
Delete
|
||||
</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
<x-forms.input id="private_key.name" label="Name" required />
|
||||
<x-forms.input id="private_key.description" label="Description" />
|
||||
<div>
|
||||
<div class="flex items-end gap-2 py-2 ">
|
||||
<div class="pl-1 ">Public Key</div>
|
||||
</div>
|
||||
<x-forms.input readonly id="public_key" />
|
||||
<div class="flex items-end gap-2 py-2 ">
|
||||
<div class="pl-1 ">Private Key <span class='text-helper'>*</span></div>
|
||||
<div class="text-xs text-white underline cursor-pointer" x-cloak x-show="!showPrivateKey"
|
||||
x-on:click="showPrivateKey = true">
|
||||
Edit
|
||||
</div>
|
||||
<div class="text-xs text-white underline cursor-pointer" x-cloak x-show="showPrivateKey"
|
||||
x-on:click="showPrivateKey = false">
|
||||
Hide
|
||||
</div>
|
||||
</div>
|
||||
@if ($private_key->is_git_related)
|
||||
<div class="w-48">
|
||||
<x-forms.checkbox id="private_key.is_git_related" disabled label="Is used by a Git App?" />
|
||||
</div>
|
||||
@endif
|
||||
<div x-cloak x-show="!showPrivateKey">
|
||||
<x-forms.input allowToPeak="false" type="password" rows="10" id="private_key.private_key" required
|
||||
disabled />
|
||||
</div>
|
||||
<div x-cloak x-show="showPrivateKey">
|
||||
<x-forms.textarea rows="10" id="private_key.private_key" required />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
@@ -1,12 +0,0 @@
|
||||
<div>
|
||||
<form wire:submit='submit' class="flex flex-col">
|
||||
<div class="flex items-center gap-2">
|
||||
<h2>General</h2>
|
||||
<x-forms.button type="submit" label="Save">Save</x-forms.button>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="name" label="Name" required />
|
||||
<x-forms.input id="email" label="Email" readonly />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
92
resources/views/livewire/profile/index.blade.php
Normal file
92
resources/views/livewire/profile/index.blade.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<div>
|
||||
<h1>Profile</h1>
|
||||
<div class="subtitle ">Your user profile settings.</div>
|
||||
<form wire:submit='submit' class="flex flex-col">
|
||||
<div class="flex items-center gap-2">
|
||||
<h2>General</h2>
|
||||
<x-forms.button type="submit" label="Save">Save</x-forms.button>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="name" label="Name" required />
|
||||
<x-forms.input id="email" label="Email" readonly />
|
||||
</div>
|
||||
</form>
|
||||
<h2 class="py-4">Subscription</h2>
|
||||
<a href="{{ route('team.index') }}">Check in Team Settings</a>
|
||||
<h2 class="py-4">Two-factor Authentication</h2>
|
||||
@if (session('status') == 'two-factor-authentication-enabled')
|
||||
<div class="mb-4 font-medium">
|
||||
Please finish configuring two factor authentication below. Read the QR code or enter the secret key
|
||||
manually.
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<form action="/user/confirmed-two-factor-authentication" method="POST" class="flex items-end gap-2">
|
||||
@csrf
|
||||
<x-forms.input type="number" id="code" label="One-time code" required />
|
||||
<x-forms.button type="submit">Validate 2FA</x-forms.button>
|
||||
</form>
|
||||
<div>
|
||||
<div>{!! request()->user()->twoFactorQrCodeSvg() !!}</div>
|
||||
<div x-data="{ showCode: false }" class="py-2">
|
||||
<template x-if="showCode">
|
||||
<div class="py-2 ">{!! decrypt(request()->user()->two_factor_secret) !!}</div>
|
||||
</template>
|
||||
<x-forms.button x-on:click="showCode = !showCode">Show secret key to manually
|
||||
enter</x-forms.button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@elseif(session('status') == 'two-factor-authentication-confirmed')
|
||||
<div class="mb-4 ">
|
||||
Two factor authentication confirmed and enabled successfully.
|
||||
</div>
|
||||
<div>
|
||||
<div class="pb-6 ">Here are the recovery codes for your account. Please store them in a secure
|
||||
location.
|
||||
</div>
|
||||
<div class="text-white">
|
||||
@foreach (request()->user()->recoveryCodes() as $code)
|
||||
<div>{{ $code }}</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
@if (request()->user()->two_factor_confirmed_at)
|
||||
<div class="pb-4 "> Two factor authentication is <span class="text-helper">enabled</span>.</div>
|
||||
<div class="flex gap-2">
|
||||
<form action="/user/two-factor-authentication" method="POST">
|
||||
@csrf
|
||||
@method ('DELETE')
|
||||
<x-forms.button type="submit">Disable</x-forms.button>
|
||||
</form>
|
||||
<form action="/user/two-factor-recovery-codes" method="POST">
|
||||
@csrf
|
||||
<x-forms.button type="submit">Regenerate Recovery Codes</x-forms.button>
|
||||
</form>
|
||||
</div>
|
||||
@if (session('status') == 'recovery-codes-generated')
|
||||
<div>
|
||||
<div class="py-6 ">Here are the recovery codes for your account. Please store them in a
|
||||
secure
|
||||
location.
|
||||
</div>
|
||||
<div class="text-white">
|
||||
@foreach (request()->user()->recoveryCodes() as $code)
|
||||
<div>{{ $code }}</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@else
|
||||
<form action="/user/two-factor-authentication" method="POST">
|
||||
@csrf
|
||||
<x-forms.button type="submit">Configure 2FA</x-forms.button>
|
||||
</form>
|
||||
@endif
|
||||
@endif
|
||||
@if (session()->has('errors'))
|
||||
<div class="text-error">
|
||||
Something went wrong. Please try again.
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@@ -2,7 +2,7 @@
|
||||
<h1>Configuration</h1>
|
||||
<livewire:project.application.heading :application="$application" />
|
||||
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'general' }" class="flex h-full pt-6">
|
||||
<div class="flex flex-col gap-4 min-w-fit">
|
||||
<div class="flex flex-col gap-4 xl:w-48">
|
||||
<a :class="activeTab === 'general' && 'text-white'"
|
||||
@click.prevent="activeTab = 'general'; window.location.hash = 'general'" href="#">General</a>
|
||||
@if ($application->destination->server->isSwarm())
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
<div class="pt-4" x-data="{ fullscreen: false, alwaysScroll: false, intervalId: null }">
|
||||
<livewire:project.application.deployment-navbar :application_deployment_queue="$application_deployment_queue" />
|
||||
@if (data_get($application_deployment_queue, 'status') === 'in_progress')
|
||||
<div class="flex items-center gap-1 pt-2 ">Deployment is
|
||||
<div class="text-warning"> {{ Str::headline(data_get($this->application_deployment_queue, 'status')) }}.
|
||||
</div>
|
||||
<x-loading class="loading-ring" />
|
||||
</div>
|
||||
{{-- <div class="">Logs will be updated automatically.</div> --}}
|
||||
@else
|
||||
<div class="pt-2 ">Deployment is <span
|
||||
class="text-warning">{{ Str::headline(data_get($application_deployment_queue, 'status')) }}</span>.
|
||||
</div>
|
||||
@endif
|
||||
<div id="screen" :class="fullscreen ? 'fullscreen' : ''">
|
||||
<div @if ($isKeepAliveOn) wire:poll.2000ms="polling" @endif
|
||||
class="relative flex flex-col-reverse w-full p-2 px-4 mt-4 overflow-y-auto text-white bg-coolgray-100 scrollbar border-coolgray-300"
|
||||
:class="fullscreen ? '' : 'max-h-[40rem] border border-dotted rounded'">
|
||||
<button title="Minimize" x-show="fullscreen" class="fixed top-4 right-4" x-on:click="makeFullscreen"><svg
|
||||
class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||
stroke-width="2" d="M6 14h4m0 0v4m0-4l-6 6m14-10h-4m0 0V6m0 4l6-6" />
|
||||
</svg></button>
|
||||
<button title="Go Top" x-show="fullscreen" class="fixed top-4 right-28" x-on:click="goTop"> <svg
|
||||
class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||
stroke-width="2" d="M12 5v14m4-10l-4-4M8 9l4-4" />
|
||||
</svg></button>
|
||||
<button title="Follow Logs" x-show="fullscreen" :class="alwaysScroll ? 'text-warning' : ''"
|
||||
class="fixed top-4 right-16" x-on:click="toggleScroll"><svg class="icon" viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||
stroke-width="2" d="M12 5v14m4-4l-4 4m-4-4l4 4" />
|
||||
</svg></button>
|
||||
|
||||
<button title="Fullscreen" x-show="!fullscreen" class="absolute top-2 right-8"
|
||||
x-on:click="makeFullscreen"><svg class="fixed icon" viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="none">
|
||||
<path
|
||||
d="M24 0v24H0V0h24ZM12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035c-.01-.004-.019-.001-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427c-.002-.01-.009-.017-.017-.018Zm.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093c.012.004.023 0 .029-.008l.004-.014l-.034-.614c-.003-.012-.01-.02-.02-.022Zm-.715.002a.023.023 0 0 0-.027.006l-.006.014l-.034.614c0 .012.007.02.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01l-.184-.092Z" />
|
||||
<path fill="currentColor"
|
||||
d="M9.793 12.793a1 1 0 0 1 1.497 1.32l-.083.094L6.414 19H9a1 1 0 0 1 .117 1.993L9 21H4a1 1 0 0 1-.993-.883L3 20v-5a1 1 0 0 1 1.993-.117L5 15v2.586l4.793-4.793ZM20 3a1 1 0 0 1 .993.883L21 4v5a1 1 0 0 1-1.993.117L19 9V6.414l-4.793 4.793a1 1 0 0 1-1.497-1.32l.083-.094L17.586 5H15a1 1 0 0 1-.117-1.993L15 3h5Z" />
|
||||
</g>
|
||||
</svg></button>
|
||||
<div id="logs" class="flex flex-col">
|
||||
@if (decode_remote_command_output($application_deployment_queue)->count() > 0)
|
||||
@foreach (decode_remote_command_output($application_deployment_queue) as $line)
|
||||
<div @class([
|
||||
'font-mono whitespace-pre-line',
|
||||
'text-warning' => $line['hidden'],
|
||||
'text-red-500' => $line['type'] == 'stderr',
|
||||
])>[{{ $line['timestamp'] }}] @if ($line['hidden'])
|
||||
<br>COMMAND: <br>{{ $line['command'] }} <br><br>OUTPUT:
|
||||
@endif{{ $line['output'] }}@if ($line['hidden'])
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
@else
|
||||
<span class="font-mono text-neutral-400">No logs yet.</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
function makeFullscreen() {
|
||||
this.fullscreen = !this.fullscreen;
|
||||
if (this.fullscreen === false) {
|
||||
this.alwaysScroll = false;
|
||||
clearInterval(this.intervalId);
|
||||
}
|
||||
}
|
||||
|
||||
function toggleScroll() {
|
||||
this.alwaysScroll = !this.alwaysScroll;
|
||||
|
||||
if (this.alwaysScroll) {
|
||||
this.intervalId = setInterval(() => {
|
||||
const screen = document.getElementById('screen');
|
||||
const logs = document.getElementById('logs');
|
||||
if (screen.scrollTop !== logs.scrollHeight) {
|
||||
screen.scrollTop = logs.scrollHeight;
|
||||
}
|
||||
}, 100);
|
||||
} else {
|
||||
clearInterval(this.intervalId);
|
||||
this.intervalId = null;
|
||||
}
|
||||
}
|
||||
|
||||
function goTop() {
|
||||
this.alwaysScroll = false;
|
||||
clearInterval(this.intervalId);
|
||||
const screen = document.getElementById('screen');
|
||||
screen.scrollTop = 0;
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
@@ -0,0 +1,105 @@
|
||||
<div>
|
||||
<h1>Deployments</h1>
|
||||
<livewire:project.application.heading :application="$application" />
|
||||
{{-- <livewire:project.application.deployment.show :application="$application" :deployments="$deployments" :deployments_count="$deployments_count" /> --}}
|
||||
<div class="flex flex-col gap-2 pb-10" @if ($skip == 0) wire:poll.5000ms='reload_deployments' @endif>
|
||||
<div class="flex items-end gap-2 pt-4">
|
||||
<h2>Deployments <span class="text-xs">({{ $deployments_count }})</span></h2>
|
||||
@if ($show_next)
|
||||
<x-forms.button wire:click="load_deployments({{ $default_take }})">Next Page
|
||||
</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
<form class="flex items-end gap-2">
|
||||
<x-forms.input id="pull_request_id" label="Pull Request"></x-forms.input>
|
||||
<x-forms.button type="submit">Filter</x-forms.button>
|
||||
</form>
|
||||
@forelse ($deployments as $deployment)
|
||||
<a @class([
|
||||
'bg-coolgray-100 p-2 border-l border-dashed transition-colors hover:no-underline',
|
||||
'hover:bg-coolgray-200' => data_get($deployment, 'status') === 'queued',
|
||||
'border-warning hover:bg-warning hover:text-black' =>
|
||||
data_get($deployment, 'status') === 'in_progress' ||
|
||||
data_get($deployment, 'status') === 'cancelled-by-user',
|
||||
'border-error hover:bg-error' =>
|
||||
data_get($deployment, 'status') === 'failed',
|
||||
'border-success hover:bg-success' =>
|
||||
data_get($deployment, 'status') === 'finished',
|
||||
]) href="{{ $current_url . '/' . data_get($deployment, 'deployment_uuid') }}"
|
||||
class="hover:no-underline">
|
||||
<div class="flex flex-col justify-start">
|
||||
<div class="flex gap-1">
|
||||
{{ $deployment->created_at }} UTC
|
||||
<span class=" text-warning">></span>
|
||||
{{ $deployment->status }}
|
||||
</div>
|
||||
@if (data_get($deployment, 'pull_request_id'))
|
||||
<div>
|
||||
<span class=" text-warning">></span>
|
||||
Pull Request #{{ data_get($deployment, 'pull_request_id') }}
|
||||
@if (data_get($deployment, 'is_webhook'))
|
||||
(Webhook)
|
||||
@endif
|
||||
Webhook (SHA
|
||||
@if (data_get($deployment, 'commit'))
|
||||
{{ data_get($deployment, 'commit') }})
|
||||
@else
|
||||
HEAD)
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col" x-data="elapsedTime('{{ $deployment->deployment_uuid }}', '{{ $deployment->status }}', '{{ $deployment->created_at }}', '{{ $deployment->updated_at }}')">
|
||||
<div>
|
||||
@if ($deployment->status !== 'in_progress')
|
||||
Finished <span x-text="measure_since_started()">0s</span> in
|
||||
@else
|
||||
Running for
|
||||
@endif
|
||||
<span class="font-bold" x-text="measure_finished_time()">0s</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
@empty
|
||||
<div class="">No deployments found</div>
|
||||
@endforelse
|
||||
<script src="https://cdn.jsdelivr.net/npm/dayjs@1/dayjs.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/dayjs@1/plugin/utc.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/dayjs@1/plugin/relativeTime.js"></script>
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
let timers = {};
|
||||
|
||||
dayjs.extend(window.dayjs_plugin_utc);
|
||||
dayjs.extend(window.dayjs_plugin_relativeTime);
|
||||
|
||||
Alpine.data('elapsedTime', (uuid, status, created_at, updated_at) => ({
|
||||
finished_time: 'calculating...',
|
||||
started_time: 'calculating...',
|
||||
init() {
|
||||
if (timers[uuid]) {
|
||||
clearInterval(timers[uuid]);
|
||||
}
|
||||
if (status === 'in_progress') {
|
||||
timers[uuid] = setInterval(() => {
|
||||
this.finished_time = dayjs().diff(dayjs.utc(created_at),
|
||||
'second') + 's'
|
||||
}, 1000);
|
||||
} else {
|
||||
let seconds = dayjs.utc(updated_at).diff(dayjs.utc(created_at), 'second')
|
||||
this.finished_time = seconds + 's';
|
||||
}
|
||||
},
|
||||
measure_finished_time() {
|
||||
return this.finished_time;
|
||||
},
|
||||
measure_since_started() {
|
||||
return dayjs.utc(created_at).fromNow();
|
||||
}
|
||||
}))
|
||||
})
|
||||
</script>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,104 @@
|
||||
<div>
|
||||
<h1 class="py-0">Deployment</h1>
|
||||
<livewire:project.application.heading :application="$application" />
|
||||
<div class="pt-4" x-data="{ fullscreen: false, alwaysScroll: false, intervalId: null }">
|
||||
<livewire:project.application.deployment-navbar :application_deployment_queue="$application_deployment_queue" />
|
||||
@if (data_get($application_deployment_queue, 'status') === 'in_progress')
|
||||
<div class="flex items-center gap-1 pt-2 ">Deployment is
|
||||
<div class="text-warning"> {{ Str::headline(data_get($this->application_deployment_queue, 'status')) }}.
|
||||
</div>
|
||||
<x-loading class="loading-ring" />
|
||||
</div>
|
||||
{{-- <div class="">Logs will be updated automatically.</div> --}}
|
||||
@else
|
||||
<div class="pt-2 ">Deployment is <span
|
||||
class="text-warning">{{ Str::headline(data_get($application_deployment_queue, 'status')) }}</span>.
|
||||
</div>
|
||||
@endif
|
||||
<div id="screen" :class="fullscreen ? 'fullscreen' : ''">
|
||||
<div @if ($isKeepAliveOn) wire:poll.2000ms="polling" @endif
|
||||
class="relative flex flex-col-reverse w-full p-2 px-4 mt-4 overflow-y-auto text-white bg-coolgray-100 scrollbar border-coolgray-300"
|
||||
:class="fullscreen ? '' : 'max-h-[40rem] border border-dotted rounded'">
|
||||
<button title="Minimize" x-show="fullscreen" class="fixed top-4 right-4"
|
||||
x-on:click="makeFullscreen"><svg class="icon" viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||
stroke-width="2" d="M6 14h4m0 0v4m0-4l-6 6m14-10h-4m0 0V6m0 4l6-6" />
|
||||
</svg></button>
|
||||
<button title="Go Top" x-show="fullscreen" class="fixed top-4 right-28" x-on:click="goTop"> <svg
|
||||
class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||
stroke-width="2" d="M12 5v14m4-10l-4-4M8 9l4-4" />
|
||||
</svg></button>
|
||||
<button title="Follow Logs" x-show="fullscreen" :class="alwaysScroll ? 'text-warning' : ''"
|
||||
class="fixed top-4 right-16" x-on:click="toggleScroll"><svg class="icon" viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||
stroke-width="2" d="M12 5v14m4-4l-4 4m-4-4l4 4" />
|
||||
</svg></button>
|
||||
|
||||
<button title="Fullscreen" x-show="!fullscreen" class="absolute top-2 right-8"
|
||||
x-on:click="makeFullscreen"><svg class="fixed icon" viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="none">
|
||||
<path
|
||||
d="M24 0v24H0V0h24ZM12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035c-.01-.004-.019-.001-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427c-.002-.01-.009-.017-.017-.018Zm.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093c.012.004.023 0 .029-.008l.004-.014l-.034-.614c-.003-.012-.01-.02-.02-.022Zm-.715.002a.023.023 0 0 0-.027.006l-.006.014l-.034.614c0 .012.007.02.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01l-.184-.092Z" />
|
||||
<path fill="currentColor"
|
||||
d="M9.793 12.793a1 1 0 0 1 1.497 1.32l-.083.094L6.414 19H9a1 1 0 0 1 .117 1.993L9 21H4a1 1 0 0 1-.993-.883L3 20v-5a1 1 0 0 1 1.993-.117L5 15v2.586l4.793-4.793ZM20 3a1 1 0 0 1 .993.883L21 4v5a1 1 0 0 1-1.993.117L19 9V6.414l-4.793 4.793a1 1 0 0 1-1.497-1.32l.083-.094L17.586 5H15a1 1 0 0 1-.117-1.993L15 3h5Z" />
|
||||
</g>
|
||||
</svg></button>
|
||||
<div id="logs" class="flex flex-col">
|
||||
@if (decode_remote_command_output($application_deployment_queue)->count() > 0)
|
||||
@foreach (decode_remote_command_output($application_deployment_queue) as $line)
|
||||
<div @class([
|
||||
'font-mono whitespace-pre-line',
|
||||
'text-warning' => $line['hidden'],
|
||||
'text-red-500' => $line['type'] == 'stderr',
|
||||
])>[{{ $line['timestamp'] }}] @if ($line['hidden'])
|
||||
<br>COMMAND: <br>{{ $line['command'] }} <br><br>OUTPUT:
|
||||
@endif{{ $line['output'] }}@if ($line['hidden'])
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
@else
|
||||
<span class="font-mono text-neutral-400">No logs yet.</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
function makeFullscreen() {
|
||||
this.fullscreen = !this.fullscreen;
|
||||
if (this.fullscreen === false) {
|
||||
this.alwaysScroll = false;
|
||||
clearInterval(this.intervalId);
|
||||
}
|
||||
}
|
||||
|
||||
function toggleScroll() {
|
||||
this.alwaysScroll = !this.alwaysScroll;
|
||||
|
||||
if (this.alwaysScroll) {
|
||||
this.intervalId = setInterval(() => {
|
||||
const screen = document.getElementById('screen');
|
||||
const logs = document.getElementById('logs');
|
||||
if (screen.scrollTop !== logs.scrollHeight) {
|
||||
screen.scrollTop = logs.scrollHeight;
|
||||
}
|
||||
}, 100);
|
||||
} else {
|
||||
clearInterval(this.intervalId);
|
||||
this.intervalId = null;
|
||||
}
|
||||
}
|
||||
|
||||
function goTop() {
|
||||
this.alwaysScroll = false;
|
||||
clearInterval(this.intervalId);
|
||||
const screen = document.getElementById('screen');
|
||||
screen.scrollTop = 0;
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1,99 +0,0 @@
|
||||
<div class="flex flex-col gap-2 pb-10" @if ($skip == 0) wire:poll.5000ms='reload_deployments' @endif>
|
||||
<div class="flex items-end gap-2 pt-4">
|
||||
<h2>Deployments <span class="text-xs">({{ $deployments_count }})</span></h2>
|
||||
@if ($show_next)
|
||||
<x-forms.button wire:click="load_deployments({{ $default_take }})">Next Page
|
||||
</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
<form class="flex items-end gap-2">
|
||||
<x-forms.input id="pull_request_id" label="Pull Request"></x-forms.input>
|
||||
<x-forms.button type="submit">Filter</x-forms.button>
|
||||
</form>
|
||||
@forelse ($deployments as $deployment)
|
||||
<a @class([
|
||||
'bg-coolgray-100 p-2 border-l border-dashed transition-colors hover:no-underline',
|
||||
'hover:bg-coolgray-200' => data_get($deployment, 'status') === 'queued',
|
||||
'border-warning hover:bg-warning hover:text-black' =>
|
||||
data_get($deployment, 'status') === 'in_progress' ||
|
||||
data_get($deployment, 'status') === 'cancelled-by-user',
|
||||
'border-error hover:bg-error' =>
|
||||
data_get($deployment, 'status') === 'failed',
|
||||
'border-success hover:bg-success' =>
|
||||
data_get($deployment, 'status') === 'finished',
|
||||
]) href="{{ $current_url . '/' . data_get($deployment, 'deployment_uuid') }}"
|
||||
class="hover:no-underline">
|
||||
<div class="flex flex-col justify-start">
|
||||
<div class="flex gap-1">
|
||||
{{ $deployment->created_at }} UTC
|
||||
<span class=" text-warning">></span>
|
||||
{{ $deployment->status }}
|
||||
</div>
|
||||
@if (data_get($deployment, 'pull_request_id'))
|
||||
<div>
|
||||
<span class=" text-warning">></span>
|
||||
Pull Request #{{ data_get($deployment, 'pull_request_id') }}
|
||||
@if (data_get($deployment, 'is_webhook'))
|
||||
(Webhook)
|
||||
@endif
|
||||
Webhook (SHA
|
||||
@if (data_get($deployment, 'commit'))
|
||||
{{ data_get($deployment, 'commit') }})
|
||||
@else
|
||||
HEAD)
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col" x-data="elapsedTime('{{ $deployment->deployment_uuid }}', '{{ $deployment->status }}', '{{ $deployment->created_at }}', '{{ $deployment->updated_at }}')">
|
||||
<div>
|
||||
@if ($deployment->status !== 'in_progress')
|
||||
Finished <span x-text="measure_since_started()">0s</span> in
|
||||
@else
|
||||
Running for
|
||||
@endif
|
||||
<span class="font-bold" x-text="measure_finished_time()">0s</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
@empty
|
||||
<div class="">No deployments found</div>
|
||||
@endforelse
|
||||
<script src="https://cdn.jsdelivr.net/npm/dayjs@1/dayjs.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/dayjs@1/plugin/utc.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/dayjs@1/plugin/relativeTime.js"></script>
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
let timers = {};
|
||||
|
||||
dayjs.extend(window.dayjs_plugin_utc);
|
||||
dayjs.extend(window.dayjs_plugin_relativeTime);
|
||||
|
||||
Alpine.data('elapsedTime', (uuid, status, created_at, updated_at) => ({
|
||||
finished_time: 'calculating...',
|
||||
started_time: 'calculating...',
|
||||
init() {
|
||||
if (timers[uuid]) {
|
||||
clearInterval(timers[uuid]);
|
||||
}
|
||||
if (status === 'in_progress') {
|
||||
timers[uuid] = setInterval(() => {
|
||||
this.finished_time = dayjs().diff(dayjs.utc(created_at),
|
||||
'second') + 's'
|
||||
}, 1000);
|
||||
} else {
|
||||
let seconds = dayjs.utc(updated_at).diff(dayjs.utc(created_at), 'second')
|
||||
this.finished_time = seconds + 's';
|
||||
}
|
||||
},
|
||||
measure_finished_time() {
|
||||
return this.finished_time;
|
||||
},
|
||||
measure_since_started() {
|
||||
return dayjs.utc(created_at).fromNow();
|
||||
}
|
||||
}))
|
||||
})
|
||||
</script>
|
||||
</div>
|
||||
@@ -16,14 +16,7 @@
|
||||
<x-forms.input id="application.name" label="Name" required />
|
||||
<x-forms.input id="application.description" label="Description" />
|
||||
</div>
|
||||
@if ($application->build_pack !== 'dockercompose')
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.input placeholder="https://coolify.io" id="application.fqdn" label="Domains"
|
||||
helper="You can specify one domain with path or more with comma. You can specify a port to bind the domain to.<br><br><span class='text-helper'>Example</span><br>- http://app.coolify.io, https://cloud.coolify.io/dashboard<br>- http://app.coolify.io/api/v3<br>- http://app.coolify.io:3000 -> app.coolify.io will point to port 3000 inside the container. " />
|
||||
<x-forms.button wire:click="getWildcardDomain">Generate Domain
|
||||
</x-forms.button>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (!$application->dockerfile && $application->build_pack !== 'dockerimage')
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex gap-2">
|
||||
@@ -70,6 +63,14 @@
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
@if ($application->build_pack !== 'dockercompose')
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.input placeholder="https://coolify.io" id="application.fqdn" label="Domains"
|
||||
helper="You can specify one domain with path or more with comma. You can specify a port to bind the domain to.<br><br><span class='text-helper'>Example</span><br>- http://app.coolify.io, https://cloud.coolify.io/dashboard<br>- http://app.coolify.io/api/v3<br>- http://app.coolify.io:3000 -> app.coolify.io will point to port 3000 inside the container. " />
|
||||
<x-forms.button wire:click="getWildcardDomain">Generate Domain
|
||||
</x-forms.button>
|
||||
</div>
|
||||
@endif
|
||||
@if ($application->build_pack !== 'dockercompose')
|
||||
<h3>Docker Registry</h3>
|
||||
@if ($application->destination->server->isSwarm())
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
wire:click="stop({{ data_get($preview, 'pull_request_id') }})">Remove Preview
|
||||
</x-forms.button>
|
||||
<a
|
||||
href="{{ route('project.application.deployments', [...$parameters, 'pull_request_id' => data_get($preview, 'pull_request_id')]) }}">
|
||||
href="{{ route('project.application.deployment.index', [...$parameters, 'pull_request_id' => data_get($preview, 'pull_request_id')]) }}">
|
||||
<x-forms.button class="bg-coolgray-500">
|
||||
Get Deployment Logs
|
||||
</x-forms.button>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<x-layout>
|
||||
<div>
|
||||
<h1>Backups</h1>
|
||||
<livewire:project.database.heading :database="$database" />
|
||||
<x-modal modalId="startDatabase">
|
||||
@@ -16,4 +16,4 @@
|
||||
<h3 class="py-4">Executions</h3>
|
||||
<livewire:project.database.backup-executions :backup="$backup" :executions="$executions" />
|
||||
</div>
|
||||
</x-layout>
|
||||
</div>
|
||||
@@ -1,4 +1,4 @@
|
||||
<x-layout>
|
||||
<div>
|
||||
<h1>Backups</h1>
|
||||
<livewire:project.database.heading :database="$database" />
|
||||
<x-modal modalId="startDatabase">
|
||||
@@ -19,4 +19,4 @@
|
||||
</div>
|
||||
<livewire:project.database.scheduled-backups :database="$database" />
|
||||
</div>
|
||||
</x-layout>
|
||||
</div>
|
||||
@@ -1,4 +1,4 @@
|
||||
<x-layout>
|
||||
<div>
|
||||
<h1>Configuration</h1>
|
||||
<livewire:project.database.heading :database="$database" />
|
||||
<x-modal modalId="startDatabase">
|
||||
@@ -79,4 +79,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-layout>
|
||||
</div>
|
||||
@@ -3,7 +3,7 @@
|
||||
@forelse($database->scheduledBackups as $backup)
|
||||
@if ($type === 'database')
|
||||
<a class="flex flex-col box"
|
||||
href="{{ route('project.database.backups.executions', [...$parameters, 'backup_uuid' => $backup->uuid]) }}">
|
||||
href="{{ route('project.database.backup.execution', [...$parameters, 'backup_uuid' => $backup->uuid]) }}">
|
||||
<div>Frequency: {{ $backup->frequency }}</div>
|
||||
<div>Last backup: {{ data_get($backup->latest_log, 'status', 'No backup yet') }}</div>
|
||||
<div>Number of backups to keep (locally): {{ $backup->number_of_backups_locally }}</div>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<a class="text-xs truncate lg:text-sm"
|
||||
href="{{ route('project.resources', ['environment_name' => request()->route('environment_name'), 'project_uuid' => request()->route('project_uuid')]) }}">{{ request()->route('environment_name') }}</a>
|
||||
href="{{ route('project.resource.index', ['environment_name' => request()->route('environment_name'), 'project_uuid' => request()->route('project_uuid')]) }}">{{ request()->route('environment_name') }}</a>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<x-layout>
|
||||
<div>
|
||||
<div class="flex gap-2">
|
||||
<h1>Projects</span></h1>
|
||||
@if ($servers > 0)
|
||||
@@ -51,4 +51,4 @@
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
</x-layout>
|
||||
</div>
|
||||
@@ -77,7 +77,7 @@
|
||||
Based on an existing Docker Image
|
||||
</div>
|
||||
<div class="description">
|
||||
You can deploy an existing Docker Image form any Registry, without Git.
|
||||
You can deploy an existing Docker Image from any Registry, without Git.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<x-layout>
|
||||
<div>
|
||||
@if ($type === 'public')
|
||||
<livewire:project.new.public-git-repository :type="$type" />
|
||||
@elseif ($type === 'private-gh-app')
|
||||
@@ -14,4 +14,4 @@
|
||||
@else
|
||||
<livewire:project.new.select />
|
||||
@endif
|
||||
</x-layout>
|
||||
</div>
|
||||
@@ -1,19 +1,19 @@
|
||||
<x-layout>
|
||||
<div>
|
||||
<div class="flex flex-col">
|
||||
<div class="flex items-center gap-2">
|
||||
<h1>Resources</h1>
|
||||
@if ($environment->isEmpty())
|
||||
<a class="font-normal text-white normal-case border-none rounded hover:no-underline btn btn-primary btn-sm no-animation"
|
||||
href="{{ route('project.clone', ['project_uuid' => data_get($project, 'uuid'), 'environment_name' => request()->route('environment_name')]) }}">
|
||||
href="{{ route('project.clone-me', ['project_uuid' => data_get($project, 'uuid'), 'environment_name' => request()->route('environment_name')]) }}">
|
||||
Clone
|
||||
</a>
|
||||
<livewire:project.delete-environment :environment_id="$environment->id" />
|
||||
@else
|
||||
<a href="{{ route('project.resources.new', ['project_uuid' => request()->route('project_uuid'), 'environment_name' => request()->route('environment_name')]) }} "
|
||||
<a href="{{ route('project.resource.create', ['project_uuid' => request()->route('project_uuid'), 'environment_name' => request()->route('environment_name')]) }} "
|
||||
class="font-normal text-white normal-case border-none rounded hover:no-underline btn btn-primary btn-sm no-animation">+
|
||||
New</a>
|
||||
<a class="font-normal text-white normal-case border-none rounded hover:no-underline btn btn-primary btn-sm no-animation"
|
||||
href="{{ route('project.clone', ['project_uuid' => data_get($project, 'uuid'), 'environment_name' => request()->route('environment_name')]) }}">
|
||||
href="{{ route('project.clone-me', ['project_uuid' => data_get($project, 'uuid'), 'environment_name' => request()->route('environment_name')]) }}">
|
||||
Clone
|
||||
</a>
|
||||
@endif
|
||||
@@ -34,14 +34,14 @@
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<a class="text-xs truncate lg:text-sm"
|
||||
href="{{ route('project.resources', ['environment_name' => request()->route('environment_name'), 'project_uuid' => request()->route('project_uuid')]) }}">{{ request()->route('environment_name') }}</a>
|
||||
href="{{ route('project.resource.index', ['environment_name' => request()->route('environment_name'), 'project_uuid' => request()->route('project_uuid')]) }}">{{ request()->route('environment_name') }}</a>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
@if ($environment->isEmpty())
|
||||
<a href="{{ route('project.resources.new', ['project_uuid' => request()->route('project_uuid'), 'environment_name' => request()->route('environment_name')]) }} "
|
||||
<a href="{{ route('project.resource.create', ['project_uuid' => request()->route('project_uuid'), 'environment_name' => request()->route('environment_name')]) }} "
|
||||
class="items-center justify-center box">+ Add New Resource</a>
|
||||
@endif
|
||||
<div class="grid gap-2 lg:grid-cols-2">
|
||||
@@ -94,4 +94,4 @@
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</x-layout>
|
||||
</div>
|
||||
169
resources/views/livewire/project/service/configuration.blade.php
Normal file
169
resources/views/livewire/project/service/configuration.blade.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'service-stack' }" x-init="$wire.checkStatus">
|
||||
<livewire:project.service.navbar :service="$service" :parameters="$parameters" :query="$query" />
|
||||
<div class="flex h-full pt-6">
|
||||
<div class="flex flex-col items-start gap-4 min-w-fit">
|
||||
<a target="_blank" href="{{ $service->documentation() }}">Documentation <x-external-link /></a>
|
||||
<a :class="activeTab === 'service-stack' && 'text-white'"
|
||||
@click.prevent="activeTab = 'service-stack';
|
||||
window.location.hash = 'service-stack'"
|
||||
href="#">Service Stack</a>
|
||||
<a :class="activeTab === 'execute-command' && 'text-white'"
|
||||
@click.prevent="activeTab = 'execute-command';
|
||||
window.location.hash = 'execute-command'"
|
||||
href="#">Execute Command</a>
|
||||
<a :class="activeTab === 'logs' && 'text-white'"
|
||||
@click.prevent="activeTab = 'logs';
|
||||
window.location.hash = 'logs'"
|
||||
href="#">Logs</a>
|
||||
<a :class="activeTab === 'storages' && 'text-white'"
|
||||
@click.prevent="activeTab = 'storages';
|
||||
window.location.hash = 'storages'"
|
||||
href="#">Storages</a>
|
||||
<a :class="activeTab === 'webhooks' && 'text-white'"
|
||||
@click.prevent="activeTab = 'webhooks'; window.location.hash = 'webhooks'" href="#">Webhooks
|
||||
</a>
|
||||
<a :class="activeTab === 'environment-variables' && 'text-white'"
|
||||
@click.prevent="activeTab = 'environment-variables'; window.location.hash = 'environment-variables'"
|
||||
href="#">Environment
|
||||
Variables</a>
|
||||
<a :class="activeTab === 'danger' && 'text-white'"
|
||||
@click.prevent="activeTab = 'danger';
|
||||
window.location.hash = 'danger'"
|
||||
href="#">Danger Zone
|
||||
</a>
|
||||
</div>
|
||||
<div class="w-full pl-8">
|
||||
<div x-cloak x-show="activeTab === 'service-stack'">
|
||||
<livewire:project.service.stack-form :service="$service" />
|
||||
<div class="grid grid-cols-1 gap-2 pt-4 xl:grid-cols-1">
|
||||
@foreach ($applications as $application)
|
||||
<div @class([
|
||||
'border-l border-dashed border-red-500' => Str::of(
|
||||
$application->status)->contains(['exited']),
|
||||
'border-l border-dashed border-success' => Str::of(
|
||||
$application->status)->contains(['running']),
|
||||
'border-l border-dashed border-warning' => Str::of(
|
||||
$application->status)->contains(['starting']),
|
||||
'flex gap-2 box-without-bg bg-coolgray-100 hover:text-neutral-300 group',
|
||||
])>
|
||||
<div class="flex flex-row w-full">
|
||||
<div class="flex flex-col flex-1">
|
||||
<div class="pb-2">
|
||||
@if ($application->human_name)
|
||||
{{ Str::headline($application->human_name) }}
|
||||
@else
|
||||
{{ Str::headline($application->name) }}
|
||||
@endif
|
||||
<span class="text-xs">({{ $application->image }})</span>
|
||||
</div>
|
||||
@if ($application->configuration_required)
|
||||
<span class="text-xs text-error">(configuration required)</span>
|
||||
@endif
|
||||
@if ($application->description)
|
||||
<span class="text-xs">{{ Str::limit($application->description, 60) }}</span>
|
||||
@endif
|
||||
@if ($application->fqdn)
|
||||
<span class="text-xs">{{ Str::limit($application->fqdn, 60) }}</span>
|
||||
@endif
|
||||
<div class="text-xs">{{ $application->status }}</div>
|
||||
</div>
|
||||
<div class="flex items-center px-4">
|
||||
<a
|
||||
class="flex flex-col flex-1 group-hover:text-white hover:no-underline"
|
||||
href="{{ route('project.service.index', [...$parameters, 'service_name' => $application->name]) }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon hover:text-warning"
|
||||
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
|
||||
stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path
|
||||
d="M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065z" />
|
||||
<path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@foreach ($databases as $database)
|
||||
<div @class([
|
||||
'border-l border-dashed border-red-500' => Str::of(
|
||||
$database->status)->contains(['exited']),
|
||||
'border-l border-dashed border-success' => Str::of(
|
||||
$database->status)->contains(['running']),
|
||||
'border-l border-dashed border-warning' => Str::of(
|
||||
$database->status)->contains(['restarting']),
|
||||
'flex gap-2 box-without-bg bg-coolgray-100 hover:text-neutral-300 group',
|
||||
])>
|
||||
|
||||
|
||||
<div class="flex flex-row w-full">
|
||||
<div class="flex flex-col flex-1">
|
||||
<div class="pb-2">
|
||||
@if ($database->human_name)
|
||||
{{ Str::headline($database->human_name) }}
|
||||
@else
|
||||
{{ Str::headline($database->name) }}
|
||||
@endif
|
||||
<span class="text-xs">({{ $database->image }})</span>
|
||||
</div>
|
||||
@if ($database->configuration_required)
|
||||
<span class="text-xs text-error">(configuration required)</span>
|
||||
@endif
|
||||
@if ($database->description)
|
||||
<span class="text-xs">{{ Str::limit($database->description, 60) }}</span>
|
||||
@endif
|
||||
<div class="text-xs">{{ $database->status }}</div>
|
||||
</div>
|
||||
<div class="flex items-center px-4">
|
||||
<a
|
||||
class="flex flex-col flex-1 group-hover:text-white hover:no-underline"
|
||||
href="{{ route('project.service.index', [...$parameters, 'service_name' => $database->name]) }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon hover:text-warning"
|
||||
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
|
||||
stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path
|
||||
d="M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065z" />
|
||||
<path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'storages'">
|
||||
<div class="flex items-center gap-2">
|
||||
<h2>Storages</h2>
|
||||
</div>
|
||||
<div class="pb-4">Persistent storage to preserve data between deployments.</div>
|
||||
<span class="text-warning">Please modify storage layout in your Docker Compose file.</span>
|
||||
@foreach ($applications as $application)
|
||||
<livewire:project.service.storage wire:key="application-{{ $application->id }}"
|
||||
:resource="$application" />
|
||||
@endforeach
|
||||
@foreach ($databases as $database)
|
||||
<livewire:project.service.storage wire:key="database-{{ $database->id }}" :resource="$database" />
|
||||
@endforeach
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'webhooks'">
|
||||
<livewire:project.shared.webhooks :resource="$service" />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'logs'">
|
||||
<livewire:project.shared.logs :resource="$service" />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'execute-command'">
|
||||
<livewire:project.shared.execute-container-command :resource="$service" />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'environment-variables'">
|
||||
<div x-cloak x-show="activeTab === 'environment-variables'">
|
||||
<livewire:project.shared.environment-variable.all :resource="$service" />
|
||||
</div>
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'danger'">
|
||||
<livewire:project.shared.danger :resource="$service" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,169 +1,62 @@
|
||||
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'service-stack' }" x-init="$wire.checkStatus">
|
||||
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'general' }">
|
||||
<livewire:project.service.navbar :service="$service" :parameters="$parameters" :query="$query" />
|
||||
<div class="flex h-full pt-6">
|
||||
<div class="flex flex-col items-start gap-4 min-w-fit">
|
||||
<a target="_blank" href="{{ $service->documentation() }}">Documentation <x-external-link /></a>
|
||||
<a :class="activeTab === 'service-stack' && 'text-white'"
|
||||
@click.prevent="activeTab = 'service-stack';
|
||||
window.location.hash = 'service-stack'"
|
||||
href="#">Service Stack</a>
|
||||
<a :class="activeTab === 'execute-command' && 'text-white'"
|
||||
@click.prevent="activeTab = 'execute-command';
|
||||
window.location.hash = 'execute-command'"
|
||||
href="#">Execute Command</a>
|
||||
<a :class="activeTab === 'logs' && 'text-white'"
|
||||
@click.prevent="activeTab = 'logs';
|
||||
window.location.hash = 'logs'"
|
||||
href="#">Logs</a>
|
||||
<div class="flex flex-col gap-4 min-w-fit">
|
||||
<a class="{{ request()->routeIs('project.service.configuration') ? 'text-white' : '' }}"
|
||||
href="{{ route('project.service.configuration', [...$parameters, 'service_name' => null]) }}">
|
||||
<button><- Back</button>
|
||||
</a>
|
||||
<a :class="activeTab === 'general' && 'text-white'"
|
||||
@click.prevent="activeTab = 'general'; window.location.hash = 'general'; if(window.location.search) window.location.search = ''"
|
||||
href="#">General</a>
|
||||
<a :class="activeTab === 'storages' && 'text-white'"
|
||||
@click.prevent="activeTab = 'storages';
|
||||
window.location.hash = 'storages'"
|
||||
href="#">Storages</a>
|
||||
<a :class="activeTab === 'webhooks' && 'text-white'"
|
||||
@click.prevent="activeTab = 'webhooks'; window.location.hash = 'webhooks'" href="#">Webhooks
|
||||
</a>
|
||||
<a :class="activeTab === 'environment-variables' && 'text-white'"
|
||||
@click.prevent="activeTab = 'environment-variables'; window.location.hash = 'environment-variables'"
|
||||
href="#">Environment
|
||||
Variables</a>
|
||||
<a :class="activeTab === 'danger' && 'text-white'"
|
||||
@click.prevent="activeTab = 'danger';
|
||||
window.location.hash = 'danger'"
|
||||
href="#">Danger Zone
|
||||
@click.prevent="activeTab = 'storages'; window.location.hash = 'storages'; if(window.location.search) window.location.search = ''"
|
||||
href="#">Storages
|
||||
</a>
|
||||
@if (
|
||||
$serviceDatabase?->databaseType() === 'standalone-mysql' ||
|
||||
$serviceDatabase?->databaseType() === 'standalone-postgresql' ||
|
||||
$serviceDatabase?->databaseType() === 'standalone-mariadb')
|
||||
<a :class="activeTab === 'backups' && 'text-white'"
|
||||
@click.prevent="activeTab = 'backups'; window.location.hash = 'backups'" href="#">Backups</a>
|
||||
@endif
|
||||
</div>
|
||||
<div class="w-full pl-8">
|
||||
<div x-cloak x-show="activeTab === 'service-stack'">
|
||||
<livewire:project.service.stack-form :service="$service" />
|
||||
<div class="grid grid-cols-1 gap-2 pt-4 xl:grid-cols-1">
|
||||
@foreach ($applications as $application)
|
||||
<div @class([
|
||||
'border-l border-dashed border-red-500' => Str::of(
|
||||
$application->status)->contains(['exited']),
|
||||
'border-l border-dashed border-success' => Str::of(
|
||||
$application->status)->contains(['running']),
|
||||
'border-l border-dashed border-warning' => Str::of(
|
||||
$application->status)->contains(['starting']),
|
||||
'flex gap-2 box-without-bg bg-coolgray-100 hover:text-neutral-300 group',
|
||||
])>
|
||||
<div class="flex flex-row w-full">
|
||||
<div class="flex flex-col flex-1">
|
||||
<div class="pb-2">
|
||||
@if ($application->human_name)
|
||||
{{ Str::headline($application->human_name) }}
|
||||
@else
|
||||
{{ Str::headline($application->name) }}
|
||||
@endif
|
||||
<span class="text-xs">({{ $application->image }})</span>
|
||||
</div>
|
||||
@if ($application->configuration_required)
|
||||
<span class="text-xs text-error">(configuration required)</span>
|
||||
@endif
|
||||
@if ($application->description)
|
||||
<span class="text-xs">{{ Str::limit($application->description, 60) }}</span>
|
||||
@endif
|
||||
@if ($application->fqdn)
|
||||
<span class="text-xs">{{ Str::limit($application->fqdn, 60) }}</span>
|
||||
@endif
|
||||
<div class="text-xs">{{ $application->status }}</div>
|
||||
</div>
|
||||
<div class="flex items-center px-4">
|
||||
<a
|
||||
class="flex flex-col flex-1 group-hover:text-white hover:no-underline"
|
||||
href="{{ route('project.service.show', [...$parameters, 'service_name' => $application->name]) }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon hover:text-warning"
|
||||
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
|
||||
stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path
|
||||
d="M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065z" />
|
||||
<path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@foreach ($databases as $database)
|
||||
<div @class([
|
||||
'border-l border-dashed border-red-500' => Str::of(
|
||||
$database->status)->contains(['exited']),
|
||||
'border-l border-dashed border-success' => Str::of(
|
||||
$database->status)->contains(['running']),
|
||||
'border-l border-dashed border-warning' => Str::of(
|
||||
$database->status)->contains(['restarting']),
|
||||
'flex gap-2 box-without-bg bg-coolgray-100 hover:text-neutral-300 group',
|
||||
])>
|
||||
|
||||
|
||||
<div class="flex flex-row w-full">
|
||||
<div class="flex flex-col flex-1">
|
||||
<div class="pb-2">
|
||||
@if ($database->human_name)
|
||||
{{ Str::headline($database->human_name) }}
|
||||
@else
|
||||
{{ Str::headline($database->name) }}
|
||||
@endif
|
||||
<span class="text-xs">({{ $database->image }})</span>
|
||||
</div>
|
||||
@if ($database->configuration_required)
|
||||
<span class="text-xs text-error">(configuration required)</span>
|
||||
@endif
|
||||
@if ($database->description)
|
||||
<span class="text-xs">{{ Str::limit($database->description, 60) }}</span>
|
||||
@endif
|
||||
<div class="text-xs">{{ $database->status }}</div>
|
||||
</div>
|
||||
<div class="flex items-center px-4">
|
||||
<a
|
||||
class="flex flex-col flex-1 group-hover:text-white hover:no-underline"
|
||||
href="{{ route('project.service.show', [...$parameters, 'service_name' => $database->name]) }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon hover:text-warning"
|
||||
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
|
||||
stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path
|
||||
d="M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065z" />
|
||||
<path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@isset($serviceApplication)
|
||||
<div x-cloak x-show="activeTab === 'general'" class="h-full">
|
||||
<livewire:project.service.application :application="$serviceApplication" />
|
||||
</div>
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'storages'">
|
||||
<div class="flex items-center gap-2">
|
||||
<h2>Storages</h2>
|
||||
<div x-cloak x-show="activeTab === 'storages'">
|
||||
<div class="flex items-center gap-2">
|
||||
<h2>Storages</h2>
|
||||
</div>
|
||||
<div class="pb-4">Persistent storage to preserve data between deployments.</div>
|
||||
<span class="text-warning">Please modify storage layout in your Docker Compose file.</span>
|
||||
<livewire:project.service.storage wire:key="application-{{ $serviceApplication->id }}"
|
||||
:resource="$serviceApplication" />
|
||||
</div>
|
||||
<div class="pb-4">Persistent storage to preserve data between deployments.</div>
|
||||
<span class="text-warning">Please modify storage layout in your Docker Compose file.</span>
|
||||
@foreach ($applications as $application)
|
||||
<livewire:project.service.storage wire:key="application-{{ $application->id }}"
|
||||
:resource="$application" />
|
||||
@endforeach
|
||||
@foreach ($databases as $database)
|
||||
<livewire:project.service.storage wire:key="database-{{ $database->id }}" :resource="$database" />
|
||||
@endforeach
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'webhooks'">
|
||||
<livewire:project.shared.webhooks :resource="$service" />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'logs'">
|
||||
<livewire:project.shared.logs :resource="$service" />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'execute-command'">
|
||||
<livewire:project.shared.execute-container-command :resource="$service" />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'environment-variables'">
|
||||
<div x-cloak x-show="activeTab === 'environment-variables'">
|
||||
<livewire:project.shared.environment-variable.all :resource="$service" />
|
||||
@endisset
|
||||
@isset($serviceDatabase)
|
||||
<div x-cloak x-show="activeTab === 'general'" class="h-full">
|
||||
<livewire:project.service.database :database="$serviceDatabase" />
|
||||
</div>
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'danger'">
|
||||
<livewire:project.shared.danger :resource="$service" />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'storages'">
|
||||
<div class="flex items-center gap-2">
|
||||
<h2>Storages</h2>
|
||||
</div>
|
||||
<div class="pb-4">Persistent storage to preserve data between deployments.</div>
|
||||
<span class="text-warning">Please modify storage layout in your Docker Compose file.</span>
|
||||
<livewire:project.service.storage wire:key="application-{{ $serviceDatabase->id }}" :resource="$serviceDatabase" />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'backups'">
|
||||
<div class="flex gap-2 ">
|
||||
<h2 class="pb-4">Scheduled Backups</h2>
|
||||
<x-forms.button onclick="createScheduledBackup.showModal()">+ Add</x-forms.button>
|
||||
</div>
|
||||
<livewire:project.database.create-scheduled-backup :database="$serviceDatabase" :s3s="$s3s" />
|
||||
<livewire:project.database.scheduled-backups :database="$serviceDatabase" />
|
||||
</div>
|
||||
@endisset
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'general' }">
|
||||
<livewire:project.service.navbar :service="$service" :parameters="$parameters" :query="$query" />
|
||||
<div class="flex h-full pt-6">
|
||||
<div class="flex flex-col gap-4 min-w-fit">
|
||||
<a class="{{ request()->routeIs('project.service.configuration') ? 'text-white' : '' }}"
|
||||
href="{{ route('project.service.configuration', [...$parameters, 'service_name' => null]) }}">
|
||||
<button><- Back</button>
|
||||
</a>
|
||||
<a :class="activeTab === 'general' && 'text-white'"
|
||||
@click.prevent="activeTab = 'general'; window.location.hash = 'general'; if(window.location.search) window.location.search = ''"
|
||||
href="#">General</a>
|
||||
<a :class="activeTab === 'storages' && 'text-white'"
|
||||
@click.prevent="activeTab = 'storages'; window.location.hash = 'storages'; if(window.location.search) window.location.search = ''"
|
||||
href="#">Storages
|
||||
</a>
|
||||
@if (
|
||||
$serviceDatabase?->databaseType() === 'standalone-mysql' ||
|
||||
$serviceDatabase?->databaseType() === 'standalone-postgresql' ||
|
||||
$serviceDatabase?->databaseType() === 'standalone-mariadb')
|
||||
<a :class="activeTab === 'backups' && 'text-white'"
|
||||
@click.prevent="activeTab = 'backups'; window.location.hash = 'backups'" href="#">Backups</a>
|
||||
@endif
|
||||
</div>
|
||||
<div class="w-full pl-8">
|
||||
@isset($serviceApplication)
|
||||
<div x-cloak x-show="activeTab === 'general'" class="h-full">
|
||||
<livewire:project.service.application :application="$serviceApplication" />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'storages'">
|
||||
<div class="flex items-center gap-2">
|
||||
<h2>Storages</h2>
|
||||
</div>
|
||||
<div class="pb-4">Persistent storage to preserve data between deployments.</div>
|
||||
<span class="text-warning">Please modify storage layout in your Docker Compose file.</span>
|
||||
<livewire:project.service.storage wire:key="application-{{ $serviceApplication->id }}"
|
||||
:resource="$serviceApplication" />
|
||||
</div>
|
||||
@endisset
|
||||
@isset($serviceDatabase)
|
||||
<div x-cloak x-show="activeTab === 'general'" class="h-full">
|
||||
<livewire:project.service.database :database="$serviceDatabase" />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'storages'">
|
||||
<div class="flex items-center gap-2">
|
||||
<h2>Storages</h2>
|
||||
</div>
|
||||
<div class="pb-4">Persistent storage to preserve data between deployments.</div>
|
||||
<span class="text-warning">Please modify storage layout in your Docker Compose file.</span>
|
||||
<livewire:project.service.storage wire:key="application-{{ $serviceDatabase->id }}" :resource="$serviceDatabase" />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'backups'">
|
||||
<div class="flex gap-2 ">
|
||||
<h2 class="pb-4">Scheduled Backups</h2>
|
||||
<x-forms.button onclick="createScheduledBackup.showModal()">+ Add</x-forms.button>
|
||||
</div>
|
||||
<livewire:project.database.create-scheduled-backup :database="$serviceDatabase" :s3s="$s3s" />
|
||||
<livewire:project.database.scheduled-backups :database="$serviceDatabase" />
|
||||
</div>
|
||||
@endisset
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,4 +1,4 @@
|
||||
<x-layout>
|
||||
<div>
|
||||
<div class="flex items-center gap-2">
|
||||
<h1>Environments</h1>
|
||||
<x-forms.button class="btn" onclick="newEnvironment.showModal()">+ Add</x-forms.button>
|
||||
@@ -13,7 +13,7 @@
|
||||
<div class="gap-2 border border-transparent cursor-pointer box group" x-data
|
||||
x-on:click="goto('{{ $project->uuid }}','{{ $environment->name }}')">
|
||||
<a class="flex flex-col flex-1 mx-6 hover:no-underline"
|
||||
href="{{ route('project.resources', [$project->uuid, $environment->name]) }}">
|
||||
href="{{ route('project.resource.index', [$project->uuid, $environment->name]) }}">
|
||||
<div class="font-bold text-white"> {{ $environment->name }}</div>
|
||||
<div class="description ">
|
||||
{{ $environment->description }}</div>
|
||||
@@ -41,4 +41,4 @@
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
</x-layout>
|
||||
</div>
|
||||
@@ -1,4 +1,6 @@
|
||||
<div>
|
||||
<h1>Create a new Private Key</h1>
|
||||
<div class="subtitle ">Private Keys are used to connect to your servers without passwords.</div>
|
||||
<x-forms.button class="mb-4" wire:click="generateNewKey">Generate new SSH key for me</x-forms.button>
|
||||
<form class="flex flex-col gap-2" wire:submit='createPrivateKey'>
|
||||
<div class="flex gap-2">
|
||||
54
resources/views/livewire/security/private-key/show.blade.php
Normal file
54
resources/views/livewire/security/private-key/show.blade.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<div>
|
||||
<x-security.navbar />
|
||||
<div x-data="{ showPrivateKey: false }">
|
||||
<x-modal yesOrNo modalId="deletePrivateKey" modalTitle="Delete Private Key">
|
||||
<x-slot:modalBody>
|
||||
<p>This private key will be deleted. It is not reversible. <br>Please think again.</p>
|
||||
</x-slot:modalBody>
|
||||
</x-modal>
|
||||
<form class="flex flex-col gap-2" wire:submit='changePrivateKey'>
|
||||
<div class="flex items-end gap-2">
|
||||
<h2>Private Key</h2>
|
||||
<x-forms.button type="submit">
|
||||
Save
|
||||
</x-forms.button>
|
||||
@if ($private_key->id > 0)
|
||||
<x-forms.button isError isModal modalId="deletePrivateKey">
|
||||
Delete
|
||||
</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
<x-forms.input id="private_key.name" label="Name" required />
|
||||
<x-forms.input id="private_key.description" label="Description" />
|
||||
<div>
|
||||
<div class="flex items-end gap-2 py-2 ">
|
||||
<div class="pl-1 ">Public Key</div>
|
||||
</div>
|
||||
<x-forms.input readonly id="public_key" />
|
||||
<div class="flex items-end gap-2 py-2 ">
|
||||
<div class="pl-1 ">Private Key <span class='text-helper'>*</span></div>
|
||||
<div class="text-xs text-white underline cursor-pointer" x-cloak x-show="!showPrivateKey"
|
||||
x-on:click="showPrivateKey = true">
|
||||
Edit
|
||||
</div>
|
||||
<div class="text-xs text-white underline cursor-pointer" x-cloak x-show="showPrivateKey"
|
||||
x-on:click="showPrivateKey = false">
|
||||
Hide
|
||||
</div>
|
||||
</div>
|
||||
@if ($private_key->is_git_related)
|
||||
<div class="w-48">
|
||||
<x-forms.checkbox id="private_key.is_git_related" disabled label="Is used by a Git App?" />
|
||||
</div>
|
||||
@endif
|
||||
<div x-cloak x-show="!showPrivateKey">
|
||||
<x-forms.input allowToPeak="false" type="password" rows="10" id="private_key.private_key"
|
||||
required disabled />
|
||||
</div>
|
||||
<div x-cloak x-show="showPrivateKey">
|
||||
<x-forms.textarea rows="10" id="private_key.private_key" required />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,7 +1,7 @@
|
||||
<div>
|
||||
<div class="flex items-end gap-2 pb-6 ">
|
||||
<h2>Private Key</h2>
|
||||
<a href="{{ route('security.private-key.new') }}">
|
||||
<a href="{{ route('security.private-key.create') }}">
|
||||
<x-forms.button>Add a new Private Key</x-forms.button>
|
||||
</a>
|
||||
<x-forms.button wire:click.prevent='checkConnection'>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<x-layout>
|
||||
<div>
|
||||
<x-settings.navbar />
|
||||
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'general' }" class="flex h-full pt-1">
|
||||
<div class="flex flex-col gap-4 min-w-fit">
|
||||
@@ -22,4 +22,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-layout>
|
||||
</div>
|
||||
28
resources/views/livewire/settings/license.blade.php
Normal file
28
resources/views/livewire/settings/license.blade.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<div>
|
||||
<x-settings.navbar />
|
||||
<h2>Resale License</h2>
|
||||
<form wire:submit='submit' class="flex flex-col gap-2">
|
||||
<div>
|
||||
@if ($settings->is_resale_license_active)
|
||||
<div class="text-success">License is active</div>
|
||||
@else
|
||||
<div class="text-error">License is not active</div>
|
||||
@endif
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input type="password" id="settings.resale_license"
|
||||
placeholder="eg: BE558E91-0CC5-4AA2-B1C0-B6403C2988DD" label="License Key" />
|
||||
<x-forms.input type="password" id="instance_id" label="Instance Id (do not change this)" disabled />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.button type="submit">
|
||||
Check License
|
||||
</x-forms.button>
|
||||
</div>
|
||||
@if (session()->has('error'))
|
||||
<div class="text-error">
|
||||
{!! session('error') !!}
|
||||
</div>
|
||||
@endif
|
||||
</form>
|
||||
</div>
|
||||
@@ -1,7 +1,11 @@
|
||||
<form class="flex flex-col gap-2" wire:submit='submit'>
|
||||
<x-forms.input autofocus id="name" label="Name" required />
|
||||
<x-forms.input id="description" label="Description" />
|
||||
<x-forms.button type="submit">
|
||||
Save Team
|
||||
</x-forms.button>
|
||||
</form>
|
||||
<div>
|
||||
<h1>New Team</h1>
|
||||
<div class="subtitle">Add a new team</div>
|
||||
<form class="flex flex-col gap-2" wire:submit='submit'>
|
||||
<x-forms.input autofocus id="name" label="Name" required />
|
||||
<x-forms.input id="description" label="Description" />
|
||||
<x-forms.button type="submit">
|
||||
Save Team
|
||||
</x-forms.button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
<div>
|
||||
<x-modal yesOrNo modalId="deleteTeam" modalTitle="Delete Team">
|
||||
<x-slot:modalBody>
|
||||
<p>This team be deleted. It is not reversible. <br>Please think again.</p>
|
||||
</x-slot:modalBody>
|
||||
</x-modal>
|
||||
<h2>Danger Zone</h2>
|
||||
<div class="pb-4">Woah. I hope you know what are you doing.</div>
|
||||
<h4 class="pb-4">Delete Team</h4>
|
||||
@if (session('currentTeam.id') === 0)
|
||||
<div>This is the default team. You can't delete it.</div>
|
||||
@elseif(auth()->user()->teams()->get()->count() === 1)
|
||||
<div>You can't delete your last team.</div>
|
||||
@elseif(currentTeam()->subscription && currentTeam()->subscription?->lemon_status !== 'cancelled')
|
||||
<div>Please cancel your subscription before delete this team (Manage My Subscription).</div>
|
||||
@else
|
||||
@if (currentTeam()->isEmpty())
|
||||
<div class="pb-4">This will delete your team. Beware! There is no coming back!</div>
|
||||
<x-forms.button isError isModal modalId="deleteTeam">
|
||||
Delete
|
||||
</x-forms.button>
|
||||
@else
|
||||
<div>
|
||||
<div class="pb-4">You need to delete the following resources to be able to delete the team:</div>
|
||||
@if (currentTeam()->projects()->count() > 0)
|
||||
<h4 class="pb-4">Projects:</h4>
|
||||
<ul class="pl-8 list-disc">
|
||||
@foreach (currentTeam()->projects as $resource)
|
||||
<li>{{ $resource->name }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
@if (currentTeam()->servers()->count() > 0)
|
||||
<h4 class="py-4">Servers:</h4>
|
||||
<ul class="pl-8 list-disc">
|
||||
@foreach (currentTeam()->servers as $resource)
|
||||
<li>{{ $resource->name }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
@if (currentTeam()->privateKeys()->count() > 0)
|
||||
<h4 class="py-4">Private Keys:</h4>
|
||||
<ul class="pl-8 list-disc">
|
||||
@foreach (currentTeam()->privateKeys as $resource)
|
||||
<li>{{ $resource->name }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
@if (currentTeam()->sources()->count() > 0)
|
||||
<h4 class="py-4">Sources:</h4>
|
||||
<ul class="pl-8 list-disc">
|
||||
@foreach (currentTeam()->sources() as $resource)
|
||||
<li>{{ $resource->name }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
@endif
|
||||
@endif
|
||||
|
||||
</div>
|
||||
@@ -1,12 +0,0 @@
|
||||
<form class="flex flex-col gap-2 pb-6" wire:submit='submit'>
|
||||
<div class="flex items-end gap-2">
|
||||
<h2>General</h2>
|
||||
<x-forms.button type="submit">
|
||||
Save
|
||||
</x-forms.button>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="team.name" label="Name" required />
|
||||
<x-forms.input id="team.description" label="Description" />
|
||||
</div>
|
||||
</form>
|
||||
89
resources/views/livewire/team/index.blade.php
Normal file
89
resources/views/livewire/team/index.blade.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<div>
|
||||
<x-team.navbar />
|
||||
|
||||
<form class="flex flex-col gap-2 pb-6" wire:submit='submit'>
|
||||
<div class="flex items-end gap-2">
|
||||
<h2>General</h2>
|
||||
<x-forms.button type="submit">
|
||||
Save
|
||||
</x-forms.button>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="team.name" label="Name" required />
|
||||
<x-forms.input id="team.description" label="Description" />
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@if (isCloud())
|
||||
<div class="pb-8">
|
||||
<h2>Subscription</h2>
|
||||
@if (data_get(currentTeam(), 'subscription'))
|
||||
<livewire:subscription.actions />
|
||||
@else
|
||||
<x-forms.button class="mt-4"><a class="text-white hover:no-underline"
|
||||
href="{{ route('subscription.index') }}">Subscribe Now</a>
|
||||
</x-forms.button>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
@endif
|
||||
<div>
|
||||
<x-modal yesOrNo modalId="deleteTeam" modalTitle="Delete Team">
|
||||
<x-slot:modalBody>
|
||||
<p>This team be deleted. It is not reversible. <br>Please think again.</p>
|
||||
</x-slot:modalBody>
|
||||
</x-modal>
|
||||
<h2>Danger Zone</h2>
|
||||
<div class="pb-4">Woah. I hope you know what are you doing.</div>
|
||||
<h4 class="pb-4">Delete Team</h4>
|
||||
@if (session('currentTeam.id') === 0)
|
||||
<div>This is the default team. You can't delete it.</div>
|
||||
@elseif(auth()->user()->teams()->get()->count() === 1)
|
||||
<div>You can't delete your last team.</div>
|
||||
@elseif(currentTeam()->subscription && currentTeam()->subscription?->lemon_status !== 'cancelled')
|
||||
<div>Please cancel your subscription before delete this team (Manage My Subscription).</div>
|
||||
@else
|
||||
@if (currentTeam()->isEmpty())
|
||||
<div class="pb-4">This will delete your team. Beware! There is no coming back!</div>
|
||||
<x-forms.button isError isModal modalId="deleteTeam">
|
||||
Delete
|
||||
</x-forms.button>
|
||||
@else
|
||||
<div>
|
||||
<div class="pb-4">You need to delete the following resources to be able to delete the team:</div>
|
||||
@if (currentTeam()->projects()->count() > 0)
|
||||
<h4 class="pb-4">Projects:</h4>
|
||||
<ul class="pl-8 list-disc">
|
||||
@foreach (currentTeam()->projects as $resource)
|
||||
<li>{{ $resource->name }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
@if (currentTeam()->servers()->count() > 0)
|
||||
<h4 class="py-4">Servers:</h4>
|
||||
<ul class="pl-8 list-disc">
|
||||
@foreach (currentTeam()->servers as $resource)
|
||||
<li>{{ $resource->name }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
@if (currentTeam()->privateKeys()->count() > 0)
|
||||
<h4 class="py-4">Private Keys:</h4>
|
||||
<ul class="pl-8 list-disc">
|
||||
@foreach (currentTeam()->privateKeys as $resource)
|
||||
<li>{{ $resource->name }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
@if (currentTeam()->sources()->count() > 0)
|
||||
<h4 class="py-4">Sources:</h4>
|
||||
<ul class="pl-8 list-disc">
|
||||
@foreach (currentTeam()->sources() as $resource)
|
||||
<li>{{ $resource->name }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,4 +1,4 @@
|
||||
<x-layout>
|
||||
<div>
|
||||
<x-team.navbar />
|
||||
<h2>Members</h2>
|
||||
<div class="pt-4 overflow-hidden">
|
||||
@@ -41,4 +41,4 @@
|
||||
</div>
|
||||
<livewire:team.invitations :invitations="$invitations" />
|
||||
@endif
|
||||
</x-layout>
|
||||
</div>
|
||||
@@ -1,4 +1,4 @@
|
||||
<x-layout>
|
||||
<div>
|
||||
<x-team.navbar />
|
||||
<h2 class="pb-4">Notifications</h2>
|
||||
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'email' }" class="flex h-full">
|
||||
@@ -21,4 +21,4 @@
|
||||
<livewire:notifications.discord-settings />
|
||||
</div>
|
||||
</div>
|
||||
</x-layout>
|
||||
</div>
|
||||
@@ -1,4 +1,4 @@
|
||||
<x-layout>
|
||||
<div>
|
||||
<x-team.navbar :team="auth()
|
||||
->user()
|
||||
->currentTeam()" />
|
||||
@@ -30,4 +30,4 @@
|
||||
window.location.href = '/team/storages/' + uuid;
|
||||
}
|
||||
</script>
|
||||
</x-layout>
|
||||
</div>
|
||||
@@ -1,6 +1,6 @@
|
||||
<x-layout>
|
||||
<div>
|
||||
<x-team.navbar :team="auth()
|
||||
->user()
|
||||
->currentTeam()" />
|
||||
<livewire:team.storage.form :storage="$storage" />
|
||||
</x-layout>
|
||||
</div>
|
||||
3
resources/views/livewire/team/storages/create.blade.php
Normal file
3
resources/views/livewire/team/storages/create.blade.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<div>
|
||||
{{-- If you look to others for fulfillment, you will never truly be fulfilled. --}}
|
||||
</div>
|
||||
@@ -1,5 +0,0 @@
|
||||
<x-layout>
|
||||
<h1 class="py-0">Deployment</h1>
|
||||
<livewire:project.application.heading :application="$application" />
|
||||
<livewire:project.application.deployment-logs :application_deployment_queue="$application_deployment_queue" />
|
||||
</x-layout>
|
||||
@@ -1,5 +0,0 @@
|
||||
<x-layout>
|
||||
<h1>Deployments</h1>
|
||||
<livewire:project.application.heading :application="$application" />
|
||||
<livewire:project.application.deployments :application="$application" :deployments="$deployments" :deployments_count="$deployments_count" />
|
||||
</x-layout>
|
||||
@@ -1,3 +0,0 @@
|
||||
<x-layout>
|
||||
<livewire:project.edit :project="$project" />
|
||||
</x-layout>
|
||||
@@ -2,11 +2,11 @@
|
||||
<x-security.navbar />
|
||||
<div class="flex gap-2">
|
||||
<h2 class="pb-4">Private Keys</h2>
|
||||
<a href="{{ route('security.private-key.new') }}"><x-forms.button>+ Add</x-forms.button></a>
|
||||
<a href="{{ route('security.private-key.create') }}"><x-forms.button>+ Add</x-forms.button></a>
|
||||
</div>
|
||||
<div class="grid gap-2 lg:grid-cols-2">
|
||||
@forelse ($privateKeys as $key)
|
||||
<a class="text-center hover:no-underline box group"
|
||||
<a class="text-center hover:no-underline box group"
|
||||
href="{{ route('security.private-key.show', ['private_key_uuid' => data_get($key, 'uuid')]) }}">
|
||||
<div class="group-hover:text-white">
|
||||
<div>{{ $key->name }}</div>
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<x-layout>
|
||||
<h1>Create a new Private Key</h1>
|
||||
<div class="subtitle ">Private Keys are used to connect to your servers without passwords.</div>
|
||||
<livewire:private-key.create />
|
||||
</x-layout>
|
||||
@@ -1,4 +0,0 @@
|
||||
<x-layout>
|
||||
<x-security.navbar />
|
||||
<livewire:private-key.change :private_key="$private_key" />
|
||||
</x-layout>
|
||||
@@ -1,5 +0,0 @@
|
||||
<x-layout-subscription>
|
||||
<x-settings.navbar />
|
||||
<h2>Resale License</h2>
|
||||
<livewire:check-license />
|
||||
</x-layout-subscription>
|
||||
@@ -1,5 +0,0 @@
|
||||
<x-layout>
|
||||
<h1>New Team</h1>
|
||||
<div class="subtitle">Add a new team</div>
|
||||
<livewire:team.create />
|
||||
</x-layout>
|
||||
@@ -1,18 +0,0 @@
|
||||
<x-layout>
|
||||
<x-team.navbar />
|
||||
<livewire:team.form />
|
||||
@if (isCloud())
|
||||
<div class="pb-8">
|
||||
<h2>Subscription</h2>
|
||||
@if (data_get(currentTeam(), 'subscription'))
|
||||
<livewire:subscription.actions />
|
||||
@else
|
||||
<x-forms.button class="mt-4"><a class="text-white hover:no-underline"
|
||||
href="{{ route('subscription.index') }}">Subscribe Now</a>
|
||||
</x-forms.button>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
@endif
|
||||
<livewire:team.delete />
|
||||
</x-layout>
|
||||
@@ -1,3 +0,0 @@
|
||||
<x-layout>
|
||||
<livewire:team.storage.create />
|
||||
</x-layout>
|
||||
Reference in New Issue
Block a user