Merge pull request #1694 from coollabsio/next

v4.0.0-beta.204
This commit is contained in:
Andras Bacsai 2024-02-01 10:54:27 +01:00 committed by GitHub
commit de7d584648
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
46 changed files with 215 additions and 263 deletions

View File

@ -27,7 +27,7 @@ class StartProxy
$server->save();
if ($server->isSwarm()) {
$commands = $commands->merge([
"mkdir -p $proxy_path && cd $proxy_path",
"mkdir -p $proxy_path/dynamic && cd $proxy_path",
"echo 'Creating required Docker Compose file.'",
"echo 'Starting coolify-proxy.'",
"cd $proxy_path && docker stack deploy -c docker-compose.yml coolify-proxy",
@ -35,7 +35,7 @@ class StartProxy
]);
} else {
$commands = $commands->merge([
"mkdir -p $proxy_path && cd $proxy_path",
"mkdir -p $proxy_path/dynamic && cd $proxy_path",
"echo 'Creating required Docker Compose file.'",
"echo 'Pulling docker image.'",
'docker compose pull',

View File

@ -488,7 +488,6 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
} else {
$this->application_deployment_queue->addLogEntry("Starting pull request (#{$this->pull_request_id}) deployment of {$this->customRepository}:{$this->application->git_branch}.");
}
ray('asddf');
$this->prepare_builder_image();
$this->check_git_if_build_needed();
$this->clone_repository();

View File

@ -39,7 +39,7 @@ class ScheduledTaskJob implements ShouldQueue
} else if ($application = $task->application()->first()) {
$this->resource = $application;
} else {
throw new \Exception('ScheduledTaskJob failed: No resource found.');
throw new \RuntimeException('ScheduledTaskJob failed: No resource found.');
}
$this->team = Team::find($task->team_id);
}

View File

