Merge branch 'main' into fix-typos

This commit is contained in:
Andras Bacsai
2024-01-10 11:55:33 +01:00
committed by GitHub
153 changed files with 1770 additions and 1523 deletions

View File

@@ -1,3 +0,0 @@
<x-layout-simple>
<livewire:force-password-reset />
</x-layout-simple>

View File

@@ -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" />

View File

@@ -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

View File

@@ -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>

View File

@@ -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())

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -1,3 +1,3 @@
<x-emails.layout>
Verify your email [here]({{ $url }}).
Verify your email [here]({{ $url }}).
</x-emails.layout>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View 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>

View File

@@ -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"

View File

@@ -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>

View File

@@ -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>

View 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>

View File

@@ -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())

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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())

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View 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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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">

View 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>

View File

@@ -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'>

View File

@@ -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>

View 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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View 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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -1,6 +1,6 @@
<x-layout>
<div>
<x-team.navbar :team="auth()
->user()
->currentTeam()" />
<livewire:team.storage.form :storage="$storage" />
</x-layout>
</div>

View File

@@ -0,0 +1,3 @@
<div>
{{-- If you look to others for fulfillment, you will never truly be fulfilled. --}}
</div>

View File

@@ -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>

View File

@@ -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>

View File

@@ -1,3 +0,0 @@
<x-layout>
<livewire:project.edit :project="$project" />
</x-layout>

View File

@@ -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>

View File

@@ -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>

View File

@@ -1,4 +0,0 @@
<x-layout>
<x-security.navbar />
<livewire:private-key.change :private_key="$private_key" />
</x-layout>

View File

@@ -1,5 +0,0 @@
<x-layout-subscription>
<x-settings.navbar />
<h2>Resale License</h2>
<livewire:check-license />
</x-layout-subscription>

View File

@@ -1,5 +0,0 @@
<x-layout>
<h1>New Team</h1>
<div class="subtitle">Add a new team</div>
<livewire:team.create />
</x-layout>

View File

@@ -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>

View File

@@ -1,3 +0,0 @@
<x-layout>
<livewire:team.storage.create />
</x-layout>