mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-14 06:17:36 +00:00
Merge remote-tracking branch 'origin/next' into ghe-support-helpers
This commit is contained in:
commit
b90380f542
477 files changed
+19669
-4970
No files matched your search
@@ -122,7 +122,11 @@
|
||||
}
|
||||
|
||||
@utility button {
|
||||
@apply flex gap-2 justify-center items-center px-2 h-8 text-sm text-black normal-case rounded-sm border-2 outline-0 cursor-pointer font-medium bg-white border-neutral-200 hover:bg-neutral-100 dark:bg-coolgray-100 dark:text-white dark:hover:text-white dark:hover:bg-coolgray-200 dark:border-coolgray-300 hover:text-black disabled:cursor-not-allowed min-w-fit dark:disabled:text-neutral-600 disabled:border-transparent disabled:hover:bg-transparent disabled:bg-transparent disabled:text-neutral-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-coollabs dark:focus-visible:ring-warning focus-visible:ring-offset-2 dark:focus-visible:ring-offset-base;
|
||||
@apply flex gap-2 justify-center items-center px-2 h-8 text-sm text-black normal-case rounded-sm border-2 outline-0 cursor-pointer font-medium bg-white border-neutral-200 hover:bg-neutral-100 dark:bg-coolgray-100 dark:text-white dark:hover:text-white dark:hover:bg-coolgray-200 dark:border-coolgray-300 hover:text-black disabled:cursor-not-allowed min-w-fit dark:disabled:text-neutral-600 disabled:border-neutral-200 dark:disabled:border-coolgray-300 disabled:hover:bg-transparent disabled:bg-transparent disabled:text-neutral-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-coollabs dark:focus-visible:ring-warning focus-visible:ring-offset-2 dark:focus-visible:ring-offset-base;
|
||||
}
|
||||
|
||||
@utility auth-tooltip {
|
||||
@apply fixed z-[99] px-2.5 py-1.5 text-xs rounded-sm pointer-events-none whitespace-nowrap text-neutral-700 bg-neutral-200 dark:text-neutral-300 dark:bg-coolgray-400;
|
||||
}
|
||||
|
||||
@utility alert-success {
|
||||
@@ -355,4 +359,8 @@
|
||||
gap: 0;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
.sidebar-collapsed .sidebar-collapsed-label {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -3,50 +3,84 @@
|
||||
Advanced
|
||||
</x-slot>
|
||||
@if ($application->status === 'running')
|
||||
<x-modal-confirmation title="Confirm Application Force Deployment?" buttonTitle="Force deploy"
|
||||
submitAction="force_deploy_without_cache" :actions="[
|
||||
'This application will be force deployed without build cache.',
|
||||
]" :confirmWithText="false" :confirmWithPassword="false"
|
||||
step2ButtonText="Confirm">
|
||||
<x-slot:content>
|
||||
<div class="dropdown-iteme">
|
||||
<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.983 8.978c3.955 -.182 7.017 -1.446 7.017 -2.978c0 -1.657 -3.582 -3 -8 -3c-1.661 0 -3.204 .19 -4.483 .515m-2.783 1.228c-.471 .382 -.734 .808 -.734 1.257c0 1.22 1.944 2.271 4.734 2.74" />
|
||||
<path
|
||||
d="M4 6v6c0 1.657 3.582 3 8 3c.986 0 1.93 -.067 2.802 -.19m3.187 -.82c1.251 -.53 2.011 -1.228 2.011 -1.99v-6" />
|
||||
<path d="M4 12v6c0 1.657 3.582 3 8 3c3.217 0 5.991 -.712 7.261 -1.74m.739 -3.26v-4" />
|
||||
<path d="M3 3l18 18" />
|
||||
</svg>
|
||||
Force deploy (without
|
||||
cache)
|
||||
</div>
|
||||
</x-slot:content>
|
||||
</x-modal-confirmation>
|
||||
@can('deploy', $application)
|
||||
<x-modal-confirmation title="Confirm Application Force Deployment?" buttonTitle="Force deploy"
|
||||
submitAction="force_deploy_without_cache" :actions="[
|
||||
'This application will be force deployed without build cache.',
|
||||
]" :confirmWithText="false" :confirmWithPassword="false"
|
||||
step2ButtonText="Confirm">
|
||||
<x-slot:content>
|
||||
<div class="dropdown-iteme">
|
||||
<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.983 8.978c3.955 -.182 7.017 -1.446 7.017 -2.978c0 -1.657 -3.582 -3 -8 -3c-1.661 0 -3.204 .19 -4.483 .515m-2.783 1.228c-.471 .382 -.734 .808 -.734 1.257c0 1.22 1.944 2.271 4.734 2.74" />
|
||||
<path
|
||||
d="M4 6v6c0 1.657 3.582 3 8 3c.986 0 1.93 -.067 2.802 -.19m3.187 -.82c1.251 -.53 2.011 -1.228 2.011 -1.99v-6" />
|
||||
<path d="M4 12v6c0 1.657 3.582 3 8 3c3.217 0 5.991 -.712 7.261 -1.74m.739 -3.26v-4" />
|
||||
<path d="M3 3l18 18" />
|
||||
</svg>
|
||||
Force deploy (without
|
||||
cache)
|
||||
</div>
|
||||
</x-slot:content>
|
||||
</x-modal-confirmation>
|
||||
@else
|
||||
<div class="dropdown-iteme" data-disabled>
|
||||
<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.983 8.978c3.955 -.182 7.017 -1.446 7.017 -2.978c0 -1.657 -3.582 -3 -8 -3c-1.661 0 -3.204 .19 -4.483 .515m-2.783 1.228c-.471 .382 -.734 .808 -.734 1.257c0 1.22 1.944 2.271 4.734 2.74" />
|
||||
<path
|
||||
d="M4 6v6c0 1.657 3.582 3 8 3c.986 0 1.93 -.067 2.802 -.19m3.187 -.82c1.251 -.53 2.011 -1.228 2.011 -1.99v-6" />
|
||||
<path d="M4 12v6c0 1.657 3.582 3 8 3c3.217 0 5.991 -.712 7.261 -1.74m.739 -3.26v-4" />
|
||||
<path d="M3 3l18 18" />
|
||||
</svg>
|
||||
Force deploy (without
|
||||
cache)
|
||||
</div>
|
||||
@endcan
|
||||
@else
|
||||
<x-modal-confirmation title="Confirm Application Force Deployment?" buttonTitle="Force deploy"
|
||||
submitAction="deploy(true)" :actions="[
|
||||
'This application will be force deployed without build cache.',
|
||||
]" :confirmWithText="false" :confirmWithPassword="false"
|
||||
step2ButtonText="Confirm">
|
||||
<x-slot:content>
|
||||
<div class="dropdown-item">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" 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.983 8.978c3.955 -.182 7.017 -1.446 7.017 -2.978c0 -1.657 -3.582 -3 -8 -3c-1.661 0 -3.204 .19 -4.483 .515m-2.783 1.228c-.471 .382 -.734 .808 -.734 1.257c0 1.22 1.944 2.271 4.734 2.74" />
|
||||
<path
|
||||
d="M4 6v6c0 1.657 3.582 3 8 3c.986 0 1.93 -.067 2.802 -.19m3.187 -.82c1.251 -.53 2.011 -1.228 2.011 -1.99v-6" />
|
||||
<path d="M4 12v6c0 1.657 3.582 3 8 3c3.217 0 5.991 -.712 7.261 -1.74m.739 -3.26v-4" />
|
||||
<path d="M3 3l18 18" />
|
||||
</svg>
|
||||
Force deploy (without
|
||||
cache)
|
||||
</div>
|
||||
</x-slot:content>
|
||||
</x-modal-confirmation>
|
||||
@can('deploy', $application)
|
||||
<x-modal-confirmation title="Confirm Application Force Deployment?" buttonTitle="Force deploy"
|
||||
submitAction="deploy(true)" :actions="[
|
||||
'This application will be force deployed without build cache.',
|
||||
]" :confirmWithText="false" :confirmWithPassword="false"
|
||||
step2ButtonText="Confirm">
|
||||
<x-slot:content>
|
||||
<div class="dropdown-item">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" 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.983 8.978c3.955 -.182 7.017 -1.446 7.017 -2.978c0 -1.657 -3.582 -3 -8 -3c-1.661 0 -3.204 .19 -4.483 .515m-2.783 1.228c-.471 .382 -.734 .808 -.734 1.257c0 1.22 1.944 2.271 4.734 2.74" />
|
||||
<path
|
||||
d="M4 6v6c0 1.657 3.582 3 8 3c.986 0 1.93 -.067 2.802 -.19m3.187 -.82c1.251 -.53 2.011 -1.228 2.011 -1.99v-6" />
|
||||
<path d="M4 12v6c0 1.657 3.582 3 8 3c3.217 0 5.991 -.712 7.261 -1.74m.739 -3.26v-4" />
|
||||
<path d="M3 3l18 18" />
|
||||
</svg>
|
||||
Force deploy (without
|
||||
cache)
|
||||
</div>
|
||||
</x-slot:content>
|
||||
</x-modal-confirmation>
|
||||
@else
|
||||
<div class="dropdown-item" data-disabled>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" 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.983 8.978c3.955 -.182 7.017 -1.446 7.017 -2.978c0 -1.657 -3.582 -3 -8 -3c-1.661 0 -3.204 .19 -4.483 .515m-2.783 1.228c-.471 .382 -.734 .808 -.734 1.257c0 1.22 1.944 2.271 4.734 2.74" />
|
||||
<path
|
||||
d="M4 6v6c0 1.657 3.582 3 8 3c.986 0 1.93 -.067 2.802 -.19m3.187 -.82c1.251 -.53 2.011 -1.228 2.011 -1.99v-6" />
|
||||
<path d="M4 12v6c0 1.657 3.582 3 8 3c3.217 0 5.991 -.712 7.261 -1.74m.739 -3.26v-4" />
|
||||
<path d="M3 3l18 18" />
|
||||
</svg>
|
||||
Force deploy (without
|
||||
cache)
|
||||
</div>
|
||||
@endcan
|
||||
@endif
|
||||
</x-dropdown>
|
||||
@@ -11,6 +11,7 @@
|
||||
'certificateValidUntil' => null,
|
||||
'isExited' => false,
|
||||
'showPublicUrlPlaceholder' => false,
|
||||
'isPasswordHiddenForMember' => false,
|
||||
])
|
||||
|
||||
@php
|
||||
@@ -18,14 +19,19 @@
|
||||
@endphp
|
||||
|
||||
<div class="flex flex-col gap-2">
|
||||
<x-forms.input :label="$label . ' URL (internal)'" :helper="$urlHelper" type="password" readonly
|
||||
wire:model="dbUrl" canGate="update" :canResource="$database" />
|
||||
@if ($dbUrlPublic)
|
||||
<x-forms.input :label="$label . ' URL (public)'" :helper="$urlHelper" type="password" readonly
|
||||
wire:model="dbUrlPublic" canGate="update" :canResource="$database" />
|
||||
@elseif ($showPublicUrlPlaceholder)
|
||||
<x-forms.input :label="$label . ' URL (public)'" :helper="$urlHelper" readonly
|
||||
value="Starting the database will generate this." canGate="update" :canResource="$database" />
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input :label="$label . ' URL (internal)'" disabled value="Hidden (only admins can view)" />
|
||||
<x-forms.input :label="$label . ' URL (public)'" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input :label="$label . ' URL (internal)'" :helper="$urlHelper" type="password" readonly
|
||||
wire:model="dbUrl" canGate="update" :canResource="$database" />
|
||||
@if ($dbUrlPublic)
|
||||
<x-forms.input :label="$label . ' URL (public)'" :helper="$urlHelper" type="password" readonly
|
||||
wire:model="dbUrlPublic" canGate="update" :canResource="$database" />
|
||||
@elseif ($showPublicUrlPlaceholder)
|
||||
<x-forms.input :label="$label . ' URL (public)'" :helper="$urlHelper" readonly
|
||||
value="Starting the database will generate this." canGate="update" :canResource="$database" />
|
||||
@endif
|
||||
@endif
|
||||
|
||||
@if ($supportsSsl)
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
@if ($authDisabled)
|
||||
<span class="relative inline-flex"
|
||||
x-data="{ visible: false, _t: null }"
|
||||
@mouseenter="_t = setTimeout(() => {
|
||||
visible = true;
|
||||
$nextTick(() => requestAnimationFrame(() => {
|
||||
const tip = $refs.tip;
|
||||
if (!tip) return;
|
||||
const r = $el.getBoundingClientRect();
|
||||
const t = tip.getBoundingClientRect();
|
||||
let top = r.top - t.height - 6;
|
||||
let left = r.left;
|
||||
if (top < 4) top = r.bottom + 6;
|
||||
if (left + t.width > innerWidth - 8) left = innerWidth - 8 - t.width;
|
||||
if (left < 4) left = 4;
|
||||
tip.style.top = top + 'px';
|
||||
tip.style.left = left + 'px';
|
||||
}));
|
||||
}, 300)"
|
||||
@mouseleave="clearTimeout(_t); visible = false">
|
||||
@endif
|
||||
<button @disabled($disabled) {{ $attributes->merge(['class' => $defaultClass]) }}
|
||||
{{ $attributes->merge(['type' => 'button']) }}
|
||||
@isset($confirm)
|
||||
@@ -18,3 +39,9 @@
|
||||
@endif
|
||||
@endif
|
||||
</button>
|
||||
@if ($authDisabled)
|
||||
<div x-ref="tip" x-show="visible" x-cloak class="auth-tooltip">
|
||||
You do not have permission to perform this action.
|
||||
</div>
|
||||
</span>
|
||||
@endif
|
||||
@@ -2,24 +2,27 @@
|
||||
|
||||
<div class="w-full" x-data="{ copied: false, isSecure: window.isSecureContext }">
|
||||
@if ($label)
|
||||
<label class="flex gap-1 items-center mb-1 text-sm font-medium">{{ $label }}</label>
|
||||
<label class="flex gap-1 items-center mb-1 text-sm font-medium text-black dark:text-white">{{ $label }}</label>
|
||||
@endif
|
||||
<div class="relative">
|
||||
<input type="text" value="{{ $text }}" class="input pr-10"
|
||||
<input type="text" value="{{ $text }}"
|
||||
class="input pr-11 bg-white dark:bg-coolgray-100 dark:read-only:bg-coolgray-100 dark:read-only:text-white"
|
||||
readonly
|
||||
@keydown.prevent @paste.prevent @cut.prevent @drop.prevent
|
||||
@focus="$event.target.select()">
|
||||
<button
|
||||
x-show="isSecure"
|
||||
@click.prevent="copied = true; navigator.clipboard.writeText({{ Js::from($text) }}); setTimeout(() => copied = false, 1000)"
|
||||
class="absolute right-2 top-1/2 -translate-y-1/2 p-1.5 text-gray-400 hover:text-gray-300 transition-colors"
|
||||
title="Copy to clipboard">
|
||||
<svg x-show="!copied" class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
|
||||
</svg>
|
||||
<svg x-show="copied" class="w-5 h-5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
x-show="isSecure"
|
||||
@click.prevent="copied = true; navigator.clipboard.writeText({{ Js::from($text) }}); setTimeout(() => copied = false, 1000)"
|
||||
class="absolute right-2 top-1/2 -translate-y-1/2 rounded-sm p-1.5 text-neutral-500 transition-colors hover:text-neutral-700 focus-visible:ring-2 focus-visible:ring-coollabs focus-visible:ring-offset-2 dark:text-neutral-400 dark:hover:text-white dark:focus-visible:ring-warning dark:focus-visible:ring-offset-base"
|
||||
title="Copy to clipboard"
|
||||
aria-label="Copy to clipboard">
|
||||
<svg x-show="!copied" class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
|
||||
</svg>
|
||||
<svg x-show="copied" class="w-5 h-5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -6,6 +6,7 @@
|
||||
'buttonFullWidth' => false,
|
||||
'customButton' => null,
|
||||
'disabled' => false,
|
||||
'authDisabled' => false,
|
||||
'dispatchAction' => false,
|
||||
'submitAction' => 'delete',
|
||||
'content' => null,
|
||||
@@ -128,9 +129,13 @@
|
||||
}
|
||||
}"
|
||||
@keydown.escape.window="if (modalOpen) { modalOpen = false; resetModal(); }" :class="{ 'z-40': modalOpen }"
|
||||
class="relative w-auto h-auto">
|
||||
@class([
|
||||
'relative h-auto',
|
||||
'w-full' => $buttonFullWidth,
|
||||
'w-full sm:w-auto' => ! $buttonFullWidth,
|
||||
])>
|
||||
@if (isset($trigger))
|
||||
<div @click="modalOpen=true">
|
||||
<div class="w-full" @click="modalOpen=true">
|
||||
{{ $trigger }}
|
||||
</div>
|
||||
@elseif ($customButton)
|
||||
@@ -151,11 +156,11 @@
|
||||
@else
|
||||
@if ($disabled)
|
||||
@if ($buttonFullWidth)
|
||||
<x-forms.button class="w-full" isError disabled wire:target>
|
||||
<x-forms.button class="w-full" isError disabled :authDisabled="$authDisabled" wire:target>
|
||||
{{ $buttonTitle }}
|
||||
</x-forms.button>
|
||||
@else
|
||||
<x-forms.button isError disabled wire:target>
|
||||
<x-forms.button isError disabled :authDisabled="$authDisabled" wire:target>
|
||||
{{ $buttonTitle }}
|
||||
</x-forms.button>
|
||||
@endif
|
||||
|
||||
@@ -44,16 +44,6 @@
|
||||
this.queryTheme();
|
||||
this.checkZoom();
|
||||
},
|
||||
setTheme(type) {
|
||||
this.theme = type;
|
||||
localStorage.setItem('theme', type);
|
||||
this.queryTheme();
|
||||
},
|
||||
cycleTheme() {
|
||||
const themes = ['light', 'system', 'dark'];
|
||||
const currentIndex = themes.indexOf(this.theme || localStorage.getItem('theme') || 'dark');
|
||||
this.setTheme(themes[(currentIndex + 1) % themes.length]);
|
||||
},
|
||||
queryTheme() {
|
||||
const darkModePreference = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
const userSettings = localStorage.getItem('theme') || 'dark';
|
||||
@@ -375,45 +365,6 @@
|
||||
<li>
|
||||
<livewire:settings-dropdown trigger="changelog-sidebar" />
|
||||
</li>
|
||||
<li>
|
||||
<button type="button" @click.stop="cycleTheme()"
|
||||
:title="`Theme: ${theme === 'system' ? 'System default' : theme}. Click to change.`"
|
||||
:aria-label="`Theme: ${theme === 'system' ? 'System default' : theme}. Click to change theme.`"
|
||||
class="menu-item"
|
||||
:class="collapsed && 'lg:hidden'">
|
||||
<svg x-show="theme === 'dark'" class="menu-item-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
|
||||
</svg>
|
||||
<svg x-show="theme === 'light'" class="menu-item-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
|
||||
</svg>
|
||||
<svg x-show="theme === 'system'" class="menu-item-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||
</svg>
|
||||
<span class="text-left menu-item-label">Theme</span>
|
||||
</button>
|
||||
<button type="button" @click.stop="cycleTheme()"
|
||||
:title="`Theme: ${theme === 'system' ? 'System default' : theme}. Click to change.`"
|
||||
:aria-label="`Theme: ${theme === 'system' ? 'System default' : theme}. Click to change theme.`"
|
||||
class="menu-item hidden"
|
||||
:class="collapsed && 'lg:flex'">
|
||||
<svg x-show="theme === 'dark'" class="menu-item-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
|
||||
</svg>
|
||||
<svg x-show="theme === 'light'" class="menu-item-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
|
||||
</svg>
|
||||
<svg x-show="theme === 'system'" class="menu-item-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||
</svg>
|
||||
</button>
|
||||
</li>
|
||||
@if (isInstanceAdmin() && !isCloud())
|
||||
@persist('upgrade')
|
||||
<li>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<div class="sub-menu-wrapper">
|
||||
<a class="{{ request()->routeIs('server.sentinel') ? 'sub-menu-item menu-item-active' : 'sub-menu-item' }}" {{ wireNavigate() }}
|
||||
href="{{ route('server.sentinel', $parameters) }}">
|
||||
<span class="menu-item-label">Configuration</span>
|
||||
</a>
|
||||
<a class="{{ request()->routeIs('server.sentinel.logs') ? 'sub-menu-item menu-item-active' : 'sub-menu-item' }}" {{ wireNavigate() }}
|
||||
href="{{ route('server.sentinel.logs', $parameters) }}">
|
||||
<span class="menu-item-label">Logs</span>
|
||||
</a>
|
||||
@can('viewSentinel', $server)
|
||||
<a class="{{ request()->routeIs('server.sentinel') ? 'sub-menu-item menu-item-active' : 'sub-menu-item' }}" {{ wireNavigate() }}
|
||||
href="{{ route('server.sentinel', $parameters) }}">
|
||||
<span class="menu-item-label">Configuration</span>
|
||||
</a>
|
||||
<a class="{{ request()->routeIs('server.sentinel.logs') ? 'sub-menu-item menu-item-active' : 'sub-menu-item' }}" {{ wireNavigate() }}
|
||||
href="{{ route('server.sentinel.logs', $parameters) }}">
|
||||
<span class="menu-item-label">Logs</span>
|
||||
</a>
|
||||
@endcan
|
||||
</div>
|
||||
@@ -3,7 +3,7 @@
|
||||
Advanced
|
||||
</x-slot>
|
||||
@if (str($service->status)->contains('running'))
|
||||
<div class="dropdown-item" @click="document.getElementById('service-pullAndRestart-trigger')?.click()">
|
||||
<div class="dropdown-item" @if(!auth()->user()->can('deploy', $service)) data-disabled @endif @click="document.getElementById('service-pullAndRestart-trigger')?.click()">
|
||||
<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" />
|
||||
@@ -17,7 +17,7 @@
|
||||
Pull Latest Images & Restart
|
||||
</div>
|
||||
@elseif (str($service->status)->contains('degraded'))
|
||||
<div class="dropdown-item" @click="document.getElementById('service-forceDeploy-trigger')?.click()">
|
||||
<div class="dropdown-item" @if(!auth()->user()->can('deploy', $service)) data-disabled @endif @click="document.getElementById('service-forceDeploy-trigger')?.click()">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-linecap="round" stroke-linejoin="round" data-darkreader-inline-stroke=""
|
||||
style="--darkreader-inline-stroke: currentColor;" class="w-6 h-6" stroke-width="2">
|
||||
@@ -27,7 +27,7 @@
|
||||
Force Restart
|
||||
</div>
|
||||
@else
|
||||
<div class="dropdown-item" @click="document.getElementById('service-forceDeploy-trigger')?.click()">
|
||||
<div class="dropdown-item" @if(!auth()->user()->can('deploy', $service)) data-disabled @endif @click="document.getElementById('service-forceDeploy-trigger')?.click()">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-linecap="round" stroke-linejoin="round" data-darkreader-inline-stroke=""
|
||||
style="--darkreader-inline-stroke: currentColor;" class="w-4 h-4" stroke-width="2">
|
||||
@@ -36,7 +36,7 @@
|
||||
</svg>
|
||||
Force Deploy
|
||||
</div>
|
||||
<div class="dropdown-item" @click="document.getElementById('service-cleanup-trigger')?.click()">
|
||||
<div class="dropdown-item" @if(!auth()->user()->can('stop', $service)) data-disabled @endif @click="document.getElementById('service-cleanup-trigger')?.click()">
|
||||
<svg class="w-4 h-4" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="currentColor" d="M26 20h-6v-2h6zm4 8h-6v-2h6zm-2-4h-6v-2h6z" />
|
||||
<path fill="currentColor"
|
||||
|
||||
@@ -11,20 +11,23 @@
|
||||
<section class="-mt-2">
|
||||
<div class="flex items-center gap-2 pb-2">
|
||||
<h3>Projects</h3>
|
||||
@if ($projects->count() > 0)
|
||||
<x-modal-input buttonTitle="Add" title="New Project">
|
||||
<x-slot:content>
|
||||
<button
|
||||
class="flex items-center justify-center size-4 text-black dark:text-white rounded hover:bg-coolgray-400 dark:hover:bg-coolgray-300 cursor-pointer">
|
||||
<svg class="size-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="2" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
||||
</svg>
|
||||
</button>
|
||||
</x-slot:content>
|
||||
<livewire:project.add-empty />
|
||||
</x-modal-input>
|
||||
@endif
|
||||
@can('create', App\Models\Project::class)
|
||||
@if ($projects->count() > 0)
|
||||
<x-modal-input buttonTitle="Add" title="New Project">
|
||||
<x-slot:content>
|
||||
<button
|
||||
class="flex items-center justify-center size-4 text-black dark:text-white rounded hover:bg-coolgray-400 dark:hover:bg-coolgray-300 cursor-pointer">
|
||||
<svg class="size-3" xmlns="http://www.w3.org/2000/svg" fill="none"
|
||||
viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M12 4.5v15m7.5-7.5h-15" />
|
||||
</svg>
|
||||
</button>
|
||||
</x-slot:content>
|
||||
<livewire:project.add-empty />
|
||||
</x-modal-input>
|
||||
@endif
|
||||
@endcan
|
||||
</div>
|
||||
@if ($projects->count() > 0)
|
||||
<div class="grid grid-cols-1 gap-4 xl:grid-cols-2">
|
||||
@@ -64,12 +67,15 @@
|
||||
@else
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class='font-bold dark:text-warning'>No projects found.</div>
|
||||
<div class="flex items-center gap-1">
|
||||
<x-modal-input buttonTitle="Add" title="New Project">
|
||||
<livewire:project.add-empty />
|
||||
</x-modal-input> your first project or
|
||||
go to the <a class="underline dark:text-white" href="{{ route('onboarding') }}" {{ wireNavigate() }}>onboarding</a> page.
|
||||
</div>
|
||||
@can('create', App\Models\Project::class)
|
||||
<div class="flex items-center gap-1">
|
||||
<x-modal-input buttonTitle="Add" title="New Project">
|
||||
<livewire:project.add-empty />
|
||||
</x-modal-input> your first project or
|
||||
go to the <a class="underline dark:text-white" href="{{ route('onboarding') }}"
|
||||
{{ wireNavigate() }}>onboarding</a> page.
|
||||
</div>
|
||||
@endcan
|
||||
</div>
|
||||
@endif
|
||||
</section>
|
||||
@@ -77,20 +83,23 @@
|
||||
<section>
|
||||
<div class="flex items-center gap-2 pb-2">
|
||||
<h3>Servers</h3>
|
||||
@if ($servers->count() > 0 && $privateKeys->count() > 0)
|
||||
<x-modal-input buttonTitle="Add" title="New Server" :closeOutside="false">
|
||||
<x-slot:content>
|
||||
<button
|
||||
class="flex items-center justify-center size-4 text-black dark:text-white rounded hover:bg-coolgray-400 dark:hover:bg-coolgray-300 cursor-pointer">
|
||||
<svg class="size-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="2" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
||||
</svg>
|
||||
</button>
|
||||
</x-slot:content>
|
||||
<livewire:server.create />
|
||||
</x-modal-input>
|
||||
@endif
|
||||
@can('create', App\Models\Server::class)
|
||||
@if ($servers->count() > 0 && $privateKeys->count() > 0)
|
||||
<x-modal-input buttonTitle="Add" title="New Server" :closeOutside="false">
|
||||
<x-slot:content>
|
||||
<button
|
||||
class="flex items-center justify-center size-4 text-black dark:text-white rounded hover:bg-coolgray-400 dark:hover:bg-coolgray-300 cursor-pointer">
|
||||
<svg class="size-3" xmlns="http://www.w3.org/2000/svg" fill="none"
|
||||
viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M12 4.5v15m7.5-7.5h-15" />
|
||||
</svg>
|
||||
</button>
|
||||
</x-slot:content>
|
||||
<livewire:server.create />
|
||||
</x-modal-input>
|
||||
@endif
|
||||
@endcan
|
||||
</div>
|
||||
@if ($servers->count() > 0)
|
||||
<div class="grid grid-cols-1 gap-4 xl:grid-cols-2">
|
||||
@@ -127,26 +136,34 @@
|
||||
@if ($privateKeys->count() === 0)
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class='font-bold dark:text-warning'>No private keys found.</div>
|
||||
<div class="flex items-center gap-1">Before you can add your server, first <x-modal-input
|
||||
buttonTitle="add" title="New Private Key">
|
||||
<livewire:security.private-key.create from="server" />
|
||||
</x-modal-input> a private key
|
||||
or
|
||||
go to the <a class="underline dark:text-white" href="{{ route('onboarding') }}" {{ wireNavigate() }}>onboarding</a>
|
||||
page.
|
||||
</div>
|
||||
@can('create', App\Models\Server::class)
|
||||
<div class="flex items-center gap-1">Before you can add your server, first <x-modal-input
|
||||
buttonTitle="add" title="New Private Key">
|
||||
<livewire:security.private-key.create from="server" />
|
||||
</x-modal-input> a private key
|
||||
or
|
||||
go to the <a class="underline dark:text-white"
|
||||
href="{{ route('onboarding') }}"
|
||||
{{ wireNavigate() }}>onboarding</a>
|
||||
page.
|
||||
</div>
|
||||
@endcan
|
||||
</div>
|
||||
@else
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class='font-bold dark:text-warning'>No servers found.</div>
|
||||
<div class="flex items-center gap-1">
|
||||
<x-modal-input buttonTitle="Add" title="New Server" :closeOutside="false">
|
||||
<livewire:server.create />
|
||||
</x-modal-input> your first server
|
||||
or
|
||||
go to the <a class="underline dark:text-white" href="{{ route('onboarding') }}" {{ wireNavigate() }}>onboarding</a>
|
||||
page.
|
||||
</div>
|
||||
@can('create', App\Models\Server::class)
|
||||
<div class="flex items-center gap-1">
|
||||
<x-modal-input buttonTitle="Add" title="New Server" :closeOutside="false">
|
||||
<livewire:server.create />
|
||||
</x-modal-input> your first server
|
||||
or
|
||||
go to the <a class="underline dark:text-white"
|
||||
href="{{ route('onboarding') }}"
|
||||
{{ wireNavigate() }}>onboarding</a>
|
||||
page.
|
||||
</div>
|
||||
@endcan
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
</form>
|
||||
</div>
|
||||
@else
|
||||
<x-callout type="warning" title="Permission Required">
|
||||
<x-callout type="danger" title="Insufficient Permissions">
|
||||
You don't have permission to create new destinations. Please contact your team administrator for access.
|
||||
</x-callout>
|
||||
@endcan
|
||||
@@ -26,9 +26,15 @@
|
||||
helper="If enabled, a ping (@here) will be sent to the notification when a critical event happens."
|
||||
label="Ping Enabled" />
|
||||
</div>
|
||||
<x-forms.input canGate="update" :canResource="$settings" type="password"
|
||||
helper="Create a Discord Server and generate a Webhook URL. <br><a class='inline-block underline dark:text-white' href='https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks' target='_blank'>Webhook Documentation</a>"
|
||||
required id="discordWebhookUrl" label="Webhook" />
|
||||
@can('update', $settings)
|
||||
<x-forms.input type="password"
|
||||
helper="Create a Discord Server and generate a Webhook URL. <br><a class='inline-block underline dark:text-white' href='https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks' target='_blank'>Webhook Documentation</a>"
|
||||
required id="discordWebhookUrl" label="Webhook" />
|
||||
@else
|
||||
<x-forms.input disabled
|
||||
helper="Create a Discord Server and generate a Webhook URL. <br><a class='inline-block underline dark:text-white' href='https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks' target='_blank'>Webhook Documentation</a>"
|
||||
required label="Webhook" value="Hidden (only admins can view)" />
|
||||
@endcan
|
||||
</form>
|
||||
<h2 class="mt-4">Notification Settings</h2>
|
||||
<p class="mb-4">
|
||||
|
||||
@@ -81,7 +81,11 @@
|
||||
</div>
|
||||
<div class="flex flex-col w-full gap-2 xl:flex-row">
|
||||
<x-forms.input canGate="update" :canResource="$settings" id="smtpUsername" label="SMTP Username" />
|
||||
<x-forms.input canGate="update" :canResource="$settings" id="smtpPassword" type="password" label="SMTP Password" />
|
||||
@can('update', $settings)
|
||||
<x-forms.input canGate="update" :canResource="$settings" id="smtpPassword" type="password" label="SMTP Password" />
|
||||
@else
|
||||
<x-forms.input disabled label="SMTP Password" value="Hidden (only admins can view)" />
|
||||
@endcan
|
||||
<x-forms.input canGate="update" :canResource="$settings" id="smtpTimeout" type="number" helper="Timeout value for sending emails."
|
||||
label="Timeout" />
|
||||
</div>
|
||||
@@ -103,8 +107,12 @@
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex flex-col w-full gap-2 xl:flex-row">
|
||||
<x-forms.input canGate="update" :canResource="$settings" required type="password" id="resendApiKey" placeholder="API key"
|
||||
label="API Key" />
|
||||
@can('update', $settings)
|
||||
<x-forms.input canGate="update" :canResource="$settings" required type="password" id="resendApiKey" placeholder="API key"
|
||||
label="API Key" />
|
||||
@else
|
||||
<x-forms.input disabled label="API Key" value="Hidden (only admins can view)" />
|
||||
@endcan
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -24,12 +24,21 @@
|
||||
<x-forms.checkbox canGate="update" :canResource="$settings" instantSave="instantSavePushoverEnabled" id="pushoverEnabled" label="Enabled" />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input canGate="update" :canResource="$settings" type="password"
|
||||
helper="Get your User Key in Pushover. You need to be logged in to Pushover to see your user key in the top right corner. <br><a class='inline-block underline dark:text-white' href='https://pushover.net/' target='_blank'>Pushover Dashboard</a>"
|
||||
required id="pushoverUserKey" label="User Key" />
|
||||
<x-forms.input canGate="update" :canResource="$settings" type="password"
|
||||
helper="Generate an API Token/Key in Pushover by creating a new application. <br><a class='inline-block underline dark:text-white' href='https://pushover.net/apps/build' target='_blank'>Create Pushover Application</a>"
|
||||
required id="pushoverApiToken" label="API Token" />
|
||||
@can('update', $settings)
|
||||
<x-forms.input type="password"
|
||||
helper="Get your User Key in Pushover. You need to be logged in to Pushover to see your user key in the top right corner. <br><a class='inline-block underline dark:text-white' href='https://pushover.net/' target='_blank'>Pushover Dashboard</a>"
|
||||
required id="pushoverUserKey" label="User Key" />
|
||||
<x-forms.input type="password"
|
||||
helper="Generate an API Token/Key in Pushover by creating a new application. <br><a class='inline-block underline dark:text-white' href='https://pushover.net/apps/build' target='_blank'>Create Pushover Application</a>"
|
||||
required id="pushoverApiToken" label="API Token" />
|
||||
@else
|
||||
<x-forms.input disabled
|
||||
helper="Get your User Key in Pushover. You need to be logged in to Pushover to see your user key in the top right corner. <br><a class='inline-block underline dark:text-white' href='https://pushover.net/' target='_blank'>Pushover Dashboard</a>"
|
||||
required label="User Key" value="Hidden (only admins can view)" />
|
||||
<x-forms.input disabled
|
||||
helper="Generate an API Token/Key in Pushover by creating a new application. <br><a class='inline-block underline dark:text-white' href='https://pushover.net/apps/build' target='_blank'>Create Pushover Application</a>"
|
||||
required label="API Token" value="Hidden (only admins can view)" />
|
||||
@endcan
|
||||
</div>
|
||||
</form>
|
||||
<h2 class="mt-4">Notification Settings</h2>
|
||||
|
||||
@@ -23,9 +23,15 @@
|
||||
<div class="w-32">
|
||||
<x-forms.checkbox canGate="update" :canResource="$settings" instantSave="instantSaveSlackEnabled" id="slackEnabled" label="Enabled" />
|
||||
</div>
|
||||
<x-forms.input canGate="update" :canResource="$settings" type="password"
|
||||
helper="Create a Slack APP and generate a Incoming Webhook URL. <br><a class='inline-block underline dark:text-white' href='https://api.slack.com/apps' target='_blank'>Create Slack APP</a>"
|
||||
required id="slackWebhookUrl" label="Webhook" />
|
||||
@can('update', $settings)
|
||||
<x-forms.input type="password"
|
||||
helper="Create a Slack APP and generate a Incoming Webhook URL. <br><a class='inline-block underline dark:text-white' href='https://api.slack.com/apps' target='_blank'>Create Slack APP</a>"
|
||||
required id="slackWebhookUrl" label="Webhook" />
|
||||
@else
|
||||
<x-forms.input disabled
|
||||
helper="Create a Slack APP and generate a Incoming Webhook URL. <br><a class='inline-block underline dark:text-white' href='https://api.slack.com/apps' target='_blank'>Create Slack APP</a>"
|
||||
required label="Webhook" value="Hidden (only admins can view)" />
|
||||
@endcan
|
||||
</form>
|
||||
<h2 class="mt-4">Notification Settings</h2>
|
||||
<p class="mb-4">
|
||||
|
||||
@@ -24,12 +24,21 @@
|
||||
<x-forms.checkbox canGate="update" :canResource="$settings" instantSave="instantSaveTelegramEnabled" id="telegramEnabled" label="Enabled" />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input canGate="update" :canResource="$settings" type="password" autocomplete="new-password"
|
||||
helper="Get it from the <a class='inline-block underline dark:text-white' href='https://t.me/botfather' target='_blank'>BotFather Bot</a> on Telegram."
|
||||
required id="telegramToken" label="Bot API Token" />
|
||||
<x-forms.input canGate="update" :canResource="$settings" type="password" autocomplete="new-password"
|
||||
helper="Add your bot to a group chat and add its Chat ID here." required id="telegramChatId"
|
||||
label="Chat ID" />
|
||||
@can('update', $settings)
|
||||
<x-forms.input type="password" autocomplete="new-password"
|
||||
helper="Get it from the <a class='inline-block underline dark:text-white' href='https://t.me/botfather' target='_blank'>BotFather Bot</a> on Telegram."
|
||||
required id="telegramToken" label="Bot API Token" />
|
||||
<x-forms.input type="password" autocomplete="new-password"
|
||||
helper="Add your bot to a group chat and add its Chat ID here." required id="telegramChatId"
|
||||
label="Chat ID" />
|
||||
@else
|
||||
<x-forms.input disabled autocomplete="new-password"
|
||||
helper="Get it from the <a class='inline-block underline dark:text-white' href='https://t.me/botfather' target='_blank'>BotFather Bot</a> on Telegram."
|
||||
required label="Bot API Token" value="Hidden (only admins can view)" />
|
||||
<x-forms.input disabled autocomplete="new-password"
|
||||
helper="Add your bot to a group chat and add its Chat ID here." required label="Chat ID"
|
||||
value="Hidden (only admins can view)" />
|
||||
@endcan
|
||||
</div>
|
||||
</form>
|
||||
<h2 class="mt-4">Notification Settings</h2>
|
||||
|
||||
@@ -28,9 +28,15 @@
|
||||
</div>
|
||||
<div class="flex items-end gap-2">
|
||||
|
||||
<x-forms.input canGate="update" :canResource="$settings" type="password"
|
||||
helper="Enter a valid HTTP or HTTPS URL. Coolify will send POST requests to this endpoint when events occur."
|
||||
required id="webhookUrl" label="Webhook URL (POST)" />
|
||||
@can('update', $settings)
|
||||
<x-forms.input type="password"
|
||||
helper="Enter a valid HTTP or HTTPS URL. Coolify will send POST requests to this endpoint when events occur."
|
||||
required id="webhookUrl" label="Webhook URL (POST)" />
|
||||
@else
|
||||
<x-forms.input disabled
|
||||
helper="Enter a valid HTTP or HTTPS URL. Coolify will send POST requests to this endpoint when events occur."
|
||||
required label="Webhook URL (POST)" value="Hidden (only admins can view)" />
|
||||
@endcan
|
||||
</div>
|
||||
</form>
|
||||
<h2 class="mt-4">Notification Settings</h2>
|
||||
|
||||
@@ -338,6 +338,7 @@
|
||||
class="block w-full px-4 py-2 text-left text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-coolgray-300">
|
||||
Download displayed logs
|
||||
</button>
|
||||
@can('update', $application)
|
||||
<button x-on:click="
|
||||
downloadingAllLogs = true;
|
||||
$wire.downloadAllLogs().then(logs => {
|
||||
@@ -368,6 +369,7 @@
|
||||
Downloading...
|
||||
</span>
|
||||
</button>
|
||||
@endcan
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -380,6 +382,7 @@
|
||||
d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
|
||||
</svg>
|
||||
</button>
|
||||
@can('update', $application)
|
||||
<button wire:click="toggleDebug"
|
||||
title="{{ $is_debug_enabled ? 'Hide Debug Logs' : 'Show Debug Logs' }}"
|
||||
class="p-1 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 {{ $is_debug_enabled ? '!text-warning' : '' }}">
|
||||
@@ -389,6 +392,7 @@
|
||||
d="M12 12.75c1.148 0 2.278.08 3.383.237 1.037.146 1.866.966 1.866 2.013 0 3.728-2.35 6.75-5.25 6.75S6.75 18.728 6.75 15c0-1.046.83-1.867 1.866-2.013A24.204 24.204 0 0 1 12 12.75Zm0 0c2.883 0 5.647.508 8.207 1.44a23.91 23.91 0 0 1-1.152 6.06M12 12.75c-2.883 0-5.647.508-8.208 1.44.125 2.104.52 4.136 1.153 6.06M12 12.75a2.25 2.25 0 0 0 2.248-2.354M12 12.75a2.25 2.25 0 0 1-2.248-2.354M12 8.25c.995 0 1.971-.08 2.922-.236.403-.066.74-.358.795-.762a3.778 3.778 0 0 0-.399-2.25M12 8.25c-.995 0-1.97-.08-2.922-.236-.402-.066-.74-.358-.795-.762a3.734 3.734 0 0 1 .4-2.253M12 8.25a2.25 2.25 0 0 0-2.248 2.146M12 8.25a2.25 2.25 0 0 1 2.248 2.146M8.683 5a6.032 6.032 0 0 1-1.155-1.002c.07-.63.27-1.222.574-1.747m.581 2.749A3.75 3.75 0 0 1 15.318 5m0 0c.427-.283.815-.62 1.155-.999a4.471 4.471 0 0 0-.575-1.752M4.921 6a24.048 24.048 0 0 0-.392 3.314c1.668.546 3.416.914 5.223 1.082M19.08 6c.205 1.08.337 2.187.392 3.314a23.882 23.882 0 0 1-5.223 1.082" />
|
||||
</svg>
|
||||
</button>
|
||||
@endcan
|
||||
<button title="Follow Logs" :class="alwaysScroll ? '!text-warning' : ''"
|
||||
x-on:click="toggleScroll"
|
||||
class="p-1 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200">
|
||||
|
||||
@@ -483,13 +483,14 @@
|
||||
<div class="flex flex-wrap gap-2">
|
||||
@if (!str($application->status)->startsWith('exited'))
|
||||
@if (!$application->destination->server->isSwarm())
|
||||
|
||||
<x-modal-confirmation title="Confirm Application Deployment?" buttonTitle="Redeploy"
|
||||
submitAction="deploy" :actions="[
|
||||
'This application will be redeployed.',
|
||||
]" :confirmWithText="false" :confirmWithPassword="false"
|
||||
step2ButtonText="Confirm">
|
||||
<x-slot:content>
|
||||
<x-forms.button title="With rolling update if possible">
|
||||
<x-forms.button canGate="deploy" :canResource="$application" title="With rolling update if possible">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 dark:text-orange-400"
|
||||
viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
|
||||
stroke-linecap="round" stroke-linejoin="round">
|
||||
@@ -512,7 +513,7 @@
|
||||
]" :confirmWithText="false" :confirmWithPassword="false"
|
||||
step2ButtonText="Confirm">
|
||||
<x-slot:content>
|
||||
<x-forms.button title="Redeploy Swarm Service (rolling update)">
|
||||
<x-forms.button canGate="deploy" :canResource="$application" title="Redeploy Swarm Service (rolling update)">
|
||||
<svg class="w-5 h-5 dark:text-warning" viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="none" stroke="currentColor" stroke-linecap="round"
|
||||
@@ -533,7 +534,7 @@
|
||||
]" :confirmWithText="false" :confirmWithPassword="false"
|
||||
step2ButtonText="Confirm">
|
||||
<x-slot:content>
|
||||
<x-forms.button title="Restart without rebuilding">
|
||||
<x-forms.button canGate="deploy" :canResource="$application" title="Restart without rebuilding">
|
||||
<svg class="w-5 h-5 dark:text-warning" viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="none" stroke="currentColor" stroke-linecap="round"
|
||||
@@ -547,9 +548,10 @@
|
||||
</x-forms.button>
|
||||
</x-slot:content>
|
||||
</x-modal-confirmation>
|
||||
|
||||
@endif
|
||||
@endif
|
||||
<x-modal-confirmation title="Confirm Application Stopping?" buttonTitle="Stop"
|
||||
<x-modal-confirmation :disabled="!auth()->user()->can('deploy', $application)" :authDisabled="!auth()->user()->can('deploy', $application)" title="Confirm Application Stopping?" buttonTitle="Stop"
|
||||
submitAction="stop" :checkboxes="$checkboxes" :actions="[
|
||||
'This application will be stopped.',
|
||||
'All non-persistent data of this application will be deleted.',
|
||||
@@ -571,13 +573,14 @@
|
||||
</x-slot:button-title>
|
||||
</x-modal-confirmation>
|
||||
@else
|
||||
|
||||
<x-modal-confirmation title="Confirm Application Deployment?" buttonTitle="Deploy"
|
||||
submitAction="deploy" :actions="[
|
||||
'This application will be deployed.',
|
||||
]" :confirmWithText="false" :confirmWithPassword="false"
|
||||
step2ButtonText="Confirm">
|
||||
<x-slot:content>
|
||||
<x-forms.button>
|
||||
<x-forms.button canGate="deploy" :canResource="$application">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 dark:text-warning"
|
||||
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
|
||||
stroke-linecap="round" stroke-linejoin="round">
|
||||
@@ -588,6 +591,7 @@
|
||||
</x-forms.button>
|
||||
</x-slot:content>
|
||||
</x-modal-confirmation>
|
||||
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,32 +1,40 @@
|
||||
<form wire:submit="submit">
|
||||
<div class="flex gap-2 pb-2">
|
||||
<div class="flex flex-col gap-3 pb-4 sm:flex-row sm:items-center">
|
||||
<h2>Scheduled Backup</h2>
|
||||
<x-forms.button type="submit">
|
||||
Save
|
||||
</x-forms.button>
|
||||
@if (str($status)->startsWith('running'))
|
||||
<livewire:project.database.backup-now :backup="$backup" />
|
||||
@endif
|
||||
@if ($backup->database_id !== 0)
|
||||
<x-modal-confirmation title="Confirm Backup Schedule Deletion?" buttonTitle="Delete Backups and Schedule"
|
||||
isErrorButton submitAction="delete" :checkboxes="$checkboxes" :actions="[
|
||||
'The selected backup schedule will be deleted.',
|
||||
'Scheduled backups for this database will be stopped (if this is the only backup schedule for this database).',
|
||||
]"
|
||||
confirmationText="{{ $backup->database->name }}"
|
||||
confirmationLabel="Please confirm the execution of the actions by entering the Database Name of the scheduled backups below"
|
||||
shortConfirmationLabel="Database Name" />
|
||||
@endif
|
||||
<div class="flex flex-col gap-2 sm:flex-row sm:flex-wrap">
|
||||
<x-forms.button type="submit" class="w-full sm:w-auto">
|
||||
Save
|
||||
</x-forms.button>
|
||||
@if (str($status)->startsWith('running'))
|
||||
<x-forms.button wire:click='backupNow' class="w-full sm:w-auto">Backup Now</x-forms.button>
|
||||
@endif
|
||||
@if ($backup->database_id !== 0)
|
||||
<div class="w-full sm:w-auto">
|
||||
<x-modal-confirmation title="Confirm Backup Schedule Deletion?" isErrorButton submitAction="delete"
|
||||
:checkboxes="$checkboxes" :actions="[
|
||||
'The selected backup schedule will be deleted.',
|
||||
'Scheduled backups for this database will be stopped (if this is the only backup schedule for this database).',
|
||||
]"
|
||||
confirmationText="{{ $backup->database->name }}"
|
||||
confirmationLabel="Please confirm the execution of the actions by entering the Database Name of the scheduled backups below"
|
||||
shortConfirmationLabel="Database Name">
|
||||
<x-slot:trigger>
|
||||
<x-forms.button isError class="w-full sm:w-auto">Delete Backups and Schedule</x-forms.button>
|
||||
</x-slot:trigger>
|
||||
</x-modal-confirmation>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-64 pb-2">
|
||||
<div class="w-full max-w-md pb-2">
|
||||
<x-forms.checkbox instantSave label="Backup Enabled" id="backupEnabled" />
|
||||
@if ($s3s->count() > 0)
|
||||
@if ($availableS3Storages->count() > 0)
|
||||
<x-forms.checkbox instantSave label="S3 Enabled" id="saveS3" />
|
||||
@else
|
||||
<x-forms.checkbox instantSave helper="No validated S3 storage available." label="S3 Enabled" id="saveS3"
|
||||
disabled />
|
||||
@endif
|
||||
@if ($backup->save_s3)
|
||||
@if ($saveS3)
|
||||
<x-forms.checkbox instantSave label="Disable Local Backup" id="disableLocalBackup"
|
||||
helper="When enabled, backup files will be deleted from local storage immediately after uploading to S3. This requires S3 backup to be enabled." />
|
||||
@else
|
||||
@@ -34,16 +42,27 @@
|
||||
helper="When enabled, backup files will be deleted from local storage immediately after uploading to S3. This requires S3 backup to be enabled." />
|
||||
@endif
|
||||
</div>
|
||||
@if ($backup->save_s3)
|
||||
<div class="pb-6">
|
||||
<x-forms.select id="s3StorageId" label="S3 Storage" required>
|
||||
<option value="default" disabled>Select a S3 storage</option>
|
||||
@foreach ($s3s as $s3)
|
||||
<div class="w-full max-w-md pb-6">
|
||||
<div class="flex gap-1 items-center mb-1 text-sm font-medium">
|
||||
<span>S3 Storage</span>
|
||||
@if (!$saveS3)
|
||||
<span class="text-xs font-normal text-warning">(currently disabled)</span>
|
||||
@endif
|
||||
@if ($saveS3)
|
||||
<x-highlighted text="*" />
|
||||
@endif
|
||||
</div>
|
||||
<x-forms.select id="s3StorageId" wire:model.live="s3StorageId" :required="$saveS3"
|
||||
:disabled="$availableS3Storages->isEmpty()">
|
||||
@if ($availableS3Storages->isEmpty())
|
||||
<option value="">No S3 storage available</option>
|
||||
@else
|
||||
@foreach ($availableS3Storages as $s3)
|
||||
<option value="{{ $s3->id }}">{{ $s3->name }}</option>
|
||||
@endforeach
|
||||
</x-forms.select>
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
</x-forms.select>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<h3>Settings</h3>
|
||||
<div class="flex gap-2 flex-col ">
|
||||
@@ -80,7 +99,7 @@
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<div class="grid grid-cols-1 gap-2 md:grid-cols-3">
|
||||
<x-forms.input label="Frequency" id="frequency" required />
|
||||
<x-forms.input label="Timezone" id="timezone" disabled
|
||||
helper="The timezone of the server where the backup is scheduled to run (if not set, the instance timezone will be used)" required />
|
||||
@@ -98,7 +117,7 @@
|
||||
<div class="flex gap-6 flex-col">
|
||||
<div>
|
||||
<h4 class="mb-3 font-medium">Local Backup Retention</h4>
|
||||
<div class="flex gap-2">
|
||||
<div class="grid grid-cols-1 gap-2 md:grid-cols-3">
|
||||
<x-forms.input label="Number of backups to keep" id="databaseBackupRetentionAmountLocally"
|
||||
type="number" min="0"
|
||||
helper="Keeps only the specified number of most recent backups on the server. Set to 0 for unlimited backups." required />
|
||||
@@ -111,10 +130,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($backup->save_s3)
|
||||
@if ($saveS3)
|
||||
<div>
|
||||
<h4 class="mb-3 font-medium">S3 Storage Retention</h4>
|
||||
<div class="flex gap-2">
|
||||
<div class="grid grid-cols-1 gap-2 md:grid-cols-3">
|
||||
<x-forms.input label="Number of backups to keep" id="databaseBackupRetentionAmountS3"
|
||||
type="number" min="0"
|
||||
helper="Keeps only the specified number of most recent backups on S3 storage. Set to 0 for unlimited backups." required />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div wire:init='refreshBackupExecutions'>
|
||||
@isset($backup)
|
||||
<div class="flex items-center gap-2">
|
||||
<h3 class="py-4">Executions <span class="text-xs">({{ $executions_count }})</span></h3>
|
||||
<div class="flex flex-col gap-3 py-4 sm:flex-row sm:flex-wrap sm:items-center">
|
||||
<h3 class="py-0">Executions <span class="text-xs">({{ $executions_count }})</span></h3>
|
||||
@if ($executions_count > 0)
|
||||
<div class="flex items-center gap-2">
|
||||
<x-forms.button disabled="{{ !$showPrev }}" wire:click="previousPage('{{ $defaultTake }}')">
|
||||
@@ -21,13 +21,19 @@
|
||||
</x-forms.button>
|
||||
</div>
|
||||
@endif
|
||||
<x-forms.button wire:click='cleanupFailed'>Cleanup Failed Backups</x-forms.button>
|
||||
<x-modal-confirmation title="Cleanup Deleted Backup Entries?" buttonTitle="Cleanup Deleted" isErrorButton
|
||||
submitAction="cleanupDeleted()"
|
||||
:actions="['This will permanently delete all backup execution entries that are marked as deleted from local storage.', 'This only removes database entries, not actual backup files.']"
|
||||
confirmationText="cleanup deleted backups"
|
||||
confirmationLabel="Please confirm by typing 'cleanup deleted backups' below"
|
||||
shortConfirmationLabel="Confirmation" />
|
||||
<div class="flex flex-col gap-2 sm:flex-row sm:flex-wrap">
|
||||
<x-forms.button wire:click='cleanupFailed' class="w-full sm:w-auto">Cleanup Failed Backups</x-forms.button>
|
||||
<x-modal-confirmation title="Cleanup Deleted Backup Entries?" isErrorButton
|
||||
submitAction="cleanupDeleted()"
|
||||
:actions="['This will permanently delete all backup execution entries that are marked as deleted from local storage.', 'This only removes database entries, not actual backup files.']"
|
||||
confirmationText="cleanup deleted backups"
|
||||
confirmationLabel="Please confirm by typing 'cleanup deleted backups' below"
|
||||
shortConfirmationLabel="Confirmation">
|
||||
<x-slot:trigger>
|
||||
<x-forms.button isError class="w-full sm:w-auto">Cleanup Deleted</x-forms.button>
|
||||
</x-slot:trigger>
|
||||
</x-modal-confirmation>
|
||||
</div>
|
||||
</div>
|
||||
<div @if (!$skip) wire:poll.5000ms="refreshBackupExecutions" @endif
|
||||
class="flex flex-col gap-4">
|
||||
@@ -87,7 +93,7 @@
|
||||
<div class="text-gray-600 dark:text-gray-400 text-sm">
|
||||
Location: {{ data_get($execution, 'filename', 'N/A') }}
|
||||
</div>
|
||||
<div class="flex items-center gap-3 mt-2">
|
||||
<div class="flex flex-col gap-2 mt-2 sm:flex-row sm:flex-wrap sm:items-center sm:gap-3">
|
||||
<div class="text-gray-600 dark:text-gray-400 text-sm">
|
||||
Backup Availability:
|
||||
</div>
|
||||
@@ -154,9 +160,9 @@
|
||||
<pre class="whitespace-pre-wrap text-sm">{{ data_get($execution, 'message') }}</pre>
|
||||
</div>
|
||||
@endif
|
||||
<div class="flex gap-2 mt-4">
|
||||
<div class="grid grid-cols-2 gap-2 mt-4 sm:flex sm:flex-wrap">
|
||||
@if (data_get($execution, 'status') === 'success')
|
||||
<x-forms.button class="dark:hover:bg-coolgray-400"
|
||||
<x-forms.button class="w-full dark:hover:bg-coolgray-400 sm:w-auto"
|
||||
x-on:click="download_file('{{ data_get($execution, 'id') }}')">Download</x-forms.button>
|
||||
@endif
|
||||
@php
|
||||
@@ -175,11 +181,15 @@
|
||||
$deleteActions[] = 'This backup execution record will be deleted.';
|
||||
}
|
||||
@endphp
|
||||
<x-modal-confirmation title="Confirm Backup Deletion?" buttonTitle="Delete" isErrorButton
|
||||
<x-modal-confirmation title="Confirm Backup Deletion?" isErrorButton
|
||||
submitAction="deleteBackup({{ data_get($execution, 'id') }})" :checkboxes="$executionCheckboxes"
|
||||
:actions="$deleteActions" confirmationText="{{ data_get($execution, 'filename') }}"
|
||||
confirmationLabel="Please confirm the execution of the actions by entering the Backup Filename below"
|
||||
shortConfirmationLabel="Backup Filename" 1 />
|
||||
shortConfirmationLabel="Backup Filename">
|
||||
<x-slot:trigger>
|
||||
<x-forms.button isError class="w-full sm:w-auto">Delete</x-forms.button>
|
||||
</x-slot:trigger>
|
||||
</x-modal-confirmation>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<livewire:project.shared.configuration-checker :resource="$database" />
|
||||
<livewire:project.database.heading :database="$database" />
|
||||
<div>
|
||||
<livewire:project.database.backup-edit :backup="$backup" :s3s="$s3s" :status="data_get($database, 'status')" />
|
||||
<livewire:project.database.backup-edit :backup="$backup" :available-s3-storages="$s3s" :status="data_get($database, 'status')" />
|
||||
<livewire:project.database.backup-executions :backup="$backup" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -20,8 +20,12 @@
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input label="Initial Username" id="clickhouseAdminUser" placeholder="If empty: clickhouse"
|
||||
readonly helper="You can only change this in the database." canGate="update" :canResource="$database" />
|
||||
<x-forms.input label="Initial Password" id="clickhouseAdminPassword" type="password" required readonly
|
||||
helper="You can only change this in the database." canGate="update" :canResource="$database" />
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input label="Initial Password" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input label="Initial Password" id="clickhouseAdminPassword" type="password" required readonly
|
||||
helper="You can only change this in the database." canGate="update" :canResource="$database" />
|
||||
@endif
|
||||
</div>
|
||||
@else
|
||||
<div class=" dark:text-warning">Please verify these values. You can only modify them before the initial
|
||||
@@ -29,8 +33,12 @@
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input label="Username" id="clickhouseAdminUser" required canGate="update" :canResource="$database" />
|
||||
<x-forms.input label="Password" id="clickhouseAdminPassword" type="password" required canGate="update"
|
||||
:canResource="$database" />
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input label="Password" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input label="Password" id="clickhouseAdminPassword" type="password" required canGate="update"
|
||||
:canResource="$database" />
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
<x-forms.input
|
||||
|
||||
@@ -21,16 +21,24 @@
|
||||
|
||||
@if ($database->started_at)
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input label="Initial Password" id="dragonflyPassword" type="password" required readonly
|
||||
helper="You can only change this in the database." canGate="update" :canResource="$database" />
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input label="Initial Password" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input label="Initial Password" id="dragonflyPassword" type="password" required readonly
|
||||
helper="You can only change this in the database." canGate="update" :canResource="$database" />
|
||||
@endif
|
||||
</div>
|
||||
@else
|
||||
<div class=" dark:text-warning">Please verify these values. You can only modify them before the initial
|
||||
start. After that, you need to modify it in the database.
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input label="Password" id="dragonflyPassword" type="password" required canGate="update"
|
||||
:canResource="$database" />
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input label="Password" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input label="Password" id="dragonflyPassword" type="password" required canGate="update"
|
||||
:canResource="$database" />
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
<div class="flex flex-col gap-2">
|
||||
|
||||
@@ -216,7 +216,8 @@
|
||||
<div class="flex flex-wrap gap-2 items-center">
|
||||
<div class="hidden flex-wrap items-center gap-2 md:flex">
|
||||
@if (!str($database->status)->startsWith('exited'))
|
||||
<x-forms.button title="Restart" @click="document.getElementById('database-restart-trigger')?.click()">
|
||||
|
||||
<x-forms.button canGate="manage" :canResource="$database" title="Restart" @click="document.getElementById('database-restart-trigger')?.click()">
|
||||
<svg class="w-5 h-5 dark:text-warning" viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||
@@ -227,7 +228,7 @@
|
||||
</svg>
|
||||
Restart
|
||||
</x-forms.button>
|
||||
<x-forms.button isError title="Stop" @click="document.getElementById('database-stop-trigger')?.click()">
|
||||
<x-forms.button canGate="manage" :canResource="$database" isError title="Stop" @click="document.getElementById('database-stop-trigger')?.click()">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-error" viewBox="0 0 24 24"
|
||||
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
@@ -241,7 +242,8 @@
|
||||
Stop
|
||||
</x-forms.button>
|
||||
@else
|
||||
<button @click="document.getElementById('database-start-trigger')?.click()" class="gap-2 button">
|
||||
<x-forms.button canGate="manage" :canResource="$database" @click="document.getElementById('database-start-trigger')?.click()" class="gap-2">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 dark:text-warning" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
@@ -249,7 +251,7 @@
|
||||
<path d="M7 4v16l13 -8z" />
|
||||
</svg>
|
||||
Start
|
||||
</button>
|
||||
</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
@script
|
||||
|
||||
@@ -18,16 +18,24 @@
|
||||
|
||||
@if ($database->started_at)
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input label="Initial Password" id="keydbPassword" type="password" required readonly
|
||||
helper="You can only change this in the database." canGate="update" :canResource="$database" />
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input label="Initial Password" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input label="Initial Password" id="keydbPassword" type="password" required readonly
|
||||
helper="You can only change this in the database." canGate="update" :canResource="$database" />
|
||||
@endif
|
||||
</div>
|
||||
@else
|
||||
<div class=" dark:text-warning">Please verify these values. You can only modify them before the initial
|
||||
start. After that, you need to modify it in the database.
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input label="Password" id="keydbPassword" type="password" required canGate="update"
|
||||
:canResource="$database" />
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input label="Password" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input label="Password" id="keydbPassword" type="password" required canGate="update"
|
||||
:canResource="$database" />
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
<x-forms.input
|
||||
|
||||
@@ -20,15 +20,23 @@
|
||||
</div>
|
||||
@if ($database->started_at)
|
||||
<div class="flex xl:flex-row flex-col gap-2">
|
||||
<x-forms.input label="Root Password" id="mariadbRootPassword" type="password" required
|
||||
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work."
|
||||
canGate="update" :canResource="$database" />
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input label="Root Password" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input label="Root Password" id="mariadbRootPassword" type="password" required
|
||||
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work."
|
||||
canGate="update" :canResource="$database" />
|
||||
@endif
|
||||
<x-forms.input label="Normal User" id="mariadbUser" required
|
||||
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work."
|
||||
canGate="update" :canResource="$database" />
|
||||
<x-forms.input label="Normal User Password" id="mariadbPassword" type="password" required
|
||||
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work."
|
||||
canGate="update" :canResource="$database" />
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input label="Normal User Password" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input label="Normal User Password" id="mariadbPassword" type="password" required
|
||||
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work."
|
||||
canGate="update" :canResource="$database" />
|
||||
@endif
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<x-forms.input label="Initial Database" id="mariadbDatabase"
|
||||
@@ -37,12 +45,20 @@
|
||||
</div>
|
||||
@else
|
||||
<div class="flex xl:flex-row flex-col gap-2 pb-2">
|
||||
<x-forms.input label="Root Password" id="mariadbRootPassword" type="password"
|
||||
helper="You can only change this in the database." canGate="update" :canResource="$database" />
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input label="Root Password" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input label="Root Password" id="mariadbRootPassword" type="password"
|
||||
helper="You can only change this in the database." canGate="update" :canResource="$database" />
|
||||
@endif
|
||||
<x-forms.input label="Normal User" id="mariadbUser" required
|
||||
helper="You can only change this in the database." canGate="update" :canResource="$database" />
|
||||
<x-forms.input label="Normal User Password" id="mariadbPassword" type="password" required
|
||||
helper="You can only change this in the database." canGate="update" :canResource="$database" />
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input label="Normal User Password" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input label="Normal User Password" id="mariadbPassword" type="password" required
|
||||
helper="You can only change this in the database." canGate="update" :canResource="$database" />
|
||||
@endif
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<x-forms.input label="Initial Database" id="mariadbDatabase"
|
||||
|
||||
@@ -24,10 +24,14 @@
|
||||
placeholder="If empty: postgres"
|
||||
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work."
|
||||
canGate="update" :canResource="$database" />
|
||||
<x-forms.input label="Initial Password" id="mongoInitdbRootPassword" type="password"
|
||||
required
|
||||
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work."
|
||||
canGate="update" :canResource="$database" />
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input label="Initial Password" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input label="Initial Password" id="mongoInitdbRootPassword" type="password"
|
||||
required
|
||||
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work."
|
||||
canGate="update" :canResource="$database" />
|
||||
@endif
|
||||
<x-forms.input label="Initial Database" id="mongoInitdbDatabase"
|
||||
placeholder="If empty, it will be the same as Username." readonly
|
||||
helper="You can only change this in the database." canGate="update" :canResource="$database" />
|
||||
@@ -36,8 +40,12 @@
|
||||
<div class="flex xl:flex-row flex-col gap-2 pb-2">
|
||||
<x-forms.input required label="Username" id="mongoInitdbRootUsername"
|
||||
placeholder="If empty: postgres" canGate="update" :canResource="$database" />
|
||||
<x-forms.input label="Password" id="mongoInitdbRootPassword" type="password" required
|
||||
canGate="update" :canResource="$database" />
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input label="Password" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input label="Password" id="mongoInitdbRootPassword" type="password" required
|
||||
canGate="update" :canResource="$database" />
|
||||
@endif
|
||||
<x-forms.input required label="Database" id="mongoInitdbDatabase"
|
||||
placeholder="If empty, it will be the same as Username." canGate="update" :canResource="$database" />
|
||||
</div>
|
||||
|
||||
@@ -20,12 +20,20 @@
|
||||
</div>
|
||||
@if ($database->started_at)
|
||||
<div class="flex xl:flex-row flex-col gap-2">
|
||||
<x-forms.input label="Root Password" id="mysqlRootPassword" type="password" required
|
||||
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." canGate="update" :canResource="$database" />
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input label="Root Password" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input label="Root Password" id="mysqlRootPassword" type="password" required
|
||||
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." canGate="update" :canResource="$database" />
|
||||
@endif
|
||||
<x-forms.input label="Normal User" id="mysqlUser" required
|
||||
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." canGate="update" :canResource="$database" />
|
||||
<x-forms.input label="Normal User Password" id="mysqlPassword" type="password" required
|
||||
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." canGate="update" :canResource="$database" />
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input label="Normal User Password" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input label="Normal User Password" id="mysqlPassword" type="password" required
|
||||
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." canGate="update" :canResource="$database" />
|
||||
@endif
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<x-forms.input label="Initial Database" id="mysqlDatabase"
|
||||
@@ -34,12 +42,20 @@
|
||||
</div>
|
||||
@else
|
||||
<div class="flex xl:flex-row flex-col gap-4 pb-2">
|
||||
<x-forms.input label="Root Password" id="mysqlRootPassword" type="password"
|
||||
helper="You can only change this in the database." canGate="update" :canResource="$database" />
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input label="Root Password" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input label="Root Password" id="mysqlRootPassword" type="password"
|
||||
helper="You can only change this in the database." canGate="update" :canResource="$database" />
|
||||
@endif
|
||||
<x-forms.input label="Normal User" id="mysqlUser" required
|
||||
helper="You can only change this in the database." canGate="update" :canResource="$database" />
|
||||
<x-forms.input label="Normal User Password" id="mysqlPassword" type="password" required
|
||||
helper="You can only change this in the database." canGate="update" :canResource="$database" />
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input label="Normal User Password" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input label="Normal User Password" id="mysqlPassword" type="password" required
|
||||
helper="You can only change this in the database." canGate="update" :canResource="$database" />
|
||||
@endif
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<x-forms.input label="Initial Database" id="mysqlDatabase"
|
||||
|
||||
@@ -37,9 +37,13 @@
|
||||
<x-forms.input label="Username" id="postgresUser" placeholder="If empty: postgres" canGate="update"
|
||||
:canResource="$database"
|
||||
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." />
|
||||
<x-forms.input label="Password" id="postgresPassword" type="password" required canGate="update"
|
||||
:canResource="$database"
|
||||
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." />
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input label="Password" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input label="Password" id="postgresPassword" type="password" required canGate="update"
|
||||
:canResource="$database"
|
||||
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." />
|
||||
@endif
|
||||
<x-forms.input label="Initial Database" id="postgresDb"
|
||||
placeholder="If empty, it will be the same as Username." readonly
|
||||
helper="You can only change this in the database." />
|
||||
@@ -48,8 +52,12 @@
|
||||
<div class="flex xl:flex-row flex-col gap-2 pb-2">
|
||||
<x-forms.input label="Username" id="postgresUser" placeholder="If empty: postgres" canGate="update"
|
||||
:canResource="$database" />
|
||||
<x-forms.input label="Password" id="postgresPassword" type="password" required canGate="update"
|
||||
:canResource="$database" />
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input label="Password" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input label="Password" id="postgresPassword" type="password" required canGate="update"
|
||||
:canResource="$database" />
|
||||
@endif
|
||||
<x-forms.input label="Initial Database" id="postgresDb"
|
||||
placeholder="If empty, it will be the same as Username." canGate="update" :canResource="$database" />
|
||||
</div>
|
||||
@@ -134,7 +142,8 @@
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
@forelse($initScripts ?? [] as $script)
|
||||
<livewire:project.database.init-script :script="$script" :wire:key="$script['index']" />
|
||||
<livewire:project.database.init-script :database="$database" :script="$script"
|
||||
:wire:key="$script['index']" />
|
||||
@empty
|
||||
<div>No initialization scripts found.</div>
|
||||
@endforelse
|
||||
|
||||
@@ -26,8 +26,12 @@
|
||||
<x-forms.input label="Username" id="redisUsername"
|
||||
helper="You can only change this in the database." canGate="update" :canResource="$database" />
|
||||
@endif
|
||||
<x-forms.input label="Password" id="redisPassword" type="password"
|
||||
helper="You can only change this in the database." canGate="update" :canResource="$database" />
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input label="Password" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input label="Password" id="redisPassword" type="password"
|
||||
helper="You can only change this in the database." canGate="update" :canResource="$database" />
|
||||
@endif
|
||||
</div>
|
||||
@else
|
||||
<div class="pt-2 dark:text-warning">You can only change the username and password in the database after
|
||||
@@ -42,13 +46,17 @@
|
||||
Note: If the environment variable REDIS_USERNAME is set as a shared variable (environment, project, or team-based), this input field will become read-only."
|
||||
:disabled="$this->isSharedVariable('REDIS_USERNAME')" canGate="update" :canResource="$database" />
|
||||
@endif
|
||||
<x-forms.input label="Password" id="redisPassword" type="password" required
|
||||
helper="You can change the Redis Password in the input field below or by editing the value of the REDIS_PASSWORD environment variable.
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input label="Password" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input label="Password" id="redisPassword" type="password" required
|
||||
helper="You can change the Redis Password in the input field below or by editing the value of the REDIS_PASSWORD environment variable.
|
||||
<br><br>
|
||||
If you change the Redis Password in the database, please sync it here, otherwise automations (like backups) won't work.
|
||||
<br><br>
|
||||
Note: If the environment variable REDIS_PASSWORD is set as a shared variable (environment, project, or team-based), this input field will become read-only."
|
||||
:disabled="$this->isSharedVariable('REDIS_PASSWORD')" canGate="update" :canResource="$database" />
|
||||
:disabled="$this->isSharedVariable('REDIS_PASSWORD')" canGate="update" :canResource="$database" />
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@@ -216,7 +216,7 @@
|
||||
@if ($type === 'service-database' && $selectedBackup)
|
||||
<div class="pt-10">
|
||||
<livewire:project.database.backup-edit wire:key="{{ $selectedBackup->id }}" :backup="$selectedBackup"
|
||||
:s3s="$s3s" :status="data_get($database, 'status')" />
|
||||
:available-s3-storages="$s3s" :status="data_get($database, 'status')" />
|
||||
<livewire:project.database.backup-executions wire:key="{{ $selectedBackup->uuid }}" :backup="$selectedBackup"
|
||||
:database="$database" />
|
||||
</div>
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
<x-database-status-info :database="$database" :label="$label" :db-url="$dbUrl" :db-url-public="$dbUrlPublic"
|
||||
:enable-ssl="$enableSsl" :ssl-mode="$sslMode" :certificate-valid-until="$certificateValidUntil"
|
||||
:supports-ssl="$supportsSsl" :ssl-mode-options="$sslModeOptions" :ssl-mode-helper="$sslModeHelper"
|
||||
:show-public-url-placeholder="$showPublicUrlPlaceholder" :is-exited="$isExited" />
|
||||
:show-public-url-placeholder="$showPublicUrlPlaceholder" :is-exited="$isExited"
|
||||
:is-password-hidden-for-member="$isPasswordHiddenForMember" />
|
||||
</div>
|
||||
@@ -154,7 +154,7 @@
|
||||
|
||||
<div class="grid justify-start grid-cols-1 gap-4 text-left xl:grid-cols-3">
|
||||
<template x-for="service in filteredServices" :key="service.name">
|
||||
<div class="relative" x-on:click="setType('one-click-service-' + service.name)"
|
||||
<div class="relative" x-on:click="setType('one-click-service-' + service.id)"
|
||||
:class="{ 'cursor-pointer': !selecting, 'cursor-not-allowed opacity-50': selecting }">
|
||||
<x-resource-view>
|
||||
<x-slot:title>
|
||||
@@ -214,7 +214,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="shouldShowDocIcon(service)">
|
||||
<a :href="getDocLink(service) || coolifyDocsUrl(service.name)" target="_blank"
|
||||
<a :href="getDocLink(service) || coolifyDocsUrl(service)" target="_blank"
|
||||
@click.stop @mouseenter="resolveDocLink(service)"
|
||||
class="absolute top-2 right-2 p-1.5 rounded hover:bg-neutral-200 dark:hover:bg-coolgray-300 transition-colors"
|
||||
:class="{ 'opacity-50': docCheckInProgress[service.name] }"
|
||||
@@ -287,8 +287,8 @@
|
||||
// Remove flavor suffixes: -with-*, -without-*
|
||||
return normalized.replace(/-(with|without)-.+$/, '');
|
||||
},
|
||||
coolifyDocsUrl(serviceName) {
|
||||
const baseName = this.extractBaseServiceName(serviceName);
|
||||
coolifyDocsUrl(service) {
|
||||
const baseName = service.docsSlug || this.extractBaseServiceName(service.name);
|
||||
return 'https://coolify.io/docs/services/' + baseName;
|
||||
},
|
||||
officialDocsUrl(service) {
|
||||
@@ -322,7 +322,7 @@
|
||||
this.docCheckInProgress[serviceName] = true;
|
||||
|
||||
// 1. Try Coolify docs first
|
||||
const coolifyUrl = this.coolifyDocsUrl(serviceName);
|
||||
const coolifyUrl = this.coolifyDocsUrl(service);
|
||||
const coolifyExists = await this.checkUrlExists(coolifyUrl);
|
||||
|
||||
if (coolifyExists) {
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
<div class="w-full p-2 text-sm rounded bg-warning/10 text-warning">
|
||||
File on server exceeds 5 MB and cannot be edited from the UI. Edit it directly on the server.
|
||||
</div>
|
||||
@elseif ($fileStorage->is_host_file)
|
||||
<div class="w-full p-2 text-sm rounded bg-warning/10 text-warning">
|
||||
This host file mount is bind-only. Coolify will not create, edit, load, chmod, or delete the source file.
|
||||
</div>
|
||||
@elseif ($isReadOnly)
|
||||
<div class="w-full p-2 text-sm rounded bg-warning/10 text-warning">
|
||||
@if ($fileStorage->is_directory)
|
||||
@@ -32,7 +36,14 @@
|
||||
@if (!$isReadOnly)
|
||||
@can('update', $resource)
|
||||
<div class="flex gap-2">
|
||||
@if ($fileStorage->is_directory)
|
||||
@if ($fileStorage->is_host_file)
|
||||
<x-modal-confirmation :ignoreWire="false" title="Confirm Host File Mount Removal?"
|
||||
buttonTitle="Delete" isErrorButton submitAction="delete" :checkboxes="$hostFileDeletionCheckboxes"
|
||||
:actions="['Only the mount configuration will be removed. The host file will not be deleted.']"
|
||||
confirmationText="{{ $fs_path }}"
|
||||
confirmationLabel="Please confirm the execution of the actions by entering the Filepath below"
|
||||
shortConfirmationLabel="Filepath" />
|
||||
@elseif ($fileStorage->is_directory)
|
||||
<x-modal-confirmation :ignoreWire="false" title="Confirm Directory Conversion to File?"
|
||||
buttonTitle="Convert to file" submitAction="convertToFile" :actions="[
|
||||
'All files in this directory will be permanently deleted and an empty file will be created in its place.',
|
||||
@@ -68,7 +79,7 @@
|
||||
@endif
|
||||
</div>
|
||||
@endcan
|
||||
@if (!$fileStorage->is_directory)
|
||||
@if (!$fileStorage->is_directory && !$fileStorage->is_host_file)
|
||||
@can('update', $resource)
|
||||
@if (data_get($resource, 'settings.is_preserve_repository_enabled'))
|
||||
<div class="w-full sm:w-96">
|
||||
@@ -99,8 +110,8 @@
|
||||
@endif
|
||||
@else
|
||||
{{-- Read-only view --}}
|
||||
@if (!$fileStorage->is_directory)
|
||||
@can('view', $resource)
|
||||
@if (!$fileStorage->is_directory && !$fileStorage->is_host_file)
|
||||
@can('update', $resource)
|
||||
<div class="flex gap-2">
|
||||
<x-forms.button type="button" wire:click="loadStorageOnServer">Load from
|
||||
server</x-forms.button>
|
||||
|
||||
@@ -369,7 +369,9 @@
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<x-services.advanced :service="$service" />
|
||||
@if (str($service->status)->contains('running'))
|
||||
<x-forms.button title="Restart" @click="document.getElementById('service-restart-trigger')?.click()">
|
||||
|
||||
<x-forms.button canGate="deploy" :canResource="$service" title="Restart" @click="document.getElementById('service-restart-trigger')?.click()">
|
||||
|
||||
<svg class="w-5 h-5 dark:text-warning" 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">
|
||||
@@ -379,7 +381,8 @@
|
||||
</svg>
|
||||
Restart
|
||||
</x-forms.button>
|
||||
<x-forms.button isError title="Stop" @click="document.getElementById('service-stop-trigger')?.click()">
|
||||
|
||||
<x-forms.button canGate="stop" :canResource="$service" isError title="Stop" @click="document.getElementById('service-stop-trigger')?.click()">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-error" viewBox="0 0 24 24"
|
||||
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
@@ -393,7 +396,8 @@
|
||||
Stop
|
||||
</x-forms.button>
|
||||
@elseif (str($service->status)->contains('degraded'))
|
||||
<x-forms.button title="Restart" @click="document.getElementById('service-restart-trigger')?.click()">
|
||||
<x-forms.button canGate="deploy" :canResource="$service" title="Restart" @click="document.getElementById('service-restart-trigger')?.click()">
|
||||
|
||||
<svg class="w-5 h-5 dark:text-warning" 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">
|
||||
@@ -403,7 +407,8 @@
|
||||
</svg>
|
||||
Restart
|
||||
</x-forms.button>
|
||||
<x-forms.button isError title="Stop" @click="document.getElementById('service-stop-trigger')?.click()">
|
||||
|
||||
<x-forms.button canGate="stop" :canResource="$service" isError title="Stop" @click="document.getElementById('service-stop-trigger')?.click()">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-error" viewBox="0 0 24 24"
|
||||
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
@@ -417,7 +422,8 @@
|
||||
Stop
|
||||
</x-forms.button>
|
||||
@elseif (str($service->status)->contains('exited'))
|
||||
<button @click="document.getElementById('service-start-trigger')?.click()" class="gap-2 button">
|
||||
<x-forms.button canGate="deploy" :canResource="$service" @click="document.getElementById('service-start-trigger')?.click()" class="gap-2">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 dark:text-warning" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
@@ -425,9 +431,10 @@
|
||||
<path d="M7 4v16l13 -8z" />
|
||||
</svg>
|
||||
Deploy
|
||||
</button>
|
||||
</x-forms.button>
|
||||
@else
|
||||
<x-forms.button isError title="Stop" @click="document.getElementById('service-stop-trigger')?.click()">
|
||||
|
||||
<x-forms.button canGate="stop" :canResource="$service" isError title="Stop" @click="document.getElementById('service-stop-trigger')?.click()">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-error" viewBox="0 0 24 24"
|
||||
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
@@ -440,7 +447,8 @@
|
||||
</svg>
|
||||
Stop
|
||||
</x-forms.button>
|
||||
<button @click="document.getElementById('service-start-trigger')?.click()" class="gap-2 button">
|
||||
<x-forms.button canGate="deploy" :canResource="$service" @click="document.getElementById('service-start-trigger')?.click()" class="gap-2">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 dark:text-warning" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
@@ -448,7 +456,7 @@
|
||||
<path d="M7 4v16l13 -8z" />
|
||||
</svg>
|
||||
Deploy
|
||||
</button>
|
||||
</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@@ -522,11 +530,9 @@
|
||||
);
|
||||
return;
|
||||
}
|
||||
window.dispatchEvent(new CustomEvent('startservice'));
|
||||
$wire.$call('start');
|
||||
});
|
||||
$wire.$on('forceDeployEvent', () => {
|
||||
window.dispatchEvent(new CustomEvent('startservice'));
|
||||
$wire.$call('forceDeploy');
|
||||
});
|
||||
$wire.$on('restartEvent', async () => {
|
||||
@@ -539,12 +545,10 @@
|
||||
}
|
||||
$wire.$dispatch('info',
|
||||
'Gracefully stopping service.<br/><br/>It could take a while depending on the service.');
|
||||
window.dispatchEvent(new CustomEvent('startservice'));
|
||||
$wire.$call('restart');
|
||||
});
|
||||
$wire.$on('pullAndRestartEvent', () => {
|
||||
$wire.$dispatch('info', 'Pulling new images and restarting service.');
|
||||
window.dispatchEvent(new CustomEvent('startservice'));
|
||||
$wire.$call('pullAndRestartEvent');
|
||||
});
|
||||
$wire.$on('cleanupEvent', () => {
|
||||
|
||||
@@ -45,10 +45,14 @@
|
||||
<x-helper helper="Variable name: {{ $serviceName }}" />
|
||||
@endif
|
||||
</div>
|
||||
<x-forms.input canGate="update" :canResource="$service"
|
||||
type="{{ data_get($field, 'isPassword') ? 'password' : 'text' }}"
|
||||
required="{{ str(data_get($field, 'rules'))?->contains('required') }}"
|
||||
id="fields.{{ $serviceName }}.value"></x-forms.input>
|
||||
@if ($isPasswordHiddenForMember && data_get($field, 'isPassword'))
|
||||
<x-forms.input disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input canGate="update" :canResource="$service"
|
||||
type="{{ data_get($field, 'isPassword') ? 'password' : 'text' }}"
|
||||
required="{{ str(data_get($field, 'rules'))?->contains('required') }}"
|
||||
id="fields.{{ $serviceName }}.value"></x-forms.input>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@@ -22,11 +22,13 @@
|
||||
dropdownOpen: false,
|
||||
volumeModalOpen: false,
|
||||
fileModalOpen: false,
|
||||
hostFileModalOpen: false,
|
||||
directoryModalOpen: false
|
||||
}"
|
||||
@close-storage-modal.window="
|
||||
if ($event.detail === 'volume') volumeModalOpen = false;
|
||||
if ($event.detail === 'file') fileModalOpen = false;
|
||||
if ($event.detail === 'host-file') hostFileModalOpen = false;
|
||||
if ($event.detail === 'directory') directoryModalOpen = false;
|
||||
">
|
||||
<div class="relative" @click.outside="dropdownOpen = false">
|
||||
@@ -62,6 +64,15 @@
|
||||
</svg>
|
||||
File Mount
|
||||
</a>
|
||||
<a class="dropdown-item"
|
||||
@click="hostFileModalOpen = true; dropdownOpen = false">
|
||||
<svg class="size-4" fill="none" stroke="currentColor"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" />
|
||||
</svg>
|
||||
Host File Mount
|
||||
</a>
|
||||
<a class="dropdown-item"
|
||||
@click="directoryModalOpen = true; dropdownOpen = false">
|
||||
<svg class="size-4" fill="none" stroke="currentColor"
|
||||
@@ -188,14 +199,28 @@
|
||||
}
|
||||
})">
|
||||
<form class="flex flex-col w-full gap-2 rounded-sm"
|
||||
x-data="{
|
||||
hostPath: @js($this->fileStorageHostPath()),
|
||||
filePath: @entangle('file_storage_path'),
|
||||
previewPath() {
|
||||
const path = (this.filePath || '').trim();
|
||||
|
||||
return this.hostPath + (path === '' ? '/' : (path.startsWith('/') ? path : `/${path}`));
|
||||
},
|
||||
}"
|
||||
wire:submit='submitFileStorage'>
|
||||
<div class="flex flex-col">
|
||||
<div>Actual file mounted from the host system to the container.</div>
|
||||
<div>This file will be created on the host, then mounted into the container.</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="p-2 text-xs rounded-sm bg-neutral-100 dark:bg-coolgray-200">
|
||||
<div class="mb-1 font-medium">Host file path</div>
|
||||
<code class="break-all" x-text="previewPath()">{{ $this->fileStoragePreviewPath() }}</code>
|
||||
</div>
|
||||
<x-forms.input canGate="update" :canResource="$resource"
|
||||
placeholder="/etc/nginx/nginx.conf" id="file_storage_path"
|
||||
label="Destination Path" required
|
||||
x-on:input="filePath = $event.target.value"
|
||||
helper="File location inside the container" />
|
||||
<x-forms.textarea canGate="update" :canResource="$resource" label="Content"
|
||||
id="file_storage_content"></x-forms.textarea>
|
||||
@@ -209,6 +234,67 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
{{-- Host File Modal --}}
|
||||
<template x-teleport="body">
|
||||
<div x-show="hostFileModalOpen" @keydown.window.escape="hostFileModalOpen=false"
|
||||
class="fixed top-0 left-0 lg:px-0 px-4 z-99 flex items-center justify-center w-screen h-screen">
|
||||
<div x-show="hostFileModalOpen" 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="hostFileModalOpen=false"
|
||||
class="absolute inset-0 w-full h-full bg-black/20 backdrop-blur-xs"></div>
|
||||
<div x-show="hostFileModalOpen" x-trap.inert.noscroll="hostFileModalOpen"
|
||||
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-sm drop-shadow-sm min-w-full lg:min-w-[36rem] max-w-fit bg-white border-neutral-200 dark:bg-base px-6 dark:border-coolgray-300">
|
||||
<div class="flex items-center justify-between pb-3">
|
||||
<h3 class="text-2xl font-bold">Add Host File Mount</h3>
|
||||
<button @click="hostFileModalOpen=false"
|
||||
class="absolute top-0 right-0 flex items-center justify-center w-8 h-8 mt-5 mr-5 rounded-full dark:text-white hover:bg-neutral-100 dark:hover:bg-coolgray-300 outline-0 focus-visible:ring-2 focus-visible:ring-coollabs dark:focus-visible:ring-warning">
|
||||
<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 flex items-center justify-center w-auto"
|
||||
x-init="$watch('hostFileModalOpen', value => {
|
||||
if (value) {
|
||||
$nextTick(() => {
|
||||
const input = $el.querySelector('input');
|
||||
input?.focus();
|
||||
})
|
||||
}
|
||||
})">
|
||||
<form class="flex flex-col w-full gap-2 rounded-sm"
|
||||
wire:submit='submitHostFileStorage'>
|
||||
<div class="flex flex-col">
|
||||
<div>Bind an existing host file into the container. Coolify will not create, edit, load, chmod, or delete the source file.</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<x-forms.input canGate="update" :canResource="$resource"
|
||||
placeholder="/etc/nginx/nginx.conf"
|
||||
id="host_file_storage_source" label="Host File Path" required
|
||||
helper="Existing file on the host system." />
|
||||
<x-forms.input canGate="update" :canResource="$resource"
|
||||
placeholder="/etc/nginx/nginx.conf"
|
||||
id="host_file_storage_destination" label="Destination Path"
|
||||
required helper="File location inside the container." />
|
||||
<x-forms.button canGate="update" :canResource="$resource" type="submit">
|
||||
Add
|
||||
</x-forms.button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
{{-- Directory Modal --}}
|
||||
<template x-teleport="body">
|
||||
<div x-show="directoryModalOpen" @keydown.window.escape="directoryModalOpen=false"
|
||||
|
||||
@@ -184,6 +184,7 @@
|
||||
@endif
|
||||
</div>
|
||||
<x-forms.input instantSave id="comment" label="Comment"
|
||||
placeholder="{{ $isMagicVariable ? 'This env cannot be edited manually, it is handled by Coolify.' : '' }}"
|
||||
helper="Add a note to document what this environment variable is used for." maxlength="256" />
|
||||
</div>
|
||||
@endif
|
||||
@@ -191,16 +192,23 @@
|
||||
<div class="flex flex-col w-full gap-2">
|
||||
<div class="flex flex-col w-full gap-2 lg:flex-row">
|
||||
<x-forms.input disabled id="key" />
|
||||
<x-forms.env-var-input
|
||||
disabled
|
||||
type="password"
|
||||
id="value"
|
||||
:availableVars="$isSharedVariable ? [] : $this->availableSharedVariables"
|
||||
:projectUuid="data_get($parameters, 'project_uuid')"
|
||||
:environmentUuid="data_get($parameters, 'environment_uuid')"
|
||||
:serverUuid="data_get($parameters, 'server_uuid')" />
|
||||
@if ($is_shared)
|
||||
<x-forms.input disabled type="password" id="real_value" />
|
||||
@if ($isValueHidden)
|
||||
<div class="w-full">
|
||||
<input disabled type="text" value="Hidden (only admins can view)"
|
||||
class="input italic !text-neutral-500 dark:!text-neutral-500" />
|
||||
</div>
|
||||
@else
|
||||
<x-forms.env-var-input
|
||||
disabled
|
||||
type="password"
|
||||
id="value"
|
||||
:availableVars="$isSharedVariable ? [] : $this->availableSharedVariables"
|
||||
:projectUuid="data_get($parameters, 'project_uuid')"
|
||||
:environmentUuid="data_get($parameters, 'environment_uuid')"
|
||||
:serverUuid="data_get($parameters, 'server_uuid')" />
|
||||
@if ($is_shared)
|
||||
<x-forms.input disabled type="password" id="real_value" />
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
<x-forms.input disabled id="comment" label="Comment"
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
<h2>Healthcheck</h2>
|
||||
<x-forms.button canGate="update" :canResource="$resource" type="submit">Save</x-forms.button>
|
||||
@if (!$healthCheckEnabled)
|
||||
<x-modal-confirmation title="Confirm Healthcheck Enable?" buttonTitle="Enable Healthcheck"
|
||||
submitAction="toggleHealthcheck" :actions="['Enable healthcheck for this resource.']"
|
||||
warningMessage="If the health check fails, your application will become inaccessible. Please review the <a href='https://coolify.io/docs/knowledge-base/health-checks' target='_blank' class='underline text-white'>Health Checks</a> guide before proceeding!"
|
||||
step2ButtonText="Enable Healthcheck" :confirmWithText="false" :confirmWithPassword="false"
|
||||
isHighlightedButton>
|
||||
</x-modal-confirmation>
|
||||
<x-modal-confirmation :disabled="!auth()->user()->can('update', $resource)" :authDisabled="!auth()->user()->can('update', $resource)" title="Confirm Healthcheck Enable?" buttonTitle="Enable Healthcheck"
|
||||
submitAction="toggleHealthcheck" :actions="['Enable healthcheck for this resource.']"
|
||||
warningMessage="If the health check fails, your application will become inaccessible. Please review the <a href='https://coolify.io/docs/knowledge-base/health-checks' target='_blank' class='underline text-white'>Health Checks</a> guide before proceeding!"
|
||||
step2ButtonText="Enable Healthcheck" :confirmWithText="false" :confirmWithPassword="false"
|
||||
isHighlightedButton>
|
||||
</x-modal-confirmation>
|
||||
@else
|
||||
<x-forms.button canGate="update" :canResource="$resource" wire:click="toggleHealthcheck">Disable Healthcheck</x-forms.button>
|
||||
@endif
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<div class="w-full max-h-[70vh] overflow-y-auto pr-1 -mt-4">
|
||||
<div class="pb-4 text-sm dark:text-neutral-400">Identifiers for this resource. Read-only</div>
|
||||
|
||||
<div class="w-full max-h-[70vh] overflow-y-auto pr-1 pt-1">
|
||||
<div class="flex flex-col gap-6">
|
||||
<div>
|
||||
<h3>Resource</h3>
|
||||
|
||||
@@ -101,16 +101,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<x-callout type="warning" title="Access Restricted">
|
||||
You don't have permission to clone resources. Contact your team administrator to request access.
|
||||
</x-callout>
|
||||
@endcan
|
||||
|
||||
<h3 class="pt-4">Move Resource</h3>
|
||||
<div class="pb-4">Transfer this resource between projects and environments.</div>
|
||||
<h3 class="pt-4">Move Resource</h3>
|
||||
<div class="pb-4">Transfer this resource between projects and environments.</div>
|
||||
|
||||
@can('update', $resource)
|
||||
@if ($projects->count() > 0)
|
||||
<div class="space-y-4">
|
||||
<div class="flex flex-col lg:flex-row gap-4">
|
||||
@@ -160,9 +154,8 @@
|
||||
</div>
|
||||
@endif
|
||||
@else
|
||||
<x-callout type="warning" title="Access Restricted">
|
||||
You don't have permission to move resources between projects or environments. Contact your team
|
||||
administrator to request access.
|
||||
<x-callout type="danger" title="Insufficient Permissions">
|
||||
You don't have permission to modify this resource. Contact your team administrator for access.
|
||||
</x-callout>
|
||||
@endcan
|
||||
</div>
|
||||
|
||||
@@ -3,44 +3,47 @@
|
||||
<div class="flex flex-col gap-2 pb-2">
|
||||
<div class="flex gap-2 items-end">
|
||||
<h2>Task {{ $task->name }}</h2>
|
||||
<x-forms.button type="submit">
|
||||
<x-forms.button canGate="update" :canResource="$resource" type="submit">
|
||||
Save
|
||||
</x-forms.button>
|
||||
@if ($resource->isRunning())
|
||||
<x-forms.button type="button" wire:click="executeNow">
|
||||
Execute Now
|
||||
</x-forms.button>
|
||||
@can('update', $resource)
|
||||
<x-forms.button type="button" wire:click="executeNow">
|
||||
Execute Now
|
||||
</x-forms.button>
|
||||
@endcan
|
||||
@endif
|
||||
@if (!$isEnabled)
|
||||
<x-forms.button wire:click="toggleEnabled" isHighlighted>Enable Task</x-forms.button>
|
||||
@else
|
||||
<x-forms.button wire:click="toggleEnabled">Disable Task</x-forms.button>
|
||||
@endif
|
||||
<x-modal-confirmation title="Confirm Scheduled Task Deletion?" isErrorButton buttonTitle="Delete"
|
||||
submitAction="delete({{ $task->id }})" :actions="['The selected scheduled task will be permanently deleted.']" confirmationText="{{ $task->name }}"
|
||||
confirmationLabel="Please confirm the execution of the actions by entering the Scheduled Task Name below"
|
||||
shortConfirmationLabel="Scheduled Task Name" :confirmWithPassword="false"
|
||||
step2ButtonText="Permanently Delete" />
|
||||
|
||||
@can('update', $resource)
|
||||
@if (!$isEnabled)
|
||||
<x-forms.button wire:click="toggleEnabled" isHighlighted>Enable Task</x-forms.button>
|
||||
@else
|
||||
<x-forms.button wire:click="toggleEnabled">Disable Task</x-forms.button>
|
||||
@endif
|
||||
<x-modal-confirmation title="Confirm Scheduled Task Deletion?" isErrorButton buttonTitle="Delete"
|
||||
submitAction="delete({{ $task->id }})" :actions="['The selected scheduled task will be permanently deleted.']" confirmationText="{{ $task->name }}"
|
||||
confirmationLabel="Please confirm the execution of the actions by entering the Scheduled Task Name below"
|
||||
shortConfirmationLabel="Scheduled Task Name" :confirmWithPassword="false"
|
||||
step2ButtonText="Permanently Delete" />
|
||||
@endcan
|
||||
</div>
|
||||
<h3 class="pt-4">Configuration</h3>
|
||||
<div class="flex gap-2 w-full">
|
||||
<x-forms.input placeholder="Name" id="name" label="Name" required />
|
||||
<x-forms.input placeholder="0 0 * * * or daily" id="frequency" label="Frequency"
|
||||
<x-forms.input :disabled="!auth()->user()->can('update', $resource)" placeholder="Name" id="name" label="Name" required />
|
||||
<x-forms.input :disabled="!auth()->user()->can('update', $resource)" placeholder="0 0 * * * or daily" id="frequency" label="Frequency"
|
||||
helper="You can use every_minute, hourly, daily, weekly, monthly, yearly or a cron expression." required />
|
||||
<x-forms.input type="number" placeholder="300" id="timeout"
|
||||
<x-forms.input :disabled="!auth()->user()->can('update', $resource)" type="number" placeholder="300" id="timeout"
|
||||
helper="Maximum execution time in seconds (60-36000)." label="Timeout (seconds)" required />
|
||||
@if ($type === 'application')
|
||||
<x-forms.input placeholder="php"
|
||||
<x-forms.input :disabled="!auth()->user()->can('update', $resource)" placeholder="php"
|
||||
helper="You can leave this empty if your resource only has one container." id="container"
|
||||
label="Container name" />
|
||||
@elseif ($type === 'service')
|
||||
<x-forms.input placeholder="php"
|
||||
<x-forms.input :disabled="!auth()->user()->can('update', $resource)" placeholder="php"
|
||||
helper="You can leave this empty if your resource only has one service in your stack. Otherwise use the stack name, without the random generated ID. So if you have a mysql service in your stack, use mysql."
|
||||
id="container" label="Service name" />
|
||||
@endif
|
||||
</div>
|
||||
<x-forms.input placeholder="php artisan schedule:run" id="command" label="Command" required />
|
||||
<x-forms.input :disabled="!auth()->user()->can('update', $resource)" placeholder="php artisan schedule:run" id="command" label="Command" required />
|
||||
</form>
|
||||
|
||||
<div class="pt-4">
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
<x-forms.button type="submit">Add</x-forms.button>
|
||||
</form>
|
||||
@else
|
||||
<x-callout type="warning" title="Access Restricted" class="mt-4">
|
||||
You don't have permission to manage tags. Contact your team administrator to request access.
|
||||
<x-callout type="danger" title="Insufficient Permissions" class="mt-4">
|
||||
You don't have permission to manage this resource. Contact your team administrator for access.
|
||||
</x-callout>
|
||||
@endcan
|
||||
@if (data_get($this->resource, 'tags') && count(data_get($this->resource, 'tags')) > 0)
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in GitHub."
|
||||
label="GitHub Webhook Secret" id="githubManualWebhookSecret"></x-forms.input>
|
||||
@else
|
||||
<x-forms.input disabled type="password"
|
||||
<x-forms.input disabled
|
||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in GitHub."
|
||||
label="GitHub Webhook Secret" id="githubManualWebhookSecret"></x-forms.input>
|
||||
label="GitHub Webhook Secret" value="Hidden (only admins can view)"></x-forms.input>
|
||||
@endcan
|
||||
</div>
|
||||
<a target="_blank" class="flex hover:no-underline" href="{{ $resource?->gitWebhook }}">
|
||||
@@ -39,9 +39,9 @@
|
||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in GitLab."
|
||||
label="GitLab Webhook Secret" id="gitlabManualWebhookSecret"></x-forms.input>
|
||||
@else
|
||||
<x-forms.input disabled type="password"
|
||||
<x-forms.input disabled
|
||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in GitLab."
|
||||
label="GitLab Webhook Secret" id="gitlabManualWebhookSecret"></x-forms.input>
|
||||
label="GitLab Webhook Secret" value="Hidden (only admins can view)"></x-forms.input>
|
||||
@endcan
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
@@ -51,9 +51,9 @@
|
||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in Bitbucket."
|
||||
label="Bitbucket Webhook Secret" id="bitbucketManualWebhookSecret"></x-forms.input>
|
||||
@else
|
||||
<x-forms.input disabled type="password"
|
||||
<x-forms.input disabled
|
||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in Bitbucket."
|
||||
label="Bitbucket Webhook Secret" id="bitbucketManualWebhookSecret"></x-forms.input>
|
||||
label="Bitbucket Webhook Secret" value="Hidden (only admins can view)"></x-forms.input>
|
||||
@endcan
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
@@ -63,9 +63,9 @@
|
||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in Gitea."
|
||||
label="Gitea Webhook Secret" id="giteaManualWebhookSecret"></x-forms.input>
|
||||
@else
|
||||
<x-forms.input disabled type="password"
|
||||
<x-forms.input disabled
|
||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in Gitea."
|
||||
label="Gitea Webhook Secret" id="giteaManualWebhookSecret"></x-forms.input>
|
||||
label="Gitea Webhook Secret" value="Hidden (only admins can view)"></x-forms.input>
|
||||
@endcan
|
||||
</div>
|
||||
@can('update', $resource)
|
||||
|
||||
@@ -24,20 +24,23 @@
|
||||
</x-forms.select>
|
||||
<x-forms.button type="submit">Create</x-forms.button>
|
||||
</div>
|
||||
<div class="flex">
|
||||
Permissions
|
||||
<span
|
||||
class="pr-1">:</span>
|
||||
<div class="flex gap-1 font-bold dark:text-white">
|
||||
@if ($permissions)
|
||||
<div class="flex items-center gap-2">
|
||||
<span>Permissions</span>
|
||||
<x-helper helper="These permissions will be granted to the token." />
|
||||
@if ($permissions)
|
||||
<div class="flex gap-1.5 flex-wrap">
|
||||
@foreach ($permissions as $permission)
|
||||
<div>{{ $permission }}</div>
|
||||
<span
|
||||
class="px-2 py-0.5 text-xs rounded-sm font-medium {{ $permission === 'root' ? 'bg-red-500/20 text-red-400' : ($permission === 'write' || $permission === 'write:sensitive' ? 'bg-amber-500/20 text-amber-400' : ($permission === 'deploy' ? 'bg-blue-500/20 text-blue-400' : 'bg-neutral-500/20 text-neutral-300')) }}">
|
||||
{{ $permission }}
|
||||
</span>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="w-64">
|
||||
<h4>Token Permissions</h4>
|
||||
<div class="w-96">
|
||||
@if ($canUseRootPermissions)
|
||||
<x-forms.checkbox label="root" wire:model.live="permissions" domValue="root"
|
||||
helper="Root access, be careful!" :checked="in_array('root', $permissions)"></x-forms.checkbox>
|
||||
@@ -55,13 +58,23 @@
|
||||
helper="Write access requires admin or owner role" :checked="false"></x-forms.checkbox>
|
||||
@endif
|
||||
|
||||
<x-forms.checkbox label="deploy" wire:model.live="permissions" domValue="deploy"
|
||||
helper="Can trigger deploy webhooks." :checked="in_array('deploy', $permissions)"></x-forms.checkbox>
|
||||
<x-forms.checkbox label="read" domValue="read" wire:model.live="permissions" domValue="read"
|
||||
@if ($canUseDeployPermissions)
|
||||
<x-forms.checkbox label="deploy" wire:model.live="permissions" domValue="deploy"
|
||||
helper="Can trigger deploy webhooks." :checked="in_array('deploy', $permissions)"></x-forms.checkbox>
|
||||
@else
|
||||
<x-forms.checkbox label="deploy (admin/owner only)" disabled domValue="deploy"
|
||||
helper="Deploy access requires admin or owner role" :checked="false"></x-forms.checkbox>
|
||||
@endif
|
||||
<x-forms.checkbox label="read" wire:model.live="permissions" domValue="read"
|
||||
:checked="in_array('read', $permissions)"></x-forms.checkbox>
|
||||
<x-forms.checkbox label="read:sensitive" wire:model.live="permissions" domValue="read:sensitive"
|
||||
helper="Responses will include secrets, logs, passwords, and compose file contents."
|
||||
:checked="in_array('read:sensitive', $permissions)"></x-forms.checkbox>
|
||||
@if ($canUseSensitivePermissions)
|
||||
<x-forms.checkbox label="read:sensitive" wire:model.live="permissions" domValue="read:sensitive"
|
||||
helper="Responses will include secrets, logs, passwords, and compose file contents."
|
||||
:checked="in_array('read:sensitive', $permissions)"></x-forms.checkbox>
|
||||
@else
|
||||
<x-forms.checkbox label="read:sensitive (admin/owner only)" disabled domValue="read:sensitive"
|
||||
helper="Read:sensitive access requires admin or owner role" :checked="false"></x-forms.checkbox>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
@if (in_array('root', $permissions))
|
||||
@@ -70,13 +83,36 @@
|
||||
</form>
|
||||
@endcan
|
||||
@if (session()->has('token'))
|
||||
<div class="py-4 font-bold dark:text-warning">Please copy this token now. For your security, it won't be shown
|
||||
again.
|
||||
<div class="p-4 my-4 border rounded dark:border-coolgray-200 dark:bg-coolgray-100">
|
||||
<div class="pb-2 font-bold dark:text-warning">Please copy this token now. For your security, it won't
|
||||
be shown again.</div>
|
||||
<div class="relative" x-data="{ copied: false, isSecure: window.isSecureContext }">
|
||||
<input type="text" value="{{ session('token') }}" readonly
|
||||
class="input !text-white !bg-coolgray-200 font-mono" />
|
||||
<button x-show="isSecure"
|
||||
@click.prevent="copied = true; navigator.clipboard.writeText({{ Js::from(session('token')) }}); setTimeout(() => copied = false, 1000)"
|
||||
class="absolute right-2 top-1/2 -translate-y-1/2 p-1.5 text-gray-400 hover:text-gray-300 transition-colors"
|
||||
title="Copy to clipboard">
|
||||
<svg x-show="!copied" class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
|
||||
</svg>
|
||||
<svg x-show="copied" class="w-5 h-5 text-green-500" fill="none" stroke="currentColor"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pb-4 font-bold dark:text-white"> {{ session('token') }}</div>
|
||||
@endif
|
||||
<h3 class="py-4">Issued Tokens</h3>
|
||||
<div class="flex flex-col">
|
||||
<div x-data="{ search: '' }">
|
||||
<div class="flex items-center justify-between py-4">
|
||||
<h3>Issued Tokens</h3>
|
||||
@if ($tokens->count() > 1)
|
||||
<input type="text" x-model="search" placeholder="Filter tokens..." class="input w-64" />
|
||||
@endif
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<div class="overflow-x-auto">
|
||||
<div class="inline-block min-w-full">
|
||||
@@ -94,13 +130,17 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse ($tokens as $token)
|
||||
<tr wire:key="token-{{ $token->id }}">
|
||||
<tr wire:key="token-{{ $token->id }}"
|
||||
x-show="!search || {{ Js::from(strtolower($token->name).' '.strtolower(implode(' ', $token->abilities ?? []))) }}.includes(search.toLowerCase())">
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap">{{ $token->name }}</td>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||
@if ($token->abilities)
|
||||
<div class="flex gap-1">
|
||||
<div class="flex gap-1.5 flex-wrap">
|
||||
@foreach ($token->abilities as $ability)
|
||||
<div class="font-bold dark:text-white">{{ $ability }}</div>
|
||||
<span
|
||||
class="px-2 py-0.5 text-xs rounded-sm font-medium {{ $ability === 'root' ? 'bg-red-500/20 text-red-400' : ($ability === 'write' || $ability === 'write:sensitive' ? 'bg-amber-500/20 text-amber-400' : ($ability === 'deploy' ? 'bg-blue-500/20 text-blue-400' : 'bg-neutral-500/20 text-neutral-300')) }}">
|
||||
{{ $ability }}
|
||||
</span>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@@ -71,6 +71,11 @@
|
||||
</x-callout>
|
||||
@endif
|
||||
@if (!$isCloudflareTunnelsEnabled && $server->isFunctional())
|
||||
@cannot('update', $server)
|
||||
<x-callout type="danger" title="Insufficient Permissions" class="mb-4">
|
||||
You don't have permission to configure Cloudflare Tunnel for this server.
|
||||
</x-callout>
|
||||
@endcannot
|
||||
<div class="flex flex-col pb-2">
|
||||
<h3>Automated </h3>
|
||||
<a href="https://coolify.io/docs/knowledge-base/cloudflare/tunnels/server-ssh" target="_blank"
|
||||
@@ -91,10 +96,6 @@
|
||||
helper="The SSH domain you configured in Cloudflare. Make sure there is no protocol like http(s):// so you provide a FQDN not a URL. <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/cloudflare/tunnels/server-ssh' target='_blank'>Documentation</a>" />
|
||||
<x-forms.button type="submit" isHighlighted>Continue</x-forms.button>
|
||||
</form>
|
||||
@else
|
||||
<x-callout type="warning" title="Permission Required" class="mb-4">
|
||||
You don't have permission to configure Cloudflare Tunnel for this server.
|
||||
</x-callout>
|
||||
@endcan
|
||||
</div>
|
||||
@script
|
||||
@@ -121,10 +122,6 @@
|
||||
]" confirmationText="I manually configured Cloudflare Tunnel"
|
||||
confirmationLabel="Please type the confirmation text to confirm that you manually configured Cloudflare Tunnel."
|
||||
shortConfirmationLabel="Confirmation text" />
|
||||
@else
|
||||
<x-callout type="warning" title="Permission Required" class="mb-4">
|
||||
You don't have permission to configure Cloudflare Tunnel for this server.
|
||||
</x-callout>
|
||||
@endcan
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<h1>Server</h1>
|
||||
@if ($server->proxySet() || $server->isSentinelEnabled())
|
||||
@php
|
||||
$showSentinelStatus = $server->isFunctional() && $server->isSentinelEnabled();
|
||||
@endphp
|
||||
@if ($server->proxySet() || $showSentinelStatus)
|
||||
<div data-testid="server-status-summary" class="flex flex-wrap items-center gap-2">
|
||||
@if ($server->proxySet())
|
||||
<div class="flex items-center gap-1">
|
||||
@@ -38,7 +41,7 @@
|
||||
type="warning" />
|
||||
</div>
|
||||
@endif
|
||||
@if ($server->isSentinelEnabled())
|
||||
@if ($showSentinelStatus)
|
||||
@if ($server->isSentinelLive())
|
||||
<x-status-badge label="Sentinel" status="In sync" type="success" />
|
||||
@else
|
||||
@@ -78,7 +81,7 @@
|
||||
@endif
|
||||
</a>
|
||||
@endif
|
||||
@if ($server->isFunctional() && !$server->isSwarm() && !$server->settings->is_build_server)
|
||||
@if ($server->isFunctional() && !$server->isSwarm() && !$server->settings->is_build_server && auth()->user()?->can('viewSentinel', $server))
|
||||
<a class="{{ request()->routeIs('server.sentinel') || request()->routeIs('server.sentinel.*') ? 'dark:text-white' : '' }} flex items-center gap-1" href="{{ route('server.sentinel', [
|
||||
'server_uuid' => data_get($server, 'uuid'),
|
||||
]) }}" {{ wireNavigate() }}>
|
||||
@@ -114,6 +117,7 @@
|
||||
<div class="order-first sm:order-last">
|
||||
<div>
|
||||
@if ($server->proxySet())
|
||||
@can('manageProxy', $server)
|
||||
@if ($proxyStatus === 'running')
|
||||
<div class="flex gap-2">
|
||||
<div class="mt-1" wire:loading wire:target="loadProxyConfiguration">
|
||||
@@ -178,6 +182,7 @@
|
||||
Start Proxy
|
||||
</button>
|
||||
@endif
|
||||
@endcan
|
||||
@endif
|
||||
@script
|
||||
<script>
|
||||
|
||||
@@ -174,7 +174,7 @@
|
||||
</x-forms.button> --}}
|
||||
</div>
|
||||
@else
|
||||
<x-callout type="warning" title="Permission Required" class="mb-4">
|
||||
<x-callout type="danger" title="Insufficient Permissions" class="mb-4">
|
||||
You don't have permission to configure proxy settings for this server.
|
||||
</x-callout>
|
||||
@endcan
|
||||
|
||||
@@ -134,22 +134,22 @@
|
||||
{{ data_get($resource, 'State') }}
|
||||
</td>
|
||||
<td class="flex gap-2 px-5 py-4 text-sm whitespace-nowrap">
|
||||
@if (data_get($resource, 'State') === 'running')
|
||||
<x-forms.button
|
||||
wire:click="restartUnmanaged('{{ data_get($resource, 'ID') }}')"
|
||||
wire:key="{{ data_get($resource, 'ID') }}">Restart</x-forms.button>
|
||||
<x-forms.button isError
|
||||
wire:click="stopUnmanaged('{{ data_get($resource, 'ID') }}')"
|
||||
wire:key="{{ data_get($resource, 'ID') }}">Stop</x-forms.button>
|
||||
@elseif (data_get($resource, 'State') === 'exited')
|
||||
<x-forms.button
|
||||
wire:click="startUnmanaged('{{ data_get($resource, 'ID') }}')"
|
||||
wire:key="{{ data_get($resource, 'ID') }}">Start</x-forms.button>
|
||||
@elseif (data_get($resource, 'State') === 'restarting')
|
||||
<x-forms.button
|
||||
wire:click="stopUnmanaged('{{ data_get($resource, 'ID') }}')"
|
||||
wire:key="{{ data_get($resource, 'ID') }}">Stop</x-forms.button>
|
||||
@endif
|
||||
@if (data_get($resource, 'State') === 'running')
|
||||
<x-forms.button canGate="update" :canResource="$server"
|
||||
wire:click="restartUnmanaged('{{ data_get($resource, 'ID') }}')"
|
||||
wire:key="{{ data_get($resource, 'ID') }}">Restart</x-forms.button>
|
||||
<x-forms.button canGate="update" :canResource="$server" isError
|
||||
wire:click="stopUnmanaged('{{ data_get($resource, 'ID') }}')"
|
||||
wire:key="{{ data_get($resource, 'ID') }}">Stop</x-forms.button>
|
||||
@elseif (data_get($resource, 'State') === 'exited')
|
||||
<x-forms.button canGate="update" :canResource="$server"
|
||||
wire:click="startUnmanaged('{{ data_get($resource, 'ID') }}')"
|
||||
wire:key="{{ data_get($resource, 'ID') }}">Start</x-forms.button>
|
||||
@elseif (data_get($resource, 'State') === 'restarting')
|
||||
<x-forms.button canGate="update" :canResource="$server"
|
||||
wire:click="stopUnmanaged('{{ data_get($resource, 'ID') }}')"
|
||||
wire:key="{{ data_get($resource, 'ID') }}">Stop</x-forms.button>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
@@ -120,6 +120,19 @@
|
||||
@else
|
||||
You can't use this server until it is validated.
|
||||
@endif
|
||||
@if ($this->limaStartCommand)
|
||||
<div
|
||||
class="mt-4 rounded border border-coolgray-200 bg-coolgray-100 p-3 text-sm dark:border-coolgray-300 dark:bg-coolgray-100">
|
||||
<div class="font-semibold">Start this Lima VM locally</div>
|
||||
<div class="mt-1 dark:text-neutral-400">
|
||||
Run this from the Coolify repository root before validating this server:
|
||||
</div>
|
||||
<code
|
||||
class="mt-2 block overflow-x-auto rounded bg-black px-3 py-2 font-mono text-xs text-white">
|
||||
{{ $this->limaStartCommand }}
|
||||
</code>
|
||||
</div>
|
||||
@endif
|
||||
@if ($isValidating)
|
||||
<div x-data="{ slideOverOpen: true }">
|
||||
<x-slide-over closeWithX fullScreen>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<x-forms.input type="password" label="Password" readonly id="postgres_password" />
|
||||
</div>
|
||||
</div>
|
||||
<livewire:project.database.backup-edit :backup="$backup" :s3s="$s3s" :status="data_get($database, 'status')" />
|
||||
<livewire:project.database.backup-edit :backup="$backup" :available-s3-storages="$s3s" :status="data_get($database, 'status')" />
|
||||
<div class="py-4">
|
||||
<livewire:project.database.backup-executions :backup="$backup" />
|
||||
</div>
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
<span class="text-left menu-item-label" :class="collapsed && 'lg:hidden'">What's New</span>
|
||||
@if ($unreadCount > 0)
|
||||
<span
|
||||
class="absolute top-0 right-0 bg-error text-white text-[10px] rounded-full min-w-4 h-4 px-1 flex items-center justify-center"
|
||||
class="absolute right-2 top-1/2 -translate-y-1/2 bg-error text-white text-[10px] rounded-full min-w-4 h-4 px-1 flex items-center justify-center"
|
||||
aria-label="{{ $unreadCount }} unread changelog {{ Str::plural('entry', $unreadCount) }}">
|
||||
{{ $unreadCount > 9 ? '9+' : $unreadCount }}
|
||||
</span>
|
||||
|
||||
@@ -70,9 +70,18 @@
|
||||
environments!
|
||||
</x-callout>
|
||||
@endif
|
||||
<h4 class="pt-4">Webhook/S3 Endpoint Controls</h4>
|
||||
<x-forms.textarea id="webhook_allowed_internal_hosts" rows="4"
|
||||
label="Allowed Internal Webhook/S3 Targets"
|
||||
helper="Optional instance-level allowlist for webhook and S3 endpoint destinations. Supports exact hostnames, IPs, and CIDR ranges separated by commas or new lines."
|
||||
placeholder="hooks.company.local, 10.50.0.0/16, 192.168.10.20" />
|
||||
<div class="md:w-96">
|
||||
<x-forms.checkbox id="webhook_allow_localhost" label="Allow Localhost Webhook/S3 Targets"
|
||||
helper="Allows localhost/loopback targets only when they are also listed above. Use only for local development or trusted single-instance setups." />
|
||||
</div>
|
||||
<h4 class="pt-4">MCP Server</h4>
|
||||
<div class="md:w-96">
|
||||
<x-forms.checkbox instantSave id="is_mcp_server_enabled" label="Enable MCP Server"
|
||||
<x-forms.checkbox instantSave id="is_mcp_server_enabled" label="Enable MCP Server Instance-wide"
|
||||
helper="Exposes a Streamable HTTP Model Context Protocol endpoint at /mcp for AI clients (Claude Desktop, Cursor, etc.). Authenticates via Sanctum API tokens (Security > API Tokens). Requires API Access to be enabled." />
|
||||
</div>
|
||||
@if ($is_mcp_server_enabled)
|
||||
|
||||
@@ -81,12 +81,6 @@
|
||||
placeholder="2001:db8::1" autocomplete="new-password" />
|
||||
</div>
|
||||
|
||||
@if($buildActivityId)
|
||||
<div class="w-full mt-4">
|
||||
<livewire:activity-monitor header="Building Helper Image" :activityId="$buildActivityId"
|
||||
:fullHeight="false" />
|
||||
</div>
|
||||
@endif
|
||||
@if(isDev())
|
||||
<x-forms.input canGate="update" :canResource="$settings" id="dev_helper_version" label="Dev Helper Version (Development Only)"
|
||||
helper="Override the default coolify-helper image version. Leave empty to use the default version from config ({{ config('constants.coolify.helper_version') }}). Examples: 1.0.11, latest, dev"
|
||||
|
||||
@@ -44,6 +44,15 @@
|
||||
<x-forms.input required label="Frequency (cron expression)" disabled placeholder="disabled"
|
||||
helper="Frequency (cron expression) (automatically update coolify).<br>You can use every_minute, hourly, daily, weekly, monthly, yearly.<br><br>Default is every day at 00:00" />
|
||||
@endif
|
||||
|
||||
<h4 class="pt-4">Docker Registry</h4>
|
||||
<div class="md:w-96">
|
||||
<x-forms.select id="docker_registry_url" label="Docker Registry"
|
||||
helper="The Docker registry used to pull Coolify images during updates.<br>Switch to Docker Hub if you experience rate limiting with GitHub Container Registry.">
|
||||
<option value="docker.io">Docker Hub (docker.io)</option>
|
||||
<option value="ghcr.io">GitHub Container Registry (ghcr.io)</option>
|
||||
</x-forms.select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
</x-forms.button>
|
||||
</form>
|
||||
@else
|
||||
<x-callout type="warning" title="Permission Required">
|
||||
<x-callout type="danger" title="Insufficient Permissions">
|
||||
You don't have permission to create new GitHub Apps. Please contact your team administrator for access.
|
||||
</x-callout>
|
||||
@endcan
|
||||
@@ -24,7 +24,7 @@
|
||||
</form>
|
||||
</div>
|
||||
@else
|
||||
<x-callout type="warning" title="Permission Required">
|
||||
<x-callout type="danger" title="Insufficient Permissions">
|
||||
You don't have permission to create new S3 storage configurations. Please contact your team administrator for
|
||||
access.
|
||||
</x-callout>
|
||||
|
||||
@@ -10,10 +10,15 @@
|
||||
<x-forms.input canGate="update" :canResource="$storage" required label="Region" id="region" />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input canGate="update" :canResource="$storage" required type="password" label="Access Key"
|
||||
id="key" />
|
||||
<x-forms.input canGate="update" :canResource="$storage" required type="password" label="Secret Key"
|
||||
id="secret" />
|
||||
@if ($isPasswordHiddenForMember)
|
||||
<x-forms.input label="Access Key" disabled value="Hidden (only admins can view)" />
|
||||
<x-forms.input label="Secret Key" disabled value="Hidden (only admins can view)" />
|
||||
@else
|
||||
<x-forms.input canGate="update" :canResource="$storage" required type="password" label="Access Key"
|
||||
id="key" />
|
||||
<x-forms.input canGate="update" :canResource="$storage" required type="password" label="Secret Key"
|
||||
id="secret" />
|
||||
@endif
|
||||
</div>
|
||||
@can('validateConnection', $storage)
|
||||
<x-forms.button class="mt-4" isHighlighted wire:click="testConnection">
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
<div class="flex gap-2">
|
||||
<h1>Subscription</h1>
|
||||
</div>
|
||||
<x-callout type="warning" title="Permission Required">
|
||||
<x-callout type="danger" title="Insufficient Permissions">
|
||||
You are not an admin so you cannot manage your Team's subscription. If this does not make sense, please
|
||||
<span class="underline cursor-pointer dark:text-white" wire:click="help">contact us</span>.
|
||||
</x-callout>
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
<div class="flex items-end gap-2 pb-6">
|
||||
<x-forms.input id="name" label="Name" required canGate="update" :canResource="$team" />
|
||||
<x-forms.input id="description" label="Description" canGate="update" :canResource="$team" />
|
||||
<x-forms.checkbox id="is_mcp_server_enabled" label="Enable MCP Server" canGate="update" :canResource="$team"
|
||||
helper="Allows this team's API tokens to use the instance MCP endpoint when MCP is enabled instance-wide." />
|
||||
@can('update', $team)
|
||||
<x-forms.button type="submit">
|
||||
Save
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
@can('manageInvitations', currentTeam())
|
||||
<form wire:submit='viaLink' class="flex gap-2 flex-col lg:flex-row items-end">
|
||||
<div class="flex flex-1 lg:w-fit w-full gap-2">
|
||||
<x-forms.input id="email" type="email" label="Email" name="email" placeholder="Email" required />
|
||||
<x-forms.select id="role" name="role" label="Role">
|
||||
@if (auth()->user()->role() === 'owner')
|
||||
<option value="owner">Owner</option>
|
||||
<div>
|
||||
@can('manageInvitations', currentTeam())
|
||||
<form wire:submit='viaLink' class="flex gap-2 flex-col lg:flex-row items-end">
|
||||
<div class="flex flex-1 lg:w-fit w-full gap-2">
|
||||
<x-forms.input id="email" type="email" label="Email" name="email" placeholder="Email" required />
|
||||
<x-forms.select id="role" name="role" label="Role">
|
||||
@if (auth()->user()->role() === 'owner')
|
||||
<option value="owner">Owner</option>
|
||||
@endif
|
||||
<option value="admin">Admin</option>
|
||||
<option value="member">Member</option>
|
||||
</x-forms.select>
|
||||
</div>
|
||||
<div class="flex gap-2 lg:w-fit w-full">
|
||||
<x-forms.button type="submit">Generate Invitation Link</x-forms.button>
|
||||
@if (is_transactional_emails_enabled())
|
||||
<x-forms.button wire:click.prevent='viaEmail'>Send Invitation via Email</x-forms.button>
|
||||
@endif
|
||||
<option value="admin">Admin</option>
|
||||
<option value="member">Member</option>
|
||||
</x-forms.select>
|
||||
</div>
|
||||
<div class="flex gap-2 lg:w-fit w-full">
|
||||
<x-forms.button type="submit">Generate Invitation Link</x-forms.button>
|
||||
@if (is_transactional_emails_enabled())
|
||||
<x-forms.button wire:click.prevent='viaEmail'>Send Invitation via Email</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
</form>
|
||||
@endcan
|
||||
</div>
|
||||
</form>
|
||||
@endcan
|
||||
</div>
|
||||
@@ -13,7 +13,7 @@
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M19.5 13.572l-7.5 7.428l-7.5 -7.428m0 0a5 5 0 1 1 7.5 -6.566a5 5 0 1 1 7.5 6.572" />
|
||||
</svg>
|
||||
<span class="text-left menu-item-label" :class="collapsed && 'lg:hidden'">In progress</span>
|
||||
<span class="text-left menu-item-label sidebar-collapsed-label">In progress</span>
|
||||
</button>
|
||||
<button title="Upgrade" aria-label="Upgrade" class="menu-item cursor-pointer" @click="modalOpen=true" x-show="!showProgress">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="text-pink-500 transition-colors menu-item-icon hover:text-pink-300"
|
||||
@@ -25,7 +25,7 @@
|
||||
<path d="M9 21h6" />
|
||||
<path d="M9 18h6" />
|
||||
</svg>
|
||||
<span class="text-left menu-item-label" :class="collapsed && 'lg:hidden'">Upgrade</span>
|
||||
<span class="text-left menu-item-label sidebar-collapsed-label">Upgrade</span>
|
||||
</button>
|
||||
<template x-teleport="body">
|
||||
<div x-show="modalOpen"
|
||||
|
||||
Reference in new issue
Block a user