@ -9,6 +9,7 @@ class DeleteEnvironment extends Component
{
public array $parameters;
public int $environment_id;
public bool $disabled = false;
public function mount()
{

View File

@ -9,6 +9,7 @@ class DeleteProject extends Component
{
public array $parameters;
public int $project_id;
public bool $disabled = false;
public function mount()
{

View File

@ -8,7 +8,7 @@ use Livewire\Component;
class Configuration extends Component
{
public Service $service;
public ?Service $service = null;
public $applications;
public $databases;
public array $parameters;

View File

@ -17,8 +17,8 @@ class Danger extends Component
{
$this->modalId = new Cuid2(7);
$parameters = get_route_parameters();
$this->projectUuid = $parameters['project_uuid'];
$this->environmentName = $parameters['environment_name'];
$this->projectUuid = data_get($parameters, 'project_uuid');
$this->environmentName = data_get($parameters, 'environment_name');
}
public function delete()

View File

@ -32,6 +32,13 @@ class Add extends Component
public function submit()
{
$this->validate();
if (str($this->value)->startsWith('{{') && str($this->value)->endsWith('}}')) {
$type = str($this->value)->after("{{")->before(".")->value;
if (!collect(SHARED_VARIABLE_TYPES)->contains($type)) {
$this->dispatch('error', 'Invalid shared variable type.', "Valid types are: team, project, environment.");
return;
}
}
$this->dispatch('saveKey', [
'key' => $this->key,
'value' => $this->value,

View File

@ -71,12 +71,26 @@ class All extends Component
continue;
}
$found->value = $variable;
if (str($found->value)->startsWith('{{') && str($found->value)->endsWith('}}')) {
$type = str($found->value)->after("{{")->before(".")->value;
if (!collect(SHARED_VARIABLE_TYPES)->contains($type)) {
$this->dispatch('error', 'Invalid shared variable type.', "Valid types are: team, project, environment.");
return;
}
}
$found->save();
continue;
} else {
$environment = new EnvironmentVariable();
$environment->key = $key;
$environment->value = $variable;
if (str($environment->value)->startsWith('{{') && str($environment->value)->endsWith('}}')) {
$type = str($environment->value)->after("{{")->before(".")->value;
if (!collect(SHARED_VARIABLE_TYPES)->contains($type)) {
$this->dispatch('error', 'Invalid shared variable type.', "Valid types are: team, project, environment.");
return;
}
}
$environment->is_build_time = false;
$environment->is_preview = $isPreview ? true : false;
switch ($this->resource->type()) {

View File

@ -50,7 +50,8 @@ class Show extends Component
$this->isLocked = true;
}
}
public function serialize() {
public function serialize()
{
data_forget($this->env, 'real_value');
if ($this->env->getMorphClass() === 'App\Models\SharedEnvironmentVariable') {
data_forget($this->env, 'is_build_time');
@ -80,11 +81,18 @@ class Show extends Component
} else {
$this->validate();
}
if (str($this->env->value)->startsWith('{{') && str($this->env->value)->endsWith('}}')) {
$type = str($this->env->value)->after("{{")->before(".")->value;
if (!collect(SHARED_VARIABLE_TYPES)->contains($type)) {
$this->dispatch('error', 'Invalid shared variable type.', "Valid types are: team, project, environment.");
return;
}
}
$this->serialize();
$this->env->save();
$this->dispatch('success', 'Environment variable updated successfully.');
$this->dispatch('refreshEnvs');
} catch(\Exception $e) {
} catch (\Exception $e) {
return handleError($e);
}
}

View File

@ -20,8 +20,8 @@ class ResourceOperations extends Component
public function mount()
{
$parameters = get_route_parameters();
$this->projectUuid = $parameters['project_uuid'];
$this->environmentName = $parameters['environment_name'];
$this->projectUuid = data_get($parameters, 'project_uuid');
$this->environmentName = data_get($parameters, 'environment_name');
$this->projects = Project::ownedByCurrentTeam()->get();
$this->servers = currentTeam()->servers;
}

View File

@ -12,7 +12,11 @@ class Invitations extends Component
public function deleteInvitation(int $invitation_id)
{
TeamInvitation::find($invitation_id)->delete();
$initiation_found = TeamInvitation::find($invitation_id);
if (!$initiation_found) {
return $this->dispatch('error', 'Invitation not found.');
}
$initiation_found->delete();
$this->refreshInvitations();
$this->dispatch('success', 'Invitation revoked.');
}

View File

@ -67,7 +67,8 @@ class Create extends Component
$this->storage->save();
return redirect()->route('team.storage.show', $this->storage->uuid);
} catch (\Throwable $e) {
return handleError($e, $this);
$this->dispatch('error', 'Failed to create storage.', $e->getMessage());
// return handleError($e, $this);
}
}
}

View File

@ -33,9 +33,9 @@ class Form extends Component
{
try {
$this->storage->testConnection(shouldSave: true);
return $this->dispatch('success', 'Connection is working. Tested with "ListObjectsV2" action.');
return $this->dispatch('success', 'Connection is working.', 'Tested with "ListObjectsV2" action.');
} catch (\Throwable $e) {
return handleError($e, $this);
$this->dispatch('error', 'Failed to create storage.', $e->getMessage());
}
}

View File

@ -91,7 +91,7 @@ class EnvironmentVariable extends Model
}
private function get_real_environment_variables(?string $environment_variable = null, $resource = null): string|null
{
if (!$environment_variable) {
if (!$environment_variable || !$resource) {
return null;
}
$environment_variable = trim($environment_variable);
@ -100,6 +100,9 @@ class EnvironmentVariable extends Model
$variable = Str::after($environment_variable, "{$type}.");
$variable = Str::before($variable, '}}');
$variable = Str::of($variable)->trim()->value;
if (!collect(SHARED_VARIABLE_TYPES)->contains($type)) {
return $variable;
}
if ($type === 'environment') {
$id = $resource->environment->id;
} else if ($type === 'project') {

View File

@ -64,10 +64,13 @@ class Project extends BaseModel
}
public function mysqls()
{
return $this->hasMany(StandaloneMysql::class, Environment::class);
return $this->hasManyThrough(StandaloneMysql::class, Environment::class);
}
public function mariadbs()
{
return $this->hasMany(StandaloneMariadb::class, Environment::class);
return $this->hasManyThrough(StandaloneMariadb::class, Environment::class);
}
public function resource_count() {
return $this->applications()->count() + $this->postgresqls()->count() + $this->redis()->count() + $this->mongodbs()->count() + $this->mysqls()->count() + $this->mariadbs()->count();
}
}

View File

@ -34,3 +34,5 @@ const SUPPORTED_OS = [
'centos fedora rhel ol rocky',
'sles opensuse-leap opensuse-tumbleweed'
];
const SHARED_VARIABLE_TYPES = ['team', 'project', 'environment'];

View File

@ -29,7 +29,7 @@ function generate_github_installation_token(GithubApp $source)
'Accept' => 'application/vnd.github.machine-man-preview+json'
])->post("{$source->api_url}/app/installations/{$source->installation_id}/access_tokens");
if ($token->failed()) {
throw new \Exception("Failed to get access token for " . $source->name . " with error: " . $token->json()['message']);
throw new RuntimeException("Failed to get access token for " . $source->name . " with error: " . $token->json()['message']);
}
return $token->json()['token'];
}

View File

