Merge pull request #2100 from coollabsio/next

v4.0.0-beta.272
This commit is contained in:
Andras Bacsai 2024-05-02 13:20:14 +02:00 committed by GitHub
commit 56be0744f0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 306 additions and 265 deletions

View File

@ -318,10 +318,15 @@ public function handle(): void
private function backup_standalone_mongodb(string $databaseWithCollections): void
{
try {
ray($this->database->toArray());
$url = $this->database->get_db_url(useInternal: true);
if ($databaseWithCollections === 'all') {
$commands[] = "mkdir -p " . $this->backup_dir;
$commands[] = "docker exec $this->container_name mongodump --authenticationDatabase=admin --uri=$url --gzip --archive > $this->backup_location";
if (str($this->database->image)->startsWith('mongo:4.0')) {
$commands[] = "docker exec $this->container_name mongodump --uri=$url --gzip --archive > $this->backup_location";
} else {
$commands[] = "docker exec $this->container_name mongodump --authenticationDatabase=admin --uri=$url --gzip --archive > $this->backup_location";
}
} else {
if (str($databaseWithCollections)->contains(':')) {
$databaseName = str($databaseWithCollections)->before(':');
@ -332,9 +337,17 @@ private function backup_standalone_mongodb(string $databaseWithCollections): voi
}
$commands[] = "mkdir -p " . $this->backup_dir;
if ($collectionsToExclude->count() === 0) {
$commands[] = "docker exec $this->container_name mongodump --authenticationDatabase=admin --uri=$url --db $databaseName --gzip --archive > $this->backup_location";
if (str($this->database->image)->startsWith('mongo:4.0')) {
$commands[] = "docker exec $this->container_name mongodump --uri=$url --gzip --archive > $this->backup_location";
} else {
$commands[] = "docker exec $this->container_name mongodump --authenticationDatabase=admin --uri=$url --db $databaseName --gzip --archive > $this->backup_location";
}
} else {
$commands[] = "docker exec $this->container_name mongodump --authenticationDatabase=admin --uri=$url --db $databaseName --gzip --excludeCollection " . $collectionsToExclude->implode(' --excludeCollection ') . " --archive > $this->backup_location";
if (str($this->database->image)->startsWith('mongo:4.0')) {
$commands[] = "docker exec $this->container_name mongodump --uri=$url --gzip --excludeCollection " . $collectionsToExclude->implode(' --excludeCollection ') . " --archive > $this->backup_location";
} else {
$commands[] = "docker exec $this->container_name mongodump --authenticationDatabase=admin --uri=$url --db $databaseName --gzip --excludeCollection " . $collectionsToExclude->implode(' --excludeCollection ') . " --archive > $this->backup_location";
}
}
}
$this->backup_output = instant_remote_process($commands, $this->server);

View File

@ -20,11 +20,12 @@ class SendMessageToDiscordJob implements ShouldQueue, ShouldBeEncrypted
* @var int
*/
public $tries = 5;
public $backoff = 10;
/**
* The maximum number of unhandled exceptions to allow before failing.
*/
public int $maxExceptions = 3;
public int $maxExceptions = 5;
public function __construct(
public string $text,

View File

@ -91,15 +91,35 @@ public function getLogs($refresh = false)
if ($this->container) {
if ($this->showTimeStamps) {
if ($this->server->isSwarm()) {
$sshCommand = generateSshCommand($this->server, "docker service logs -n {$this->numberOfLines} -t {$this->container}");
$command = "docker service logs -n {$this->numberOfLines} -t {$this->container}";
if ($this->server->isNonRoot()) {
$command = parseCommandsByLineForSudo(collect($command), $this->server);
$command = $command[0];
}
$sshCommand = generateSshCommand($this->server, $command);
} else {
$sshCommand = generateSshCommand($this->server, "docker logs -n {$this->numberOfLines} -t {$this->container}");
$command = "docker logs -n {$this->numberOfLines} -t {$this->container}";
if ($this->server->isNonRoot()) {
$command = parseCommandsByLineForSudo(collect($command), $this->server);
$command = $command[0];
}
$sshCommand = generateSshCommand($this->server, $command);
}
} else {
if ($this->server->isSwarm()) {
$sshCommand = generateSshCommand($this->server, "docker service logs -n {$this->numberOfLines} {$this->container}");
$command = "docker service logs -n {$this->numberOfLines} {$this->container}";
if ($this->server->isNonRoot()) {
$command = parseCommandsByLineForSudo(collect($command), $this->server);
$command = $command[0];
}
$sshCommand = generateSshCommand($this->server, $command);
} else {
$sshCommand = generateSshCommand($this->server, "docker logs -n {$this->numberOfLines} {$this->container}");
$command = "docker logs -n {$this->numberOfLines} {$this->container}";
if ($this->server->isNonRoot()) {
$command = parseCommandsByLineForSudo(collect($command), $this->server);
$command = $command[0];
}
$sshCommand = generateSshCommand($this->server, $command);
}
}
if ($refresh) {

View File

@ -16,13 +16,13 @@ class Create extends Component
public string $endpoint;
public S3Storage $storage;
protected $rules = [
'name' => 'nullable|min:3|max:255',
'name' => 'required|min:3|max:255',
'description' => 'nullable|min:3|max:255',
'region' => 'required|max:255',
'key' => 'required|max:255',
'secret' => 'required|max:255',
'bucket' => 'required|max:255',
'endpoint' => 'nullable|url|max:255',
'endpoint' => 'required|url|max:255',
];
protected $validationAttributes = [
'name' => 'Name',

View File

@ -43,15 +43,8 @@ public function __construct(Application $application, string $deployment_uuid, A
public function via(object $notifiable): array
{
$channels = setNotificationChannels($notifiable, 'deployments');
if (isCloud()) {
$channels = array_filter($channels, function ($channel) {
return $channel !== 'App\Notifications\Channels\EmailChannel';
});
}
return $channels;
return setNotificationChannels($notifiable, 'deployments');
}
public function toMail(): MailMessage
{
$mail = new MailMessage();

View File

@ -32,6 +32,7 @@
'basic' => env('LIMIT_SERVER_BASIC', 2),
'pro' => env('LIMIT_SERVER_PRO', 10),
'ultimate' => env('LIMIT_SERVER_ULTIMATE', 25),
'dynamic' => env('LIMIT_SERVER_DYNAMIC', 2),
],
'email' => [
'zero' => true,
@ -39,6 +40,7 @@
'basic' => true,
'pro' => true,
'ultimate' => true,
'dynamic' => true,
],
],
];

View File

@ -7,7 +7,7 @@
// The release version of your application
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
'release' => '4.0.0-beta.271',
'release' => '4.0.0-beta.272',
// When left empty or `null` the Laravel environment will be used
'environment' => config('app.env'),

View File

@ -1,3 +1,3 @@
<?php
return '4.0.0-beta.271';
return '4.0.0-beta.272';

View File

@ -5,14 +5,14 @@
<h1>Dashboard</h1>
<div class="subtitle">Your self-hosted infrastructure.</div>
@if (request()->query->get('success'))
<div class="mb-10 rounded dark:text-white alert-success">
<div class="items-center justify-center mb-10 font-bold rounded alert alert-success">
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 stroke-current shrink-0" fill="none"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span>Your subscription has been activated! Welcome onboard! <br>It could take a few seconds before your
subscription is activated.<br> Please be patient.</span>
Your subscription has been activated! Welcome onboard! <br>It could take a few seconds before your
subscription is activated.<br> Please be patient.
</div>
@endif
<h3 class="pb-4">Projects</h3>

View File

@ -1,58 +1,53 @@
<div>
<h2>Resource Operations</h2>
<div class="pb-4">You can easily make different kind of operations on this resource.</div>
<h4>Clone</h4>
<div class="pb-8">
<div class="pb-2">
Clone this resource to another project / environment.
</div>
<div class="flex flex-col">
<h3>Clone</h3>
<div class="pb-4">To another project / environment on a different server.</div>
<div class="pb-4">
<div class="flex flex-col flex-wrap gap-2">
@foreach ($servers->sortBy('id') as $server)
<div>
<div class="grid grid-cols-1 gap-2 pb-4 lg:grid-cols-4">
@foreach ($server->destinations() as $destination)
<x-modal-confirmation action="cloneTo({{ data_get($destination, 'id') }})">
<x:slot name="content">
<div class="box">
<div class="flex flex-col">
<div class="box-title">{{ $server->name }}</div>
<div class="box-description">{{ $destination->name }}</div>
</div>
</div>
</x:slot>
<div>You are about to clone this resource.</div>
</x-modal-confirmation>
@endforeach
</div>
</div>
<h5>Server: <span class="font-bold text-white">{{ $server->name }}</span></h5>
@foreach ($server->destinations() as $destination)
<x-modal-confirmation action="cloneTo({{ data_get($destination, 'id') }})">
<x:slot name="content">
<div class="box group">
<div class="flex flex-col">
<div class="box-title">Network</div>
<div class="box-description">{{ $destination->name }}</div>
</div>
</div>
</x:slot>
<div>You are about to clone this resource.</div>
</x-modal-confirmation>
@endforeach
@endforeach
</div>
</div>
<h4>Move</h4>
<h3>Move</h3>
<div class="pb-4">Between projects / environments.</div>
<div>
<div class="pb-8">
<div class="pb-2">
This resource is currently in the <span
class="font-bold dark:text-warning">{{ $resource->environment->project->name }} /
{{ $resource->environment->name }}</span> environment.
</div>
<div class="flex flex-wrap gap-2">
<div class="flex flex-col flex-wrap gap-2">
@forelse ($projects as $project)
<div class="flex flex-wrap gap-2">
@foreach ($project->environments as $environment)
<x-modal-confirmation action="moveTo({{ data_get($environment, 'id') }})">
<x:slot name="content">
<div class="box">
<div class="flex flex-col">
<div class="box-title">{{ $project->name }}</div>
<div class="box-description">environment: {{ $environment->name }}
</div>
</div>
<h5>Project: <span class="font-bold text-white">{{ $project->name }}</span></h5>
@foreach ($project->environments as $environment)
<x-modal-confirmation action="moveTo({{ data_get($environment, 'id') }})">
<x:slot name="content">
<div class="box group">
<div class="flex flex-col">
<div class="box-title">Environment</div>
<div class="box-description">{{ $environment->name }}</div>
</div>
</x:slot>
<div>You are about to move this resource.</div>
</x-modal-confirmation>
@endforeach
</div>
</div>
</x:slot>
<div>You are about to move this resource.</div>
</x-modal-confirmation>
@endforeach
@empty
<div>No projects found to move to</div>
@endforelse

View File

@ -4,8 +4,12 @@
@if ($isFirst)
<x-forms.input id="storage.name" label="Volume Name" required
helper="Warning: Changing the volume name after the initial start could cause problems. Only use it when you know what are you doing." />
<x-forms.input id="storage.host_path" label="Source Path (on host)" helper="Warning: Changing the source path after the initial start could cause problems. Only use it when you know what are you doing." />
<x-forms.input id="storage.host_path" label="Source Path (on host)"
helper="Warning: Changing the source path after the initial start could cause problems. Only use it when you know what are you doing." />
<x-forms.input id="storage.mount_path" label="Destination Path (in container)" required readonly />
<x-forms.button type="submit">
Update
</x-forms.button>
@else
<x-forms.input id="storage.name" required readonly
helper="Warning: Changing the volume name after the initial start could cause problems. Only use it when you know what are you doing." />

View File

@ -2,11 +2,11 @@
<div class="subtitle">S3 Storage used to save backups / files.</div>
<form class="flex flex-col gap-2" wire:submit='submit'>
<div class="flex gap-2">
<x-forms.input label="Name" id="name" />
<x-forms.input required label="Name" id="name" />
<x-forms.input label="Description" id="description" />
</div>
<div class="flex gap-2">
<x-forms.input type="url" label="Endpoint" id="endpoint" />
<x-forms.input required type="url" label="Endpoint" id="endpoint" />
<x-forms.input required label="Bucket" id="bucket" />
<x-forms.input required label="Region" id="region" />
</div>

View File

@ -3,34 +3,50 @@
<div class="pt-4">
<h2>Your current plan</h2>
<div class="pb-4">Tier: <strong
class="dark:text-warning">{{ data_get(currentTeam(), 'subscription')->type() }}</strong></div>
class="dark:text-warning">
@if (data_get(currentTeam(), 'subscription')->type() == 'dynamic')
Pay-as-you-go
@else
{{ data_get(currentTeam(), 'subscription')->type() }}
@endif
</strong></div>
@if (currentTeam()->subscription->stripe_cancel_at_period_end)
<div>Subscription is active but on cancel period.</div>
<div class="pb-2">Subscription is active but on cancel period.</div>
@else
<div>Subscription is active. Last invoice is
<div class="pb-2">Subscription is active. Last invoice is
{{ currentTeam()->subscription->stripe_invoice_paid ? 'paid' : 'not paid' }}.</div>
@endif
<div>Number of paid servers: {{ $server_limits }}</div>
<div>Currently active servers: {{ currentTeam()->servers->count() }}</div>
<div class="flex items-center gap-2">
<div class="w-48">Number of paid servers:</div>
<div class="text-xl font-bold dark:text-white">{{ $server_limits }}</div>
</div>
<div class="flex items-center gap-2">
<div class="w-48">Currently active servers:</div>
<div class="text-xl font-bold dark:text-white">{{ currentTeam()->servers->count() }}</div>
</div>
@if (currentTeam()->serverOverflow())
<div class="py-4"><span class="font-bold text-red-500">WARNING:</span> You must delete
{{ currentTeam()->servers->count() - $server_limits }} servers,
or upgrade your subscription. {{ currentTeam()->servers->count() - $server_limits }} servers will be
deactivated.</div>
@endif
<x-forms.button class="gap-2" wire:click='stripeCustomerPortal'>Change Server Quantity
</x-forms.button>
<h2 class="pt-4">Manage your subscription</h2>
<div class="pb-4">Cancel, upgrade or downgrade your subscription.</div>
<div class="flex gap-2">
<x-forms.button class="gap-2" wire:click='stripeCustomerPortal'>Go to <svg xmlns="http://www.w3.org/2000/svg"
class="w-12 " viewBox="0 0 512 214">
<x-forms.button class="gap-2" wire:click='stripeCustomerPortal'>Go to <svg
xmlns="http://www.w3.org/2000/svg" class="w-12 " viewBox="0 0 512 214">
<path fill="#635BFF"
d="M512 110.08c0-36.409-17.636-65.138-51.342-65.138c-33.85 0-54.33 28.73-54.33 64.854c0 42.808 24.179 64.426 58.88 64.426c16.925 0 29.725-3.84 39.396-9.244v-28.445c-9.67 4.836-20.764 7.823-34.844 7.823c-13.796 0-26.027-4.836-27.591-21.618h69.547c0-1.85.284-9.245.284-12.658Zm-70.258-13.511c0-16.071 9.814-22.756 18.774-22.756c8.675 0 17.92 6.685 17.92 22.756h-36.694Zm-90.31-51.627c-13.939 0-22.899 6.542-27.876 11.094l-1.85-8.818h-31.288v165.83l35.555-7.537l.143-40.249c5.12 3.698 12.657 8.96 25.173 8.96c25.458 0 48.64-20.48 48.64-65.564c-.142-41.245-23.609-63.716-48.498-63.716Zm-8.534 97.991c-8.391 0-13.37-2.986-16.782-6.684l-.143-52.765c3.698-4.124 8.818-6.968 16.925-6.968c12.942 0 21.902 14.506 21.902 33.137c0 19.058-8.818 33.28-21.902 33.28ZM241.493 36.551l35.698-7.68V0l-35.698 7.538V36.55Zm0 10.809h35.698v124.444h-35.698V47.36Zm-38.257 10.524L200.96 47.36h-30.72v124.444h35.556V87.467c8.39-10.951 22.613-8.96 27.022-7.396V47.36c-4.551-1.707-21.191-4.836-29.582 10.524Zm-71.112-41.386l-34.702 7.395l-.142 113.92c0 21.05 15.787 36.551 36.836 36.551c11.662 0 20.195-2.133 24.888-4.693V140.8c-4.55 1.849-27.022 8.391-27.022-12.658V77.653h27.022V47.36h-27.022l.142-30.862ZM35.982 83.484c0-5.546 4.551-7.68 12.09-7.68c10.808 0 24.461 3.272 35.27 9.103V51.484c-11.804-4.693-23.466-6.542-35.27-6.542C19.2 44.942 0 60.018 0 85.192c0 39.252 54.044 32.995 54.044 49.92c0 6.541-5.688 8.675-13.653 8.675c-11.804 0-26.88-4.836-38.827-11.378v33.849c13.227 5.689 26.596 8.106 38.827 8.106c29.582 0 49.92-14.648 49.92-40.106c-.142-42.382-54.329-34.845-54.329-50.774Z" />
</svg></x-forms.button>
</svg>
</x-forms.button>
</div>
</div>
<div class="pt-4">
If you have any problem, please <a class="dark:text-white underline" href="{{ config('coolify.contact') }}"
If you have any problem, please <a class="underline dark:text-white" href="{{ config('coolify.contact') }}"
target="_blank">contact us.</a>
</div>
@endif
@ -40,7 +56,7 @@ class="w-12 " viewBox="0 0 512 214">
@if (currentTeam()->subscription->lemon_status === 'cancelled')
<div class="pb-4">Subscriptions ends at: {{ getRenewDate() }}</div>
<div class="py-4">If you would like to change the subscription to a lower/higher plan, <a
class="dark:text-white underline" href="{{ config('coolify.contact') }}" target="_blank">please
class="underline dark:text-white" href="{{ config('coolify.contact') }}" target="_blank">please
contact
us.</a></div>
@else

View File

@ -20,7 +20,7 @@
</div>
@endif
@if (config('subscription.provider') !== null)
@if (config('subscription.provider') === 'stripe')
<livewire:subscription.pricing-plans />
@endif
</div>

View File

@ -1,120 +0,0 @@
<div x-data="{ selected: 'monthly' }" class="w-full pb-20">
<div class="max-w-2xl px-6 mx-auto lg:px-8">
<div class="flex justify-center">
<fieldset
class="grid grid-cols-2 p-1 text-xs font-semibold leading-5 text-center rounded dark:text-white gap-x-1 bg-white/5">
<legend class="sr-only">Payment frequency</legend>
<label class="cursor-pointer rounded px-2.5 py-1"
:class="selected === 'monthly' ? 'bg-coollabs-100 text-white' : ''">
<input type="radio" x-on:click="selected = 'monthly'" name="frequency" value="monthly"
class="sr-only">
<span>Monthly</span>
</label>
<label class="cursor-pointer rounded px-2.5 py-1"
:class="selected === 'yearly' ? 'bg-coollabs-100 text-white' : ''">
<input type="radio" x-on:click="selected = 'yearly'" name="frequency" value="annually"
class="sr-only">
<span>Annually</span>
</label>
</fieldset>
</div>
<div x-show="selected === 'monthly'" class="flex justify-center h-10 mt-3 text-sm leading-6 ">
<div>Save <span class="font-bold text-black dark:text-warning">10%</span> annually with the yearly plans.
</div>
</div>
<div x-show="selected === 'yearly'" class="flex justify-center h-10 mt-3 text-sm leading-6 ">
<div>
</div>
</div>
<div class="flow-root mt-12">
<div class="pb-10 text-xl text-center">For the detailed list of features, please visit our landing page: <a
class="font-bold underline dark:text-white" href="https://coolify.io">coolify.io</a></div>
<div
class="grid max-w-sm grid-cols-1 -mt-16 divide-y divide-neutral-200 dark:divide-coolgray-500 isolate gap-y-16 sm:mx-auto lg:-mx-8 lg:mt-0 lg:max-w-none lg:grid-cols-1 lg:divide-x lg:divide-y-0 xl:-mx-4">
<div class="pt-16 lg:px-8 lg:pt-0 xl:px-14">
<h3 id="tier-dynamic" class="text-4xl font-semibold leading-7 dark:text-white">Dynamic</h3>
<p class="flex items-baseline mt-6 gap-x-1">
<span x-show="selected === 'monthly'" x-cloak>
<span class="text-4xl font-bold tracking-tight dark:text-white">$5</span>
<span class="text-sm font-semibold leading-6 "> for the first 2 servers</span>
</span>
<span x-show="selected === 'yearly'" x-cloak>
<span class="text-4xl font-bold tracking-tight dark:text-white">$4</span>
<span class="text-sm font-semibold leading-6 ">/month + VAT</span>
</span>
</p>
<p class="flex items-baseline gap-x-1">
<span x-show="selected === 'monthly'" x-cloak>
<span class="text-2xl font-bold tracking-tight dark:text-white">$3</span>
<span class="text-sm font-semibold leading-6 "> for any additional</span>
</span>
<span x-show="selected === 'yearly'" x-cloak>
<span class="text-4xl font-bold tracking-tight dark:text-white">$4</span>
<span class="text-sm font-semibold leading-6 ">/month + VAT</span>
</span>
</p>
<span x-show="selected === 'monthly'" x-cloak>
<span>billed monthly (+VAT)</span>
</span>
<span x-show="selected === 'yearly'" x-cloak>
<span>billed annually</span>
</span>
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-basic"
class="w-full h-10 buyme" wire:click="subscribeStripe('dynamic-monthly')">
{{ $isTrial ? 'Start Trial' : 'Subscribe' }}
</x-forms.button>
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-basic"
class="w-full h-10 buyme" wire:click="subscribeStripe('dynamic-yearly')">
{{ $isTrial ? 'Start Trial' : 'Subscribe' }}
</x-forms.button>
<p class="mt-10 text-sm leading-6 dark:text-white h-[6.5rem]">Begin hosting your own services in the
cloud.
</p>
<ul role="list" class="space-y-3 text-sm leading-6 ">
<li class="flex">
<svg class="flex-none w-5 h-6 mr-3 dark:text-warning" viewBox="0 0 20 20"
fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.775 0 001.137-.089l4-5.5z"
clip-rule="evenodd" />
</svg>
Connect <span class="px-1 font-bold dark:text-white">2</span> servers
</li>
<li class="flex gap-x-3">
<svg class="flex-none w-5 h-6 dark:text-warning" viewBox="0 0 20 20" fill="currentColor"
aria-hidden="true">
<path fill-rule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
clip-rule="evenodd" />
</svg>
Included Email System
</li>
<li class="flex gap-x-3">
<svg class="flex-none w-5 h-6 dark:text-warning" viewBox="0 0 20 20" fill="currentColor"
aria-hidden="true">
<path fill-rule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
clip-rule="evenodd" />
</svg>
Email Support
</li>
<li class="flex font-bold dark:text-white gap-x-3">
<svg width="512" height="512" class="flex-none w-5 h-6 text-green-600"
viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
stroke-width="2">
<path
d="M4 13a8 8 0 0 1 7 7a6 6 0 0 0 3-5a9 9 0 0 0 6-8a3 3 0 0 0-3-3a9 9 0 0 0-8 6a6 6 0 0 0-5 3" />
<path d="M7 14a6 6 0 0 0-3 6a6 6 0 0 0 6-3m4-8a1 1 0 1 0 2 0a1 1 0 1 0-2 0" />
</g>
</svg>
+ All upcoming features
</li>
</ul>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,67 @@
<x-pricing-plans>
@if (config('subscription.provider') === 'stripe')
<x-slot:basic>
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-basic" class="w-full h-10 buyme"
wire:click="subscribeStripe('basic-monthly')">
{{ $isTrial ? 'Start Trial' : 'Subscribe' }}
</x-forms.button>
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-basic" class="w-full h-10 buyme"
wire:click="subscribeStripe('basic-yearly')">
{{ $isTrial ? 'Start Trial' : 'Subscribe' }}
</x-forms.button>
</x-slot:basic>
<x-slot:pro>
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-pro" class="w-full h-10 buyme"
wire:click="subscribeStripe('pro-monthly')">
{{ $isTrial ? 'Start Trial' : 'Subscribe' }}
</x-forms.button>
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-pro" class="w-full h-10 buyme"
wire:click="subscribeStripe('pro-yearly')"> {{ $isTrial ? 'Start Trial' : 'Subscribe' }}
</x-forms.button>
</x-slot:pro>
<x-slot:ultimate>
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-ultimate" class="w-full h-10 buyme"
wire:click="subscribeStripe('ultimate-monthly')">
{{ $isTrial ? 'Start Trial' : 'Subscribe' }}
</x-forms.button>
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-ultimate" class="w-full h-10 buyme"
wire:click="subscribeStripe('ultimate-yearly')"> {{ $isTrial ? 'Start Trial' : 'Subscribe' }}
</x-forms.button>
</x-slot:ultimate>
@endif
@if (config('subscription.provider') === 'paddle')
<x-paddle />
@endif
@if (config('subscription.provider') === 'lemon')
<x-slot:basic>
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-basic"
class="w-full h-10 buyme" wire:click="getSubscriptionLink('basic-monthly')"> Subscribe
</x-forms.button>
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-basic"
class="w-full h-10 buyme" wire:click="getSubscriptionLink('basic-yearly')"> Subscribe
</x-forms.button>
</x-slot:basic>
<x-slot:pro>
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-pro"
class="w-full h-10 buyme" wire:click="getSubscriptionLink('pro-monthly')"> Subscribe
</x-forms.button>
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-pro" class="w-full h-10 buyme"
wire:click="getSubscriptionLink('pro-yearly')"> Subscribe
</x-forms.button>
</x-slot:pro>
<x-slot:ultimate>
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-ultimate"
class="w-full h-10 buyme" wire:click="getSubscriptionLink('ultimate-monthly')"> Subscribe
</x-forms.button>
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-ultimate"
class="w-full h-10 buyme" wire:click="getSubscriptionLink('ultimate-yearly')"> Subscribe
</x-forms.button>
</x-slot:ultimate>
@endif
</x-pricing-plans>

View File

@ -1,67 +1,117 @@
<x-pricing-plans>
@if (config('subscription.provider') === 'stripe')
<x-slot:basic>
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-basic" class="w-full h-10 buyme"
wire:click="subscribeStripe('basic-monthly')">
{{ $isTrial ? 'Start Trial' : 'Subscribe' }}
</x-forms.button>
<div x-data="{ selected: 'monthly' }" class="w-full pb-20">
<div class="max-w-3xl px-6 mx-auto lg:px-8">
<div class="flex justify-center">
<fieldset
class="grid grid-cols-2 p-1 text-xs font-semibold leading-5 text-center rounded dark:text-white gap-x-1 bg-white/5">
<legend class="sr-only">Payment frequency</legend>
<label class="cursor-pointer rounded px-2.5 py-1"
:class="selected === 'monthly' ? 'bg-coollabs-100 text-white' : ''">
<input type="radio" x-on:click="selected = 'monthly'" name="frequency" value="monthly"
class="sr-only">
<span>Monthly</span>
</label>
<label class="cursor-pointer rounded px-2.5 py-1"
:class="selected === 'yearly' ? 'bg-coollabs-100 text-white' : ''">
<input type="radio" x-on:click="selected = 'yearly'" name="frequency" value="annually"
class="sr-only">
<span>Annually</span>
</label>
</fieldset>
</div>
<div x-show="selected === 'monthly'" class="flex justify-center h-10 mt-3 text-sm leading-6 ">
<div>Save <span class="font-bold text-black dark:text-warning">10%</span> annually with the yearly plans.
</div>
</div>
<div x-show="selected === 'yearly'" class="flex justify-center h-10 mt-3 text-sm leading-6 ">
<div>
</div>
</div>
<div class="flow-root mt-12">
{{-- <div class="pb-10 text-xl text-center">For the detailed list of features, please visit our landing page: <a
class="font-bold underline dark:text-white" href="https://coolify.io">coolify.io</a></div> --}}
<div
class="grid max-w-sm grid-cols-1 -mt-16 divide-y divide-neutral-200 dark:divide-coolgray-500 isolate gap-y-16 sm:mx-auto lg:-mx-8 lg:mt-0 lg:max-w-none lg:grid-cols-1 lg:divide-x lg:divide-y-0 xl:-mx-4">
<div class="pt-16 lg:px-8 lg:pt-0 xl:px-14">
<h3 id="tier-dynamic" class="text-4xl font-semibold leading-7 dark:text-white">Pay-as-you-go</h3>
<p class="flex items-baseline mt-6 gap-x-1">
<span x-show="selected === 'monthly'" x-cloak>
<span class="text-4xl font-bold tracking-tight dark:text-white">$5</span>
<span class="text-sm font-semibold leading-6 "> for 2 servers</span>
</span>
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-basic" class="w-full h-10 buyme"
wire:click="subscribeStripe('basic-yearly')">
{{ $isTrial ? 'Start Trial' : 'Subscribe' }}
</x-forms.button>
</x-slot:basic>
<x-slot:pro>
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-pro" class="w-full h-10 buyme"
wire:click="subscribeStripe('pro-monthly')">
{{ $isTrial ? 'Start Trial' : 'Subscribe' }}
</x-forms.button>
<span x-show="selected === 'yearly'" x-cloak>
<span class="text-4xl font-bold tracking-tight dark:text-white">$4</span>
<span class="text-sm font-semibold leading-6 "> for 2 servers</span>
</span>
</p>
<p class="flex items-baseline mb-4 gap-x-1">
<span x-show="selected === 'monthly'" x-cloak>
<span class="text-sm font-semibold tracking-tight dark:text-white">$3</span>
<span class="text-sm font-semibold leading-6 "> per server from 3+ servers</span>
</span>
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-pro" class="w-full h-10 buyme"
wire:click="subscribeStripe('pro-yearly')"> {{ $isTrial ? 'Start Trial' : 'Subscribe' }}
</x-forms.button>
</x-slot:pro>
<x-slot:ultimate>
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-ultimate" class="w-full h-10 buyme"
wire:click="subscribeStripe('ultimate-monthly')">
{{ $isTrial ? 'Start Trial' : 'Subscribe' }}
</x-forms.button>
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-ultimate" class="w-full h-10 buyme"
wire:click="subscribeStripe('ultimate-yearly')"> {{ $isTrial ? 'Start Trial' : 'Subscribe' }}
</x-forms.button>
</x-slot:ultimate>
@endif
@if (config('subscription.provider') === 'paddle')
<x-paddle />
@endif
@if (config('subscription.provider') === 'lemon')
<x-slot:basic>
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-basic"
class="w-full h-10 buyme" wire:click="getSubscriptionLink('basic-monthly')"> Subscribe
</x-forms.button>
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-basic"
class="w-full h-10 buyme" wire:click="getSubscriptionLink('basic-yearly')"> Subscribe
</x-forms.button>
</x-slot:basic>
<x-slot:pro>
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-pro"
class="w-full h-10 buyme" wire:click="getSubscriptionLink('pro-monthly')"> Subscribe
</x-forms.button>
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-pro" class="w-full h-10 buyme"
wire:click="getSubscriptionLink('pro-yearly')"> Subscribe
</x-forms.button>
</x-slot:pro>
<x-slot:ultimate>
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-ultimate"
class="w-full h-10 buyme" wire:click="getSubscriptionLink('ultimate-monthly')"> Subscribe
</x-forms.button>
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-ultimate"
class="w-full h-10 buyme" wire:click="getSubscriptionLink('ultimate-yearly')"> Subscribe
</x-forms.button>
</x-slot:ultimate>
@endif
</x-pricing-plans>
<span x-show="selected === 'yearly'" x-cloak>
<span class="text-sm font-semibold tracking-tight dark:text-white">$2.7</span>
<span class="text-sm font-semibold leading-6 "> per server from 3+ servers</span>
</span>
</p>
<span x-show="selected === 'monthly'" x-cloak>
<span class="dark:text-white p">billed monthly (+VAT)</span>
</span>
<span x-show="selected === 'yearly'" x-cloak>
<span class="dark:text-white">billed annually (+VAT)</span>
</span>
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-basic"
class="w-full h-10 buyme" wire:click="subscribeStripe('dynamic-monthly')">
Subscribe
</x-forms.button>
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-basic"
class="w-full h-10 buyme" wire:click="subscribeStripe('dynamic-yearly')">
Subscribe
</x-forms.button>
<ul role="list" class="pt-6 space-y-3 text-sm leading-6">
<li class="flex">
<svg class="flex-none w-5 h-6 mr-3 dark:text-warning" viewBox="0 0 20 20"
fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.775 0 001.137-.089l4-5.5z"
clip-rule="evenodd" />
</svg>
Connect <span class="px-1 font-bold dark:text-white">unlimited</span> servers
</li>
<li class="flex gap-x-3">
<svg class="flex-none w-5 h-6 dark:text-warning" viewBox="0 0 20 20" fill="currentColor"
aria-hidden="true">
<path fill-rule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
clip-rule="evenodd" />
</svg>
Free Email Notifications
</li>
<li class="flex gap-x-3">
<svg class="flex-none w-5 h-6 dark:text-warning" viewBox="0 0 20 20" fill="currentColor"
aria-hidden="true">
<path fill-rule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
clip-rule="evenodd" />
</svg>
Support by Email
</li>
<li class="flex font-bold dark:text-white gap-x-3">
<svg width="512" height="512" class="flex-none w-5 h-6 text-green-600"
viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
stroke-width="2">
<path
d="M4 13a8 8 0 0 1 7 7a6 6 0 0 0 3-5a9 9 0 0 0 6-8a3 3 0 0 0-3-3a9 9 0 0 0-8 6a6 6 0 0 0-5 3" />
<path d="M7 14a6 6 0 0 0-3 6a6 6 0 0 0 6-3m4-8a1 1 0 1 0 2 0a1 1 0 1 0-2 0" />
</g>
</svg>
+ All upcoming features
</li>
</ul>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,7 +1,7 @@
{
"coolify": {
"v4": {
"version": "4.0.0-beta.271"
"version": "4.0.0-beta.272"
}
}
}