commit
e9158b7305
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Livewire\Project\Shared;
|
||||
|
||||
use App\Actions\Server\RunCommand;
|
||||
use App\Models\Application;
|
||||
use App\Models\Server;
|
||||
use App\Models\Service;
|
||||
@ -137,7 +138,7 @@ public function runCommand()
|
||||
} else {
|
||||
$exec = "docker exec {$container_name} {$cmd}";
|
||||
}
|
||||
$activity = remote_process([$exec], $server, ignore_errors: true);
|
||||
$activity = RunCommand::run(server: $server, command: $exec);
|
||||
$this->dispatch('activityMonitor', $activity->id);
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
|
@ -3,7 +3,6 @@
|
||||
namespace App\Livewire\Subscription;
|
||||
|
||||
use App\Models\Team;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Livewire\Component;
|
||||
|
||||
class Actions extends Component
|
||||
@ -15,70 +14,6 @@ public function mount()
|
||||
$this->server_limits = Team::serverLimit();
|
||||
}
|
||||
|
||||
public function cancel()
|
||||
{
|
||||
try {
|
||||
$subscription_id = currentTeam()->subscription->lemon_subscription_id;
|
||||
if (! $subscription_id) {
|
||||
throw new \Exception('No subscription found');
|
||||
}
|
||||
$response = Http::withHeaders([
|
||||
'Accept' => 'application/vnd.api+json',
|
||||
'Content-Type' => 'application/vnd.api+json',
|
||||
'Authorization' => 'Bearer '.config('subscription.lemon_squeezy_api_key'),
|
||||
])->delete('https://api.lemonsqueezy.com/v1/subscriptions/'.$subscription_id);
|
||||
$json = $response->json();
|
||||
if ($response->failed()) {
|
||||
$error = data_get($json, 'errors.0.status');
|
||||
if ($error === '404') {
|
||||
throw new \Exception('Subscription not found.');
|
||||
}
|
||||
throw new \Exception(data_get($json, 'errors.0.title', 'Something went wrong. Please try again later.'));
|
||||
} else {
|
||||
$this->dispatch('success', 'Subscription cancelled successfully. Reloading in 5s.');
|
||||
$this->dispatch('reloadWindow', 5000);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function resume()
|
||||
{
|
||||
try {
|
||||
$subscription_id = currentTeam()->subscription->lemon_subscription_id;
|
||||
if (! $subscription_id) {
|
||||
throw new \Exception('No subscription found');
|
||||
}
|
||||
$response = Http::withHeaders([
|
||||
'Accept' => 'application/vnd.api+json',
|
||||
'Content-Type' => 'application/vnd.api+json',
|
||||
'Authorization' => 'Bearer '.config('subscription.lemon_squeezy_api_key'),
|
||||
])->patch('https://api.lemonsqueezy.com/v1/subscriptions/'.$subscription_id, [
|
||||
'data' => [
|
||||
'type' => 'subscriptions',
|
||||
'id' => $subscription_id,
|
||||
'attributes' => [
|
||||
'cancelled' => false,
|
||||
],
|
||||
],
|
||||
]);
|
||||
$json = $response->json();
|
||||
if ($response->failed()) {
|
||||
$error = data_get($json, 'errors.0.status');
|
||||
if ($error === '404') {
|
||||
throw new \Exception('Subscription not found.');
|
||||
}
|
||||
throw new \Exception(data_get($json, 'errors.0.title', 'Something went wrong. Please try again later.'));
|
||||
} else {
|
||||
$this->dispatch('success', 'Subscription resumed successfully. Reloading in 5s.');
|
||||
$this->dispatch('reloadWindow', 5000);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function stripeCustomerPortal()
|
||||
{
|
||||
$session = getStripeCustomerPortalSession(currentTeam());
|
||||
|
@ -15,22 +15,7 @@ public function team()
|
||||
|
||||
public function type()
|
||||
{
|
||||
if (isLemon()) {
|
||||
$basic = explode(',', config('subscription.lemon_squeezy_basic_plan_ids'));
|
||||
$pro = explode(',', config('subscription.lemon_squeezy_pro_plan_ids'));
|
||||
$ultimate = explode(',', config('subscription.lemon_squeezy_ultimate_plan_ids'));
|
||||
|
||||
$subscription = $this->lemon_variant_id;
|
||||
if (in_array($subscription, $basic)) {
|
||||
return 'basic';
|
||||
}
|
||||
if (in_array($subscription, $pro)) {
|
||||
return 'pro';
|
||||
}
|
||||
if (in_array($subscription, $ultimate)) {
|
||||
return 'ultimate';
|
||||
}
|
||||
} elseif (isStripe()) {
|
||||
if (isStripe()) {
|
||||
if (! $this->stripe_plan_id) {
|
||||
return 'zero';
|
||||
}
|
||||
|
@ -1,51 +1,8 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Team;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Stripe\Stripe;
|
||||
|
||||
function getSubscriptionLink($type)
|
||||
{
|
||||
$checkout_id = config("subscription.lemon_squeezy_checkout_id_$type");
|
||||
if (! $checkout_id) {
|
||||
return null;
|
||||
}
|
||||
$user_id = auth()->user()->id;
|
||||
$team_id = currentTeam()->id ?? null;
|
||||
$email = auth()->user()->email ?? null;
|
||||
$name = auth()->user()->name ?? null;
|
||||
$url = "https://store.coollabs.io/checkout/buy/$checkout_id?";
|
||||
if ($user_id) {
|
||||
$url .= "&checkout[custom][user_id]={$user_id}";
|
||||
}
|
||||
if (isset($team_id)) {
|
||||
$url .= "&checkout[custom][team_id]={$team_id}";
|
||||
}
|
||||
if ($email) {
|
||||
$url .= "&checkout[email]={$email}";
|
||||
}
|
||||
if ($name) {
|
||||
$url .= "&checkout[name]={$name}";
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
function getPaymentLink()
|
||||
{
|
||||
return currentTeam()->subscription->lemon_update_payment_menthod_url;
|
||||
}
|
||||
|
||||
function getRenewDate()
|
||||
{
|
||||
return Carbon::parse(currentTeam()->subscription->lemon_renews_at)->format('Y-M-d H:i:s');
|
||||
}
|
||||
|
||||
function getEndDate()
|
||||
{
|
||||
return Carbon::parse(currentTeam()->subscription->lemon_renews_at)->format('Y-M-d H:i:s');
|
||||
}
|
||||
|
||||
function isSubscriptionActive()
|
||||
{
|
||||
if (! isCloud()) {
|
||||
@ -60,12 +17,6 @@ function isSubscriptionActive()
|
||||
if (is_null($subscription)) {
|
||||
return false;
|
||||
}
|
||||
if (isLemon()) {
|
||||
return $subscription->lemon_status === 'active';
|
||||
}
|
||||
// if (isPaddle()) {
|
||||
// return $subscription->paddle_status === 'active';
|
||||
// }
|
||||
if (isStripe()) {
|
||||
return $subscription->stripe_invoice_paid === true;
|
||||
}
|
||||
@ -82,12 +33,6 @@ function isSubscriptionOnGracePeriod()
|
||||
if (! $subscription) {
|
||||
return false;
|
||||
}
|
||||
if (isLemon()) {
|
||||
$is_still_grace_period = $subscription->lemon_ends_at &&
|
||||
Carbon::parse($subscription->lemon_ends_at) > Carbon::now();
|
||||
|
||||
return $is_still_grace_period;
|
||||
}
|
||||
if (isStripe()) {
|
||||
return $subscription->stripe_cancel_at_period_end;
|
||||
}
|
||||
@ -98,18 +43,10 @@ function subscriptionProvider()
|
||||
{
|
||||
return config('subscription.provider');
|
||||
}
|
||||
function isLemon()
|
||||
{
|
||||
return config('subscription.provider') === 'lemon';
|
||||
}
|
||||
function isStripe()
|
||||
{
|
||||
return config('subscription.provider') === 'stripe';
|
||||
}
|
||||
function isPaddle()
|
||||
{
|
||||
return config('subscription.provider') === 'paddle';
|
||||
}
|
||||
function getStripeCustomerPortalSession(Team $team)
|
||||
{
|
||||
Stripe::setApiKey(config('subscription.stripe_api_key'));
|
||||
|
@ -24,6 +24,7 @@
|
||||
"league/flysystem-aws-s3-v3": "^3.0",
|
||||
"league/flysystem-sftp-v3": "^3.0",
|
||||
"livewire/livewire": "3.4.9",
|
||||
"log1x/laravel-webfonts": "^1.0",
|
||||
"lorisleiva/laravel-actions": "^2.7",
|
||||
"nubs/random-name-generator": "^2.2",
|
||||
"phpseclib/phpseclib": "~3.0",
|
||||
|
64
composer.lock
generated
64
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "dbce9f366320f4d58392673fe25c69f6",
|
||||
"content-hash": "168e351cec87acbea9c1c745b83eead2",
|
||||
"packages": [
|
||||
{
|
||||
"name": "amphp/amp",
|
||||
@ -4522,6 +4522,68 @@
|
||||
],
|
||||
"time": "2024-03-14T14:03:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "log1x/laravel-webfonts",
|
||||
"version": "v1.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Log1x/laravel-webfonts.git",
|
||||
"reference": "0d38122aa7f5501394006a6715f7d97dac223507"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Log1x/laravel-webfonts/zipball/0d38122aa7f5501394006a6715f7d97dac223507",
|
||||
"reference": "0d38122aa7f5501394006a6715f7d97dac223507",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"guzzlehttp/guzzle": "^7.8",
|
||||
"laravel/prompts": "^0.1.15",
|
||||
"php": ">=8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"illuminate/console": "^10.41",
|
||||
"illuminate/http": "^10.41",
|
||||
"illuminate/support": "^10.41",
|
||||
"laravel/pint": "^1.13"
|
||||
},
|
||||
"type": "package",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Log1x\\LaravelWebfonts\\WebfontsServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Log1x\\LaravelWebfonts\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Brandon Nifong",
|
||||
"email": "brandon@tendency.me",
|
||||
"homepage": "https://github.com/log1x"
|
||||
}
|
||||
],
|
||||
"description": "Download, install, and preload over 1500 Google fonts locally in your Laravel project",
|
||||
"support": {
|
||||
"issues": "https://github.com/Log1x/laravel-webfonts/issues",
|
||||
"source": "https://github.com/Log1x/laravel-webfonts/tree/v1.0.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/Log1x",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-28T11:53:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "lorisleiva/laravel-actions",
|
||||
"version": "v2.8.0",
|
||||
|
@ -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.305',
|
||||
'release' => '4.0.0-beta.306',
|
||||
// When left empty or `null` the Laravel environment will be used
|
||||
'environment' => config('app.env'),
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'provider' => env('SUBSCRIPTION_PROVIDER', null), // stripe, paddle, lemon
|
||||
'provider' => env('SUBSCRIPTION_PROVIDER', null), // stripe
|
||||
|
||||
// Stripe
|
||||
'stripe_api_key' => env('STRIPE_API_KEY', null),
|
||||
'stripe_webhook_secret' => env('STRIPE_WEBHOOK_SECRET', null),
|
||||
@ -22,29 +23,4 @@
|
||||
|
||||
'stripe_price_id_dynamic_monthly' => env('STRIPE_PRICE_ID_DYNAMIC_MONTHLY', null),
|
||||
'stripe_price_id_dynamic_yearly' => env('STRIPE_PRICE_ID_DYNAMIC_YEARLY', null),
|
||||
|
||||
// Paddle
|
||||
'paddle_vendor_id' => env('PADDLE_VENDOR_ID', null),
|
||||
'paddle_vendor_auth_code' => env('PADDLE_VENDOR_AUTH_CODE', null),
|
||||
'paddle_webhook_secret' => env('PADDLE_WEBHOOK_SECRET', null),
|
||||
'paddle_public_key' => env('PADDLE_PUBLIC_KEY', null),
|
||||
'paddle_price_id_basic_monthly' => env('PADDLE_PRICE_ID_BASIC_MONTHLY', null),
|
||||
'paddle_price_id_basic_yearly' => env('PADDLE_PRICE_ID_BASIC_YEARLY', null),
|
||||
'paddle_price_id_pro_monthly' => env('PADDLE_PRICE_ID_PRO_MONTHLY', null),
|
||||
'paddle_price_id_pro_yearly' => env('PADDLE_PRICE_ID_PRO_YEARLY', null),
|
||||
'paddle_price_id_ultimate_monthly' => env('PADDLE_PRICE_ID_ULTIMATE_MONTHLY', null),
|
||||
'paddle_price_id_ultimate_yearly' => env('PADDLE_PRICE_ID_ULTIMATE_YEARLY', null),
|
||||
|
||||
// Lemon
|
||||
'lemon_squeezy_api_key' => env('LEMON_SQUEEZY_API_KEY', null),
|
||||
'lemon_squeezy_webhook_secret' => env('LEMON_SQUEEZY_WEBHOOK_SECRET', null),
|
||||
'lemon_squeezy_checkout_id_basic_monthly' => env('LEMON_SQUEEZY_CHECKOUT_ID_BASIC_MONTHLY', null),
|
||||
'lemon_squeezy_checkout_id_basic_yearly' => env('LEMON_SQUEEZY_CHECKOUT_ID_BASIC_YEARLY', null),
|
||||
'lemon_squeezy_checkout_id_pro_monthly' => env('LEMON_SQUEEZY_CHECKOUT_ID_PRO_MONTHLY', null),
|
||||
'lemon_squeezy_checkout_id_pro_yearly' => env('LEMON_SQUEEZY_CHECKOUT_ID_PRO_YEARLY', null),
|
||||
'lemon_squeezy_checkout_id_ultimate_monthly' => env('LEMON_SQUEEZY_CHECKOUT_ID_ULTIMATE_MONTHLY', null),
|
||||
'lemon_squeezy_checkout_id_ultimate_yearly' => env('LEMON_SQUEEZY_CHECKOUT_ID_ULTIMATE_YEARLY', null),
|
||||
'lemon_squeezy_basic_plan_ids' => env('LEMON_SQUEEZY_BASIC_PLAN_IDS', ''),
|
||||
'lemon_squeezy_pro_plan_ids' => env('LEMON_SQUEEZY_PRO_PLAN_IDS', ''),
|
||||
'lemon_squeezy_ultimate_plan_ids' => env('LEMON_SQUEEZY_ULTIMATE_PLAN_IDS', ''),
|
||||
];
|
||||
|
@ -1,3 +1,3 @@
|
||||
<?php
|
||||
|
||||
return '4.0.0-beta.305';
|
||||
return '4.0.0-beta.306';
|
||||
|
@ -69,27 +69,6 @@ services:
|
||||
- STRIPE_PRICE_ID_ULTIMATE_MONTHLY_OLD
|
||||
- STRIPE_PRICE_ID_ULTIMATE_YEARLY_OLD
|
||||
- STRIPE_EXCLUDED_PLANS
|
||||
- PADDLE_VENDOR_ID
|
||||
- PADDLE_WEBHOOK_SECRET
|
||||
- PADDLE_VENDOR_AUTH_CODE
|
||||
- PADDLE_PUBLIC_KEY
|
||||
- PADDLE_PRICE_ID_BASIC_MONTHLY
|
||||
- PADDLE_PRICE_ID_BASIC_YEARLY
|
||||
- PADDLE_PRICE_ID_PRO_MONTHLY
|
||||
- PADDLE_PRICE_ID_PRO_YEARLY
|
||||
- PADDLE_PRICE_ID_ULTIMATE_MONTHLY
|
||||
- PADDLE_PRICE_ID_ULTIMATE_YEARLY
|
||||
- LEMON_SQUEEZY_API_KEY
|
||||
- LEMON_SQUEEZY_WEBHOOK_SECRET
|
||||
- LEMON_SQUEEZY_CHECKOUT_ID_BASIC_MONTHLY
|
||||
- LEMON_SQUEEZY_CHECKOUT_ID_BASIC_YEARLY
|
||||
- LEMON_SQUEEZY_CHECKOUT_ID_PRO_MONTHLY
|
||||
- LEMON_SQUEEZY_CHECKOUT_ID_PRO_YEARLY
|
||||
- LEMON_SQUEEZY_CHECKOUT_ID_ULTIMATE_MONTHLY
|
||||
- LEMON_SQUEEZY_CHECKOUT_ID_ULTIMATE_YEARLY
|
||||
- LEMON_SQUEEZY_BASIC_PLAN_IDS
|
||||
- LEMON_SQUEEZY_PRO_PLAN_IDS
|
||||
- LEMON_SQUEEZY_ULTIMATE_PLAN_IDS
|
||||
ports:
|
||||
- "${APP_PORT:-8000}:80"
|
||||
expose:
|
||||
|
16
public/js/apexcharts.js
Normal file
16
public/js/apexcharts.js
Normal file
File diff suppressed because one or more lines are too long
@ -1,7 +1,11 @@
|
||||
@import 'fonts';
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
|
||||
|
||||
html,
|
||||
body {
|
||||
@apply h-full bg-neutral-50 text-neutral-800 dark:bg-base dark:text-neutral-400;
|
||||
|
72
resources/css/fonts.css
Normal file
72
resources/css/fonts.css
Normal file
@ -0,0 +1,72 @@
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 100;
|
||||
src: url('../fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-100.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 200;
|
||||
src: url('../fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-200.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: url('../fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-300.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
src: url('../fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-500.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: url('../fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-600.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: url('../fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-700.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
src: url('../fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-800.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
src: url('../fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-900.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url('../fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-regular.woff2') format('woff2');
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,80 +0,0 @@
|
||||
<x-slot:basic>
|
||||
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-basic" class="w-full h-10 buyme"
|
||||
x-on:click="subscribe('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"
|
||||
x-on:click="subscribe('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"
|
||||
x-on:click="subscribe('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"
|
||||
x-on:click="subscribe('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"
|
||||
x-on:click="subscribe('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"
|
||||
x-on:click="subscribe('ultimate-yearly')"> Subscribe
|
||||
</x-forms.button>
|
||||
</x-slot:ultimate>
|
||||
<x-slot:other>
|
||||
<script src="https://cdn.paddle.com/paddle/v2/paddle.js"></script>
|
||||
<script type="text/javascript">
|
||||
Paddle.Environment.set("{{ isDev() ? 'sandbox' : 'production' }}");
|
||||
Paddle.Setup({
|
||||
seller: {{ config('subscription.paddle_vendor_id') }},
|
||||
checkout: {
|
||||
settings: {
|
||||
displayMode: "overlay",
|
||||
theme: "light",
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function subscribe(type) {
|
||||
let priceId = null
|
||||
switch (type) {
|
||||
case 'basic-monthly':
|
||||
priceId = "{{ config('subscription.paddle_price_id_basic_monthly') }}"
|
||||
break;
|
||||
case 'basic-yearly':
|
||||
priceId = "{{ config('subscription.paddle_price_id_basic_yearly') }}"
|
||||
break;
|
||||
case 'pro-monthly':
|
||||
priceId = "{{ config('subscription.paddle_price_id_pro_monthly') }}"
|
||||
break;
|
||||
case 'pro-yearly':
|
||||
priceId = "{{ config('subscription.paddle_price_id_pro_yearly') }}"
|
||||
break;
|
||||
case 'ultimate-monthly':
|
||||
priceId = "{{ config('subscription.paddle_price_id_ultimate_monthly') }}"
|
||||
break;
|
||||
case 'ultimate-yearly':
|
||||
priceId = "{{ config('subscription.paddle_price_id_ultimate_yearly') }}"
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Paddle.Checkout.open({
|
||||
customer: {
|
||||
email: '{{ auth()->user()->email }}',
|
||||
},
|
||||
customData: {
|
||||
"team_id": "{{ currentTeam()->id }}",
|
||||
},
|
||||
items: [{
|
||||
priceId,
|
||||
quantity: 1
|
||||
}],
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</x-slot:other>
|
@ -34,15 +34,16 @@ class="font-bold dark:text-warning">{{ config('constants.limits.trial_period') }
|
||||
<div>
|
||||
</div>
|
||||
</div>
|
||||
{{-- <div class="p-4 rounded bg-coolgray-400">
|
||||
<div class="p-4 rounded bg-coolgray-400">
|
||||
<h2 id="tier-hobby" class="flex items-start gap-4 text-4xl font-bold tracking-tight">Unlimited Trial
|
||||
<x-forms.button><a class="font-bold dark:text-white hover:no-underline"
|
||||
href="https://github.com/coollabsio/coolify">Get Started</a></x-forms.button>
|
||||
</h2>
|
||||
<p class="mt-4 text-sm leading-6">Start self-hosting <span class="dark:text-warning">without limits</span> with
|
||||
<p class="mt-4 text-sm leading-6">Start self-hosting <span class="dark:text-warning">without limits</span>
|
||||
with
|
||||
our
|
||||
OSS version. Same features as the paid version, but you have to manage by yourself.</p>
|
||||
</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
|
||||
@ -78,8 +79,8 @@ class="grid max-w-sm grid-cols-1 -mt-16 divide-y divide-neutral-200 dark:divide-
|
||||
</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">
|
||||
<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" />
|
||||
@ -141,13 +142,14 @@ class="grid max-w-sm grid-cols-1 -mt-16 divide-y divide-neutral-200 dark:divide-
|
||||
{{ $pro }}
|
||||
@endisset
|
||||
@endif
|
||||
<p class="h-20 mt-10 text-sm leading-6 dark:text-white">Expand your business or set up your own hosting
|
||||
<p class="h-20 mt-10 text-sm leading-6 dark:text-white">Expand your business or set up your own
|
||||
hosting
|
||||
environment.
|
||||
</p>
|
||||
<ul role="list" class="mt-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">
|
||||
<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.75.75 0 001.137-.089l4-5.5z"
|
||||
clip-rule="evenodd" />
|
||||
@ -213,8 +215,8 @@ class="grid max-w-sm grid-cols-1 -mt-16 divide-y divide-neutral-200 dark:divide-
|
||||
single location.</p>
|
||||
<ul role="list" class="mt-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">
|
||||
<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.75.75 0 001.137-.089l4-5.5z"
|
||||
clip-rule="evenodd" />
|
||||
|
@ -46,13 +46,6 @@
|
||||
stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
||||
</svg>
|
||||
</button>
|
||||
{{-- <div class="flex-1 text-xl font-bold leading-6 dark:text-white">Dashboard</div> --}}
|
||||
{{-- <a href="#">
|
||||
<span class="sr-only">Your profile</span>
|
||||
<img class="w-8 h-8 rounded-full bg-gray-50"
|
||||
src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
|
||||
alt="">
|
||||
</a> --}}
|
||||
</div>
|
||||
|
||||
<main class="lg:pl-48">
|
||||
|
@ -4,16 +4,6 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="preconnect" href="https://api.fonts.coollabs.io" crossorigin>
|
||||
<link rel="dns-prefetch" href="https://api.fonts.coollabs.io" />
|
||||
<link rel="preload" href="https://api.fonts.coollabs.io/css2?family=Inter:wght@400;500;600;700;800&display=swap"
|
||||
as="style" />
|
||||
<link rel="preload" href="https://cdn.fonts.coollabs.io/inter/normal/400.woff2" as="style" />
|
||||
<link rel="preload" href="https://cdn.fonts.coollabs.io/inter/normal/500.woff2" as="style" />
|
||||
<link rel="preload" href="https://cdn.fonts.coollabs.io/inter/normal/600.woff2" as="style" />
|
||||
<link rel="preload" href="https://cdn.fonts.coollabs.io/inter/normal/700.woff2" as="style" />
|
||||
<link rel="preload" href="https://cdn.fonts.coollabs.io/inter/normal/800.woff2" as="style" />
|
||||
<link href="https://api.fonts.coollabs.io/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<meta name="robots" content="noindex">
|
||||
@use('App\Models\InstanceSettings')
|
||||
@php
|
||||
@ -46,13 +36,9 @@
|
||||
<script defer data-domain="app.coolify.io" src="https://analytics.coollabs.io/js/plausible.js"></script>
|
||||
@endif
|
||||
@auth
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/laravel-echo/1.15.3/echo.iife.min.js"
|
||||
integrity="sha512-aPAh2oRUr3ALz2MwVWkd6lmdgBQC0wSr0R++zclNjXZreT/JrwDPZQwA/p6R3wOCTcXKIHgA9pQGEQBWQmdLaA=="
|
||||
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/pusher/8.3.0/pusher.min.js"
|
||||
integrity="sha512-tXL5mrkSoP49uQf2jO0LbvzMyFgki//znmq0wYXGq94gVF6TU0QlrSbwGuPpKTeN1mIjReeqKZ4/NJPjHN1d2Q=="
|
||||
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
|
||||
<script type="text/javascript" src="{{ URL::asset('js/echo.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ URL::asset('js/pusher.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ URL::asset('js/apexcharts.js') }}"></script>
|
||||
@endauth
|
||||
</head>
|
||||
@section('body')
|
||||
|
@ -2,8 +2,7 @@
|
||||
@if (subscriptionProvider() === 'stripe')
|
||||
<div class="pt-4">
|
||||
<h2>Your current plan</h2>
|
||||
<div class="pb-4">Tier: <strong
|
||||
class="dark:text-warning">
|
||||
<div class="pb-4">Tier: <strong class="dark:text-warning">
|
||||
@if (data_get(currentTeam(), 'subscription')->type() == 'dynamic')
|
||||
Pay-as-you-go
|
||||
@else
|
||||
@ -50,35 +49,4 @@ class="dark:text-warning">
|
||||
target="_blank">contact us.</a>
|
||||
</div>
|
||||
@endif
|
||||
{{-- @if (subscriptionProvider() === 'lemon')
|
||||
<div>Status: {{ currentTeam()->subscription->lemon_status }}</div>
|
||||
<div>Type: {{ currentTeam()->subscription->lemon_variant_name }}</div>
|
||||
@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="underline dark:text-white" href="{{ config('coolify.contact') }}" target="_blank">please
|
||||
contact
|
||||
us.</a></div>
|
||||
@else
|
||||
<div class="pb-4">Renews at: {{ getRenewDate() }}</div>
|
||||
@endif
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex gap-2">
|
||||
@if (currentTeam()->subscription->lemon_status === 'cancelled')
|
||||
<x-forms.button class="bg-coollabs-gradient" wire:click='resume'>Resume Subscription
|
||||
</x-forms.button>
|
||||
@else
|
||||
<x-forms.button wire:click='cancel'>Cancel Subscription</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
<x-forms.button><a class="dark:text-white hover:no-underline" href="{{ getPaymentLink() }}">Update Payment
|
||||
Details</a>
|
||||
</x-forms.button>
|
||||
<a class="dark:text-white hover:no-underline"
|
||||
href="https://app.lemonsqueezy.com/my-orders"><x-forms.button>Manage My
|
||||
Subscription</x-forms.button></a>
|
||||
</div>
|
||||
</div>
|
||||
@endif --}}
|
||||
</div>
|
||||
|
@ -1,67 +0,0 @@
|
||||
<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>
|
@ -25,7 +25,7 @@
|
||||
<div>This is the default team. You can't delete it.</div>
|
||||
@elseif(auth()->user()->teams()->get()->count() === 1 || auth()->user()->currentTeam()->personal_team)
|
||||
<div>You can't delete your last / personal team.</div>
|
||||
@elseif(currentTeam()->subscription && currentTeam()->subscription?->lemon_status !== 'cancelled')
|
||||
@elseif(currentTeam()->subscription)
|
||||
<div>Please cancel your subscription <a class="underline dark:text-white"
|
||||
href="{{ route('subscription.show') }}">here</a> before delete this team.</div>
|
||||
@else
|
||||
|
@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Actions\CoolifyTask\RunRemoteProcess;
|
||||
use App\Actions\CoolifyTask\TidyOutput;
|
||||
use App\Models\Server;
|
||||
use App\Models\User;
|
||||
use Database\Seeders\DatabaseSeeder;
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
uses(DatabaseMigrations::class);
|
||||
|
||||
beforeEach(function () {
|
||||
$this->seed(DatabaseSeeder::class);
|
||||
});
|
||||
|
||||
it('starts a docker container correctly', function () {
|
||||
|
||||
|
||||
test()->actingAs(User::factory([
|
||||
'uuid' => Str::uuid(),
|
||||
'email' => Str::uuid() . '@example.com',
|
||||
])->create());
|
||||
|
||||
$coolifyNamePrefix = 'coolify_test_';
|
||||
|
||||
|
||||
$format = '{"ID":"{{ .ID }}", "Image": "{{ .Image }}", "Names":"{{ .Names }}"}';
|
||||
$areThereCoolifyTestContainers = "docker ps --filter=\"name={$coolifyNamePrefix}*\" --format '{$format}' ";
|
||||
|
||||
// Generate a known name
|
||||
$containerName = 'coolify_test_' . now()->format('Ymd_his');
|
||||
$host = Server::where('name', 'testing-local-docker-container')->first();
|
||||
|
||||
remote_process([
|
||||
"docker rm -f $(docker ps --filter='name={$coolifyNamePrefix}*' -aq) > /dev/null 2>&1"
|
||||
], $host);
|
||||
|
||||
// Assert there's no containers start with coolify_test_*
|
||||
$activity = remote_process([$areThereCoolifyTestContainers], $host);
|
||||
$tidyOutput = RunRemoteProcess::decodeOutput($activity);
|
||||
$containers = format_docker_command_output_to_json($tidyOutput);
|
||||
expect($containers)->toBeEmpty();
|
||||
|
||||
// start a container nginx -d --name = $containerName
|
||||
$activity = remote_process(["docker run -d --rm --name {$containerName} nginx"], $host);
|
||||
expect($activity->getExtraProperty('exitCode'))->toBe(0);
|
||||
|
||||
// docker ps name = $container
|
||||
$activity = remote_process([$areThereCoolifyTestContainers], $host);
|
||||
$tidyOutput = RunRemoteProcess::decodeOutput($activity);
|
||||
$containers = format_docker_command_output_to_json($tidyOutput);
|
||||
expect($containers->where('Names', $containerName)->count())->toBe(1);
|
||||
|
||||
// Stop testing containers
|
||||
$activity = remote_process([
|
||||
"docker ps --filter='name={$coolifyNamePrefix}*' -aq && " .
|
||||
"docker rm -f $(docker ps --filter='name={$coolifyNamePrefix}*' -aq)"
|
||||
], $host);
|
||||
expect($activity->getExtraProperty('exitCode'))->toBe(0);
|
||||
});
|
@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Actions\CoolifyTask\RunRemoteProcess;
|
||||
use App\Models\Server;
|
||||
use Database\Seeders\DatabaseSeeder;
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
uses(DatabaseMigrations::class);
|
||||
|
||||
beforeEach(function () {
|
||||
$this->seed(DatabaseSeeder::class);
|
||||
});
|
||||
|
||||
it('outputs correctly', function () {
|
||||
|
||||
$host = Server::where('name', 'testing-local-docker-container')->first();
|
||||
|
||||
$activity = remote_process([
|
||||
'pwd',
|
||||
'x=1; while [ $x -le 3 ]; do sleep 0.1 && echo "Welcome $x times" $(( x++ )); done',
|
||||
], $host);
|
||||
|
||||
|
||||
$tidyOutput = RunRemoteProcess::decodeOutput($activity);
|
||||
|
||||
expect($tidyOutput)
|
||||
->toContain('Welcome 1 times')
|
||||
->toContain('Welcome 3 times')
|
||||
->not()->toBeJson();
|
||||
});
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"coolify": {
|
||||
"v4": {
|
||||
"version": "4.0.0-beta.305"
|
||||
"version": "4.0.0-beta.306"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user