@ -937,7 +937,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
'service_id' => $resource->id,
])->first();
['command' => $command, 'forService' => $forService, 'generatedValue' => $generatedValue, 'port' => $port] = parseEnvVariable($value);
if ($command->value() === 'FQDN' || $command->value() === 'URL') {
if ($command?->value() === 'FQDN' || $command?->value() === 'URL') {
if (Str::lower($forService) === $serviceName) {
$fqdn = generateFqdn($resource->server, $containerName);
} else {
@ -1357,7 +1357,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
'application_id' => $resource->id,
])->first();
['command' => $command, 'forService' => $forService, 'generatedValue' => $generatedValue, 'port' => $port] = parseEnvVariable($value);
if ($command->value() === 'FQDN' || $command->value() === 'URL') {
if ($command?->value() === 'FQDN' || $command?->value() === 'URL') {
if (Str::lower($forService) === $serviceName) {
$fqdn = generateFqdn($server, $containerName);
} else {
@ -1670,15 +1670,21 @@ function ip_match($ip, $cidrs, &$match = null)
function check_fqdn_usage(ServiceApplication|Application $own_resource)
{
$domains = collect($own_resource->fqdns)->map(function ($domain) {
return Url::fromString($domain)->getHost();
if (str($domain)->endsWith('/')) {
$domain = str($domain)->beforeLast('/');
}
return str($domain)->replace('http://', '')->replace('https://', '');
});
$apps = Application::all();
foreach ($apps as $app) {
$list_of_domains = collect(explode(',', $app->fqdn))->filter(fn ($fqdn) => $fqdn !== '');
foreach ($list_of_domains as $domain) {
$naked_domain = Url::fromString($domain)->getHost();
if (str($domain)->endsWith('/')) {
$domain = str($domain)->beforeLast('/');
}
$naked_domain = str($domain)->replace('http://', '')->replace('https://', '')->value();
if ($domains->contains($naked_domain)) {
if ($app->uuid !== $own_resource->uuid ) {
if ($app->uuid !== $own_resource->uuid) {
throw new \RuntimeException("Domain $naked_domain is already in use by another resource.");
}
}
@ -1688,7 +1694,10 @@ function check_fqdn_usage(ServiceApplication|Application $own_resource)
foreach ($apps as $app) {
$list_of_domains = collect(explode(',', $app->fqdn))->filter(fn ($fqdn) => $fqdn !== '');
foreach ($list_of_domains as $domain) {
$naked_domain = Url::fromString($domain)->getHost();
if (str($domain)->endsWith('/')) {
$domain = str($domain)->beforeLast('/');
}
$naked_domain = str($domain)->replace('http://', '')->replace('https://', '')->value();
if ($domains->contains($naked_domain)) {
if ($app->uuid !== $own_resource->uuid) {
throw new \RuntimeException("Domain $naked_domain is already in use by another resource.");

View File

@ -7,7 +7,7 @@ return [
// 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.203',
'release' => '4.0.0-beta.204',
// 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.203';
return '4.0.0-beta.204';

View File

@ -0,0 +1,56 @@
@props([
'title' => 'Are you sure?',
'buttonTitle' => 'Open Modal',
'isErrorButton' => false,
'disabled' => false,
'action' => 'delete',
])
<div x-data="{ modalOpen: false }" @keydown.escape.window="modalOpen = false" :class="{ 'z-40': modalOpen }"
class="relative w-auto h-auto">
@if ($disabled)
<x-forms.button isError disabled>{{ $buttonTitle }}</x-forms.button>
@elseif ($isErrorButton)
<x-forms.button isError @click="modalOpen=true">{{ $buttonTitle }}</x-forms.button>
@else
<x-forms.button @click="modalOpen=true">{{ $buttonTitle }}</x-forms.button>
@endif
<template x-teleport="body">
<div x-show="modalOpen" class="fixed top-0 left-0 z-[99] flex items-center justify-center w-screen h-screen"
x-cloak>
<div x-show="modalOpen" x-transition:enter="ease-out duration-100" x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100" x-transition:leave="ease-in duration-100"
x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0" @click="modalOpen=false"
class="absolute inset-0 w-full h-full bg-black bg-opacity-20 backdrop-blur-sm"></div>
<div x-show="modalOpen" x-trap.inert.noscroll="modalOpen" x-transition:enter="ease-out duration-100"
x-transition:enter-start="opacity-0 -translate-y-2 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave="ease-in duration-100"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 -translate-y-2 sm:scale-95"
class="relative w-full py-6 border rounded shadow-lg bg-coolgray-100 px-7 border-coolgray-300 sm:max-w-lg">
<div class="flex items-center justify-between pb-3">
<h3 class="text-2xl font-bold">{{ $title }}</h3>
<button @click="modalOpen=false"
class="absolute top-0 right-0 flex items-center justify-center w-8 h-8 mt-5 mr-5 text-white rounded-full hover:bg-coolgray-300">
<svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<div class="relative w-auto pb-8">
{{ $slot }}
</div>
<div class="flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2">
<x-forms.button @click="modalOpen=false" class="w-24 bg-coolgray-200 hover:bg-coolgray-300"
type="button">Cancel
</x-forms.button>
<div class="flex-1"></div>
<x-forms.button @click="modalOpen=false" class="w-24" isError type="button"
wire:click.prevent='{{ $action }}'>Continue
</x-forms.button>
</div>
</div>
</div>
</template>
</div>

View File

@ -369,10 +369,10 @@ window.customToastHTML = `
}, 5);
}, 4000);"
@mouseover="toastHovered=true" @mouseout="toastHovered=false"
class="absolute w-full duration-200 ease-out select-none sm:max-w-xs"
class="absolute w-full duration-100 ease-out sm:max-w-xs"
:class="{ 'toast-no-description': !toast.description }">
<span
class="relative flex flex-col items-start shadow-[0_5px_15px_-3px_rgb(0_0_0_/_0.08)] w-full transition-all duration-200 ease-out bg-coolgray-200 border border-coolgray-100 sm:rounded-md sm:max-w-xs group"
class="relative flex flex-col items-start shadow-[0_5px_15px_-3px_rgb(0_0_0_/_0.08)] w-full transition-all duration-100 ease-out bg-coolgray-100 border border-coolgray-200 rounded sm:max-w-xs group"
:class="{ 'p-4': !toast.html, 'p-0': toast.html }">
<template x-if="!toast.html">
<div class="relative">
@ -403,12 +403,12 @@ window.customToastHTML = `
d="M2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12ZM11.9996 7C12.5519 7 12.9996 7.44772 12.9996 8V12C12.9996 12.5523 12.5519 13 11.9996 13C11.4474 13 10.9996 12.5523 10.9996 12V8C10.9996 7.44772 11.4474 7 11.9996 7ZM12.001 14.99C11.4488 14.9892 11.0004 15.4363 10.9997 15.9886L10.9996 15.9986C10.9989 16.5509 11.446 16.9992 11.9982 17C12.5505 17.0008 12.9989 16.5537 12.9996 16.0014L12.9996 15.9914C13.0004 15.4391 12.5533 14.9908 12.001 14.99Z"
fill="currentColor"></path>
</svg>
<p class="font-bold leading-2 text-neutral-200"
<p class="leading-2 text-neutral-200"
x-html="toast.message">
</p>
</div>
<p x-show="toast.description" :class="{ 'pl-5': toast.type!='default' }"
class="mt-1.5 text-xs leading-2 opacity-90" x-html="toast.description"></p>
class="mt-1.5 text-xs leading-2 opacity-90 whitespace-pre-wrap" x-html="toast.description"></p>
</div>
</template>
<template x-if="toast.html">

View File

@ -1,9 +1,4 @@
<div>
<x-modal yesOrNo modalId="deleteDestination" modalTitle="Delete Destination">
<x-slot:modalBody>
<p>This destination will be deleted. It is not reversible. <br>Please think again.</p>
</x-slot:modalBody>
</x-modal>
<form class="flex flex-col">
<div class="flex items-center gap-2">
<h1>Destination</h1>
@ -11,9 +6,9 @@
Save
</x-forms.button>
@if ($destination->network !== 'coolify')
<x-forms.button isError isModal modalId="deleteDestination">
Delete
</x-forms.button>
<x-new-modal isErrorButton buttonTitle="Delete Destination">
This destination will be deleted. It is not reversible. <br>Please think again.
</x-new-modal>
@endif
</div>

View File

@ -14,7 +14,7 @@
</x-forms.select>
{{-- <x-forms.checkbox type="checkbox" id="is_swarm" label="Is it a Swarm network?" /> --}}
<x-forms.button type="submit">
Save Destination
Continue
</x-forms.button>
</form>
</div>

View File

@ -1,8 +1,3 @@
<div>
<x-modal yesOrNo modalId="deleteEnvironment" modalTitle="Delete Environment">
<x-slot:modalBody>
<p>This environment will be deleted. It is not reversible. <br>Please think again.</p>
</x-slot:modalBody>
</x-modal>
<x-forms.button isError isModal modalId="deleteEnvironment"> Delete Environment</x-forms.button>
</div>
<x-new-modal isErrorButton buttonTitle="Delete Environment" disabled="{{ $disabled }}">
This environment will be deleted. It is not reversible. <br>Please think again.
</x-new-modal>

View File

@ -1,10 +1,3 @@
<div>
<x-modal yesOrNo modalId="deleteProject" modalTitle="Delete Project">
<x-slot:modalBody>
<p>This project will be deleted. It is not reversible. <br>Please think again.</p>
</x-slot:modalBody>
</x-modal>
<x-forms.button isError isModal modalId="deleteProject">
Delete Project
</x-forms.button>
</div>
<x-new-modal isErrorButton buttonTitle="Delete Project" disabled="{{ $disabled }}">
This project will be deleted. It is not reversible. <br>Please think again.
</x-new-modal>

View File

@ -5,6 +5,7 @@
<div class="flex items-end gap-2">
<h2>General</h2>
<x-forms.button type="submit">Save</x-forms.button>
<livewire:project.delete-project :disabled="$project->resource_count() > 0" :project_id="$project->id" />
</div>
<div class="flex gap-2">
<x-forms.input label="Name" id="project.name" />
@ -23,7 +24,8 @@
Add</button>
</x-slide-over>
</div>
<div class="flex items-center gap-2 pb-4">You can use these variables anywhere with <span class="text-warning">@{{project.VARIABLENAME}}</span><x-helper
<div class="flex items-center gap-2 pb-4">You can use these variables anywhere with <span
class="text-warning">@{{ project.VARIABLENAME }}</span><x-helper
helper="More info <a class='text-white underline' href='https://coolify.io/docs/environment-variables#shared-variables' target='_blank'>here</a>."></x-helper>
</div>
<div class="flex flex-col gap-2">

View File

@ -3,6 +3,7 @@
<div class="flex items-end gap-2">
<h1>Environment: {{ data_get($environment, 'name') }}</h1>
<x-forms.button type="submit">Save</x-forms.button>
<livewire:project.delete-environment :disabled="!$environment->isEmpty()" :environment_id="$environment->id" />
</div>
<nav class="flex pt-2 pb-10">
<ol class="flex items-center">

View File

@ -7,7 +7,6 @@
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.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">+
@ -17,6 +16,7 @@
Clone
</a>
@endif
<livewire:project.delete-environment :disabled="!$environment->isEmpty()" :environment_id="$environment->id" />
</div>
<nav class="flex pt-2 pb-10">
<ol class="flex items-center">

View File

@ -1,16 +1,11 @@
<div>
<x-modal yesOrNo modalId="{{ $modalId }}" modalTitle="Delete Resource">
<x-slot:modalBody>
<p>This resource will be deleted. It is not reversible. <br>Please think again.</p>
</x-slot:modalBody>
</x-modal>
<h2>Danger Zone</h2>
<div class="">Woah. I hope you know what are you doing.</div>
<h4 class="pt-4">Delete Resource</h4>
<div class="pb-4">This will stop your containers, delete all related data, etc. Beware! There is no coming
back!
</div>
<x-forms.button isError isModal modalId="{{ $modalId }}">
Delete
</x-forms.button>
<x-new-modal isErrorButton buttonTitle="Delete">
This resource will be deleted. It is not reversible. <br>Please think again.
</x-new-modal>
</div>

View File

@ -1,10 +1,4 @@
<div>
<x-modal yesOrNo modalId="{{ $modalId }}" modalTitle="Delete Environment Variable">
<x-slot:modalBody>
<p>Are you sure you want to delete this environment variable <span
class="font-bold text-warning">({{ $env->key }})</span>?</p>
</x-slot:modalBody>
</x-modal>
<form wire:submit='submit'
class="flex flex-col gap-2 p-4 m-2 border lg:items-center border-coolgray-300 lg:m-0 lg:p-0 lg:border-0 lg:flex-row">
@if ($isLocked)
@ -38,9 +32,10 @@
@endif
<div class="flex gap-2">
@if ($isLocked)
<x-forms.button isError isModal modalId="{{ $modalId }}">
Delete
</x-forms.button>
<x-new-modal isErrorButton buttonTitle="Delete">
You will delete environment variable <span
class="font-bold text-warning">{{ $env->key }}</span>.
</x-new-modal>
@else
@if ($isDisabled)
<x-forms.button disabled type="submit">
@ -49,9 +44,10 @@
<x-forms.button wire:click='lock'>
Lock
</x-forms.button>
<x-forms.button disabled isError isModal modalId="{{ $modalId }}">
Delete
</x-forms.button>
<x-new-modal isErrorButton buttonTitle="Delete">
You will delete environment variable <span
class="font-bold text-warning">{{ $env->key }}</span>.
</x-new-modal>
@else
<x-forms.button type="submit">
Update
@ -59,9 +55,10 @@
<x-forms.button wire:click='lock'>
Lock
</x-forms.button>
<x-forms.button isError isModal modalId="{{ $modalId }}">
Delete
</x-forms.button>
<x-new-modal isErrorButton buttonTitle="Delete">
You will delete environment variable <span
class="font-bold text-warning">{{ $env->key }}</span>.
</x-new-modal>
@endif
@endif
</div>

View File

@ -13,7 +13,7 @@
<x-forms.input label="Only Show Number of Lines" placeholder="1000" required id="numberOfLines"></x-forms.input>
<x-forms.button type="submit">Refresh</x-forms.button>
</form>
<div id="screen" x-data="{ fullscreen: false, alwaysScroll: false, intervalId: null }" :class="fullscreen ? 'fullscreen' : 'container w-full py-4 mx-auto'">
<div id="screen" x-data="{ fullscreen: false, alwaysScroll: false, intervalId: null }" :class="fullscreen ? 'fullscreen' : 'w-full py-4 mx-auto'">
<div class="relative flex flex-col-reverse w-full p-4 pt-6 overflow-y-auto text-white bg-coolgray-100 scrollbar border-coolgray-300"
:class="fullscreen ? '' : 'max-h-[40rem] border border-solid rounded'">
<button title="Minimize" x-show="fullscreen" class="fixed top-4 right-4" x-on:click="makeFullscreen"><svg
@ -33,8 +33,8 @@
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"
<button title="Fullscreen" x-show="!fullscreen" class="absolute top-2 right-2"
x-on:click="makeFullscreen"><svg class=" icon" viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<g fill="none">
<path

View File

@ -1,11 +1,4 @@
<div>
<x-modal yesOrNo modalId="{{ $modalId }}" modalTitle="Delete Scheduled Task">
<x-slot:modalBody>
<p>Are you sure you want to delete this scheduled task <span
class="font-bold text-warning">({{ $task->name }})</span>?</p>
</x-slot:modalBody>
</x-modal>
<h1>Scheduled Task</h1>
@if ($type === 'application')
<livewire:project.application.heading :application="$resource" />
@ -20,11 +13,9 @@
<x-forms.button type="submit">
Save
</x-forms.button>
<x-forms.button isError isModal modalId="{{ $modalId }}">
Delete
</x-forms.button>
<x-new-modal isErrorButton buttonTitle="Delete Scheduled Task">
You will delete scheduled task <span class="font-bold text-warning">{{ $task->name }}</span>.
</x-new-modal>
</div>
</div>
<div class="flex w-full gap-2">

View File

@ -1,12 +1,4 @@
<div>
<x-modal yesOrNo modalId="{{ $modalId }}" modalTitle="Delete Storage">
<x-slot:modalBody>
<p>This storage will be deleted <span class="font-bold text-warning">({{ $storage->name }})</span>. It is
not
reversible. <br>Please think again.</p>
</x-slot:modalBody>
</x-modal>
<form wire:submit='submit' class="flex flex-col gap-2 xl:items-end xl:flex-row">
@if ($isReadOnly)
@if ($isFirst)
@ -32,9 +24,12 @@
<x-forms.button type="submit">
Update
</x-forms.button>
<x-forms.button isError isModal modalId="{{ $modalId }}">
Delete
</x-forms.button>
<x-new-modal isErrorButton buttonTitle="Delete">
This storage will be deleted <span class="font-bold text-warning">{{ $storage->name }}</span>. It
is
not
reversible. <br>Please think again.
</x-new-modal>
</div>
@endif
</form>

View File

@ -3,9 +3,7 @@
<h1>Environments</h1>
<x-forms.button class="btn" onclick="newEnvironment.showModal()">+ Add</x-forms.button>
<livewire:project.add-environment :project="$project" />
@if ($project->applications->count() === 0)
<livewire:project.delete-project :project_id="$project->id" />
@endif
<livewire:project.delete-project :disabled="$project->resource_count() > 0" :project_id="$project->id" />
</div>
<div class="text-xs truncate subtitle lg:text-sm">{{ $project->name }}</div>
<div class="grid gap-2 lg:grid-cols-2">

View File

@ -1,21 +1,16 @@
<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>
@if (data_get($private_key, 'id') > 0)
<x-new-modal isErrorButton buttonTitle="Delete">
This private key will be deleted. It is not reversible. <br>Please think again.
</x-new-modal>
@endif
</div>
<x-forms.input id="private_key.name" label="Name" required />
@ -36,7 +31,7 @@
Hide
</div>
</div>
@if ($private_key->is_git_related)
@if (data_get($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>

View File

@ -1,9 +1,4 @@
<div>
<x-modal yesOrNo modalId="deleteServer" modalTitle="Delete Server">
<x-slot:modalBody>
<p>This server will be deleted. It is not reversible. <br>Please think again..</p>
</x-slot:modalBody>
</x-modal>
@if ($server->id !== 0)
<h2 class="pt-4">Danger Zone</h2>
<div class="">Woah. I hope you know what are you doing.</div>
@ -12,13 +7,13 @@
back!
</div>
@if ($server->definedResources()->count() > 0)
<x-forms.button disabled isError isModal modalId="deleteServer">
Delete
</x-forms.button>
<x-new-modal disabled isErrorButton buttonTitle="Delete">
This server will be deleted. It is not reversible. <br>Please think again.
</x-new-modal>
@else
<x-forms.button isError isModal modalId="deleteServer">
Delete
</x-forms.button>
<x-new-modal isErrorButton buttonTitle="Delete">
This server will be deleted. It is not reversible. <br>Please think again.
</x-new-modal>
@endif
<div class="flex flex-col">
@forelse ($server->definedResources() as $resource)
@ -26,7 +21,7 @@
<h3 class="pt-4">Resources</h3>
@endif
@if ($resource->link())
<a class="flex gap-2 p-1 hover:bg-coolgray-100 hover:no-underline" href="{{ $resource->link() }}">
<a class="flex gap-2 p-1 hover:bg-coolgray-100 hover:no-underline" href="{{ $resource->link() }}">
<div class="w-64">{{ str($resource->type())->headline() }}</div>
<div>{{ $resource->name }}</div>
</a>
@ -46,7 +41,7 @@
<h3 class="pt-4">Resources</h3>
@endif
@if ($resource->link())
<a class="flex gap-2 p-1 hover:bg-coolgray-100 hover:no-underline" href="{{ $resource->link() }}">
<a class="flex gap-2 p-1 hover:bg-coolgray-100 hover:no-underline" href="{{ $resource->link() }}">
<div class="w-64">{{ str($resource->type())->headline() }}</div>
<div>{{ $resource->name }}</div>
</a>

View File

@ -1,15 +1,13 @@
<div>
<x-modal yesOrNo modalId="changeLocalhost" modalTitle="Change Localhost" action="submit">
<x-slot:modalBody>
<p>You could lost a lot of functionalities if you change the server details of the server where Coolify is
running on.<br>Please think again.</p>
</x-slot:modalBody>
</x-modal>
<form wire:submit='submit' class="flex flex-col">
<div class="flex gap-2">
<h2>General</h2>
@if ($server->id === 0)
<x-forms.button isModal modalId="changeLocalhost">Save</x-forms.button>
<x-new-modal buttonTitle="Save" title="Change Localhost" action="submit">
You could lost a lot of functionalities if you change the server details of the server where Coolify
is
running on.<br>Please think again.
</x-new-modal>
@else
<x-forms.button type="submit">Save</x-forms.button>
@endif

View File

@ -1,9 +1,4 @@
<div>
<x-modal yesOrNo modalId="deleteSource" modalTitle="Delete Source">
<x-slot:modalBody>
<p>This source will be deleted. It is not reversible. <br>Please think again.</p>
</x-slot:modalBody>
</x-modal>
@if (data_get($github_app, 'app_id'))
<form wire:submit='submit'>
<div class="flex items-center gap-2">
@ -18,9 +13,9 @@
</x-forms.button>
</a>
@endif
<x-forms.button isError isModal modalId="deleteSource">
Delete
</x-forms.button>
<x-new-modal isErrorButton buttonTitle="Delete">
This source will be deleted. It is not reversible. <br>Please think again.
</x-new-modal>
</div>
</div>
<div class="subtitle">Your Private GitHub App for private repositories.</div>
@ -77,9 +72,9 @@
<div class="flex items-center gap-2 pb-4">
<h1>GitHub App</h1>
<div class="flex gap-2">
<x-forms.button isError isModal modalId="deleteSource">
Delete
</x-forms.button>
<x-new-modal isErrorButton buttonTitle="Delete">
This source will be deleted. It is not reversible. <br>Please think again.
</x-new-modal>
</div>
</div>
<div class="mb-10 rounded alert alert-warning">

View File

@ -28,11 +28,6 @@
</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>
@ -45,9 +40,9 @@
@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>
<x-new-modal isErrorButton buttonTitle="Delete">
This team be deleted. It is not reversible. <br>Please think again.
</x-new-modal>
@else
<div>
<div class="pb-4">You need to delete the following resources to be able to delete the team:</div>

View File

@ -1,10 +1,4 @@
<div>
<x-modal yesOrNo modalId="deleteS3Storage" modalTitle="Delete S3 Storage">
<x-slot:modalBody>
<p>This storage will be deleted. It is not reversible. Your data won't be touched!<br>Please think again..
</p>
</x-slot:modalBody>
</x-modal>
<form class="flex flex-col gap-2 pb-6" wire:submit='submit'>
<div class="flex items-start gap-2">
<div class="pb-4">
@ -22,9 +16,9 @@
<x-forms.button wire:click="test_s3_connection">
Validate Connection
</x-forms.button>
<x-forms.button isError isModal modalId="deleteS3Storage">
Delete
</x-forms.button>
<x-new-modal isErrorButton buttonTitle="Delete">
This storage will be deleted. It is not reversible. Your data won't be touched!<br>Please think again.
</x-new-modal>
</div>
<div class="flex gap-2">
<x-forms.input label="Name" id="storage.name" />

View File

@ -1,90 +0,0 @@
<div role="status" id="toaster" x-data="toasterHub(@js($toasts), @js($config))" @class([
'fixed z-50 p-4 w-full flex flex-col pointer-events-none sm:p-6',
'bottom-0' => $alignment->is('bottom'),
'top-1/2 -translate-y-1/2' => $alignment->is('middle'),
'top-0' => $alignment->is('top'),
'items-start' => $position->is('left'),
'items-center' => $position->is('center'),
'items-end' => $position->is('right'),
])>
<template x-for="toast in toasts" :key="toast.id">
<div x-show="toast.isVisible" x-init="$nextTick(() => toast.show($el))" @if ($alignment->is('bottom'))
x-transition:enter-start="translate-y-12 opacity-0"
x-transition:enter-end="translate-y-0 opacity-100"
@elseif($alignment->is('top'))
x-transition:enter-start="-translate-y-12 opacity-0"
x-transition:enter-end="translate-y-0 opacity-100"
@else
x-transition:enter-start="opacity-0 scale-90"
x-transition:enter-end="opacity-100 scale-100"
@endif
x-transition:leave-end="opacity-0 scale-90"
class="relative flex duration-300 transform transition ease-in-out max-w-md w-full pointer-events-auto {{ $position->is('center') ? 'text-center' : 'text-left' }}"
:class="toast.select({ error: 'text-white', info: 'text-white', success: 'text-white', warning: 'text-white' })"
>
<i class=" flex items-center gap-2 select-none not-italic pr-6 pl-4 py-3 rounded shadow-lg w-full {{ $alignment->is('bottom') ? 'mt-3' : 'mb-3' }}"
:class="toast.select({
error: 'bg-coolgray-300',
info: 'bg-coolgray-300',
success: 'bg-coolgray-300',
warning: 'bg-coolgray-300'
})">
<template x-if="toast.type === 'success'">
<div class="rounded text-success">
<svg aria-hidden="true" class="w-6 h-6" fill="currentColor" viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd"
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
clip-rule="evenodd"></path>
</svg>
</div>
</template>
<template x-if="toast.type === 'error'">
<div class="rounded text-error">
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" 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="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" />
<path d="M12 9v4" />
<path d="M12 16v.01" />
</svg>
</div>
</template>
<template x-if="toast.type === 'info'">
<div class="rounded text-info">
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" 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="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0" />
<path d="M12 9h.01" />
<path d="M11 12h1v4h1" />
</svg>
</div>
</template>
<template x-if="toast.type === 'warning'">
<div class="rounded text-warning">
<svg aria-hidden="true" class="w-6 h-6" fill="currentColor" viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd"
d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z"
clip-rule="evenodd"></path>
</svg>
</div>
</template>
<span x-html="toast.message" class="w-full pr-10 break-words" />
</i>
@if ($closeable)
<button @click="toast.dispose()" aria-label="@lang('close')"
class="absolute right-0 p-4 focus:outline-none hover:bg-transparent/10 rounded {{ $alignment->is('bottom') ? 'top-3' : 'top-0' }}">
<svg aria-hidden="true" class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd"
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
clip-rule="evenodd"></path>
</svg>
</button>
@endif
</div>
</template>
</div>

View File

@ -4,7 +4,7 @@
services:
filebrowser:
image: filebrowser/filebrowser:latest
image: filebrowser/filebrowser:s6
environment:
- SERVICE_FQDN_FILEBROWSER
- PUID=1000

View File

@ -143,7 +143,7 @@
"filebrowser": {
"documentation": "https:\/\/filebrowser.org\/configuration",
"slogan": "FileBrowser is a self-hosted, web-based file manager and file explorer with a user-friendly interface. It allows you to manage and organize your files and directories directly from your web browser.",
"compose": "c2VydmljZXM6CiAgZmlsZWJyb3dzZXI6CiAgICBpbWFnZTogJ2ZpbGVicm93c2VyL2ZpbGVicm93c2VyOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9GSUxFQlJPV1NFUgogICAgICAtIFBVSUQ9MTAwMAogICAgICAtIFBHSUQ9MTAwMAogICAgdm9sdW1lczoKICAgICAgLSAnZmlsZWJyb3dzZXItc3J2Oi9zcnYnCiAgICAgIC0gJ2ZpbGVicm93c2VyLWRhdGFiYXNlOi9kYXRhYmFzZS9maWxlYnJvd3Nlci5kYicKICAgICAgLSAnZmlsZWJyb3dzZXItY29uZmlnOi9jb25maWcvc2V0dGluZ3MuanNvbicKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovL2xvY2FsaG9zdDo4MCcKICAgICAgaW50ZXJ2YWw6IDJzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAxNQo=",
"compose": "c2VydmljZXM6CiAgZmlsZWJyb3dzZXI6CiAgICBpbWFnZTogJ2ZpbGVicm93c2VyL2ZpbGVicm93c2VyOnM2JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0ZJTEVCUk9XU0VSCiAgICAgIC0gUFVJRD0xMDAwCiAgICAgIC0gUEdJRD0xMDAwCiAgICB2b2x1bWVzOgogICAgICAtICdmaWxlYnJvd3Nlci1zcnY6L3NydicKICAgICAgLSAnZmlsZWJyb3dzZXItZGF0YWJhc2U6L2RhdGFiYXNlL2ZpbGVicm93c2VyLmRiJwogICAgICAtICdmaWxlYnJvd3Nlci1jb25maWc6L2NvbmZpZy9zZXR0aW5ncy5qc29uJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjgwJwogICAgICBpbnRlcnZhbDogMnMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDE1Cg==",
"tags": [
"file-management",
"storage-access",

View File

@ -4,7 +4,7 @@
"version": "3.12.36"
},
"v4": {
"version": "4.0.0-beta.203"
"version": "4.0.0-beta.204"
}
}
}