mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-13 22:15:35 +00:00
Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
fb4588be3c
9 files changed
+271
-90
No files matched your search
@@ -14,6 +14,8 @@ use Illuminate\Support\Facades\Queue;
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
config(['app.maintenance.driver' => 'file']);
|
||||
|
||||
InstanceSettings::unguarded(fn () => InstanceSettings::firstOrCreate(['id' => 0]));
|
||||
|
||||
$this->team = Team::factory()->create();
|
||||
@@ -136,6 +138,53 @@ test('proxy settings regenerate managed labels', function () {
|
||||
expect(base64_decode($this->application->fresh()->custom_labels))->not->toContain('sentinel-label=true');
|
||||
});
|
||||
|
||||
test('http basic auth updates regenerate managed labels', function () {
|
||||
$this->application->settings->update(['is_container_label_readonly_enabled' => true]);
|
||||
$this->application->update([
|
||||
'fqdn' => 'https://app.example.com',
|
||||
'is_http_basic_auth_enabled' => false,
|
||||
'http_basic_auth_username' => null,
|
||||
'http_basic_auth_password' => null,
|
||||
'custom_labels' => base64_encode('sentinel-label=true'),
|
||||
]);
|
||||
|
||||
$this->withHeaders(applicationSettingsApiHeaders($this->bearerToken))
|
||||
->patchJson("/api/v1/applications/{$this->application->uuid}", [
|
||||
'is_http_basic_auth_enabled' => true,
|
||||
'http_basic_auth_username' => 'api-user',
|
||||
'http_basic_auth_password' => 'api-password',
|
||||
])
|
||||
->assertOk();
|
||||
|
||||
$application = $this->application->fresh();
|
||||
$labels = $application->parseContainerLabels();
|
||||
|
||||
expect((bool) $application->is_http_basic_auth_enabled)->toBeTrue()
|
||||
->and($application->http_basic_auth_username)->toBe('api-user')
|
||||
->and($application->http_basic_auth_password)->toBe('api-password')
|
||||
->and($labels)->toContain('basicauth')
|
||||
->and($labels)->toContain('api-user')
|
||||
->and($labels)->not->toContain('sentinel-label=true');
|
||||
});
|
||||
|
||||
test('http basic auth updates preserve user-managed labels', function () {
|
||||
$this->application->settings->update(['is_container_label_readonly_enabled' => false]);
|
||||
$this->application->update([
|
||||
'fqdn' => 'https://app.example.com',
|
||||
'custom_labels' => base64_encode('sentinel-label=true'),
|
||||
]);
|
||||
|
||||
$this->withHeaders(applicationSettingsApiHeaders($this->bearerToken))
|
||||
->patchJson("/api/v1/applications/{$this->application->uuid}", [
|
||||
'is_http_basic_auth_enabled' => true,
|
||||
'http_basic_auth_username' => 'api-user',
|
||||
'http_basic_auth_password' => 'api-password',
|
||||
])
|
||||
->assertOk();
|
||||
|
||||
expect(base64_decode($this->application->fresh()->custom_labels))->toBe('sentinel-label=true');
|
||||
});
|
||||
|
||||
test('rejects invalid boolean application settings', function () {
|
||||
$this->withHeaders(applicationSettingsApiHeaders($this->bearerToken))
|
||||
->patchJson("/api/v1/applications/{$this->application->uuid}", [
|
||||
|
||||
@@ -98,7 +98,7 @@ it('uses a larger high-contrast label for every terminal loading phase', functio
|
||||
$styles = file_get_contents(resource_path('css/app.css'));
|
||||
|
||||
expect(substr_count($resourceView.$terminalView.$globalView, 'terminal-loading-label'))
|
||||
->toBeGreaterThanOrEqual(3)
|
||||
->toBeGreaterThanOrEqual(2)
|
||||
->and($styles)
|
||||
->toContain('.terminal-loading-label')
|
||||
->toContain('font-size: 0.875rem;')
|
||||
@@ -323,12 +323,12 @@ it('preserves terminal scrollback across transient reconnects', function () {
|
||||
->not->toContain("this.term.reset();\n this.term.clear();");
|
||||
});
|
||||
|
||||
it('renders a horizontally scrollable mobile terminal key row', function () {
|
||||
it('renders a horizontally scrollable terminal key row only on mobile', function () {
|
||||
$terminalView = file_get_contents(resource_path('views/livewire/project/shared/terminal.blade.php'));
|
||||
$appCss = file_get_contents(resource_path('css/app.css'));
|
||||
|
||||
expect($terminalView)
|
||||
->not->toContain('class="sm:hidden" data-terminal-mobile-toolbar')
|
||||
->toContain('class="sm:hidden"')
|
||||
->toContain('overflow-x-auto')
|
||||
->toContain('whitespace-nowrap')
|
||||
->toContain('pasteFromClipboard()')
|
||||
@@ -343,11 +343,12 @@ it('renders a horizontally scrollable mobile terminal key row', function () {
|
||||
->toContain("sendTerminalKey('~')")
|
||||
->toContain("sendTerminalKey('-')")
|
||||
->toContain("sendTerminalControl('ctrlC')")
|
||||
->toContain("sendTerminalControl('ctrlD')")
|
||||
->toContain("sendTerminalControl('ctrlBackslash')")
|
||||
->toContain("sendTerminalControl('ctrlS')")
|
||||
->toContain("sendTerminalControl('ctrlZ')")
|
||||
->not->toContain("sendTerminalControl('arrowUp')")
|
||||
->toContain("fullscreen ? 'relative z-[2] shrink-0 px-2 pb-2' : 'relative z-[2] mt-2 shrink-0'")
|
||||
->toContain("fullscreen ? 'relative z-[2] shrink-0 px-2 pb-2' : (keyboardInset > 0 ? 'fixed inset-x-0 z-[100002] px-2 pb-2' : 'relative z-[2] mt-2 shrink-0')")
|
||||
->toContain('data-terminal-mobile-toolbar')
|
||||
->and($appCss)
|
||||
->toContain('.terminal-mobile-key')
|
||||
@@ -358,13 +359,13 @@ it('renders a horizontally scrollable mobile terminal key row', function () {
|
||||
->toContain('var(--terminal-scrollbar');
|
||||
});
|
||||
|
||||
it('shows the terminal key row outside fullscreen mode', function () {
|
||||
it('shows the mobile terminal key row outside fullscreen mode', function () {
|
||||
$terminalView = file_get_contents(resource_path('views/livewire/project/shared/terminal.blade.php'));
|
||||
$terminalClient = file_get_contents(resource_path('js/terminal.js'));
|
||||
|
||||
expect($terminalView)
|
||||
->toContain("fullscreen ? 'relative z-[2] shrink-0 px-2 pb-2' : 'relative z-[2] mt-2 shrink-0'")
|
||||
->not->toContain('class="sm:hidden" data-terminal-mobile-toolbar')
|
||||
->toContain("fullscreen ? 'relative z-[2] shrink-0 px-2 pb-2' : (keyboardInset > 0 ? 'fixed inset-x-0 z-[100002] px-2 pb-2' : 'relative z-[2] mt-2 shrink-0')")
|
||||
->toContain('class="sm:hidden"')
|
||||
->toContain(':style="!fullscreen && keyboardInset > 0 ? `top: ${keyboardAnchorTop}px; transform: translateY(-100%)` : \'\'"')
|
||||
->and($terminalClient)
|
||||
->toContain("this.\$refs.terminalWrapper.style.removeProperty('display')")
|
||||
@@ -384,6 +385,7 @@ it('sends terminal mobile toolbar controls through the websocket', function () {
|
||||
->toContain("tab: '\\t'")
|
||||
->toContain("escape: '\\x1b'")
|
||||
->toContain("ctrlC: '\\x03'")
|
||||
->toContain("ctrlD: '\\x04'")
|
||||
->toContain("ctrlBackslash: '\\x1c'")
|
||||
->toContain("ctrlS: '\\x13'")
|
||||
->toContain("ctrlZ: '\\x1a'")
|
||||
|
||||
@@ -11,25 +11,61 @@ it('shows the initial terminal target launcher and keeps the header picker for s
|
||||
->toContain('this.targetChosen = true;');
|
||||
});
|
||||
|
||||
it('shows a centered themed target canvas before loading xterm', function () {
|
||||
it('shows the pre-session target list as a page card instead of a full-height console canvas', function () {
|
||||
$view = file_get_contents(resource_path('views/livewire/terminal/index.blade.php'));
|
||||
|
||||
$pickerBranch = str($view)
|
||||
->after("@if (\$selected_uuid === 'default')")
|
||||
->before("\n @else")
|
||||
->toString();
|
||||
|
||||
expect($view)
|
||||
->toContain("@if (\$selected_uuid === 'default')")
|
||||
->toContain('data-terminal-target-picker="page"')
|
||||
->toContain('data-terminal-target-canvas')
|
||||
->toContain('items-center justify-center')
|
||||
->toContain(':data-console-theme="consoleTheme"')
|
||||
->toContain("@else\n <div wire:key=\"terminal-session-canvas\" data-terminal-session-canvas");
|
||||
->toContain("@else\n <div wire:key=\"terminal-session-canvas\" data-terminal-session-canvas")
|
||||
->and($pickerBranch)
|
||||
->toContain('<x-application.settings-section class="terminal-target-card"')
|
||||
->toContain('title="Start a terminal session"')
|
||||
// The themed console canvas belongs to an open session, not to target selection.
|
||||
->not->toContain('application-console-shell')
|
||||
->not->toContain(':data-console-theme="consoleTheme"')
|
||||
->not->toContain('<x-terminal.theme-selector');
|
||||
});
|
||||
|
||||
it('keeps the terminal target picker within the mobile canvas', function () {
|
||||
it('keeps the pre-session target list scrollable inside the full-width card', function () {
|
||||
$view = file_get_contents(resource_path('views/livewire/terminal/index.blade.php'));
|
||||
$styles = file_get_contents(resource_path('css/app.css'));
|
||||
|
||||
expect($view)
|
||||
->toContain('data-terminal-target-picker="page"')
|
||||
->toContain('flex max-h-full w-full max-w-lg flex-col')
|
||||
->toContain('class="terminal-target-list min-h-0 flex-1 overflow-y-auto p-2"');
|
||||
->toContain('aria-label="Filter terminal targets"')
|
||||
->toContain('class="application-settings-workspace flex w-full min-w-0 flex-col"')
|
||||
->toContain('class="terminal-target-card-list"')
|
||||
->and($styles)
|
||||
->toContain('.terminal-target-card .application-settings-section-body')
|
||||
->toMatch('/\.terminal-target-card-list\s*\{[^}]*max-height:\s*min\(70vh, 34rem\);/s')
|
||||
->toMatch('/\.terminal-target-group-label\s*\{[^}]*position:\s*sticky;/s')
|
||||
// The wrapped filter needs the same gutter on both sides of the header, and the
|
||||
// override must match the base header selector's specificity to win.
|
||||
->toMatch('/\.application-settings-section\.terminal-target-card > :is\(header, \.application-settings-section-header\)\s*\{\s*padding-right:\s*1rem;/s');
|
||||
});
|
||||
|
||||
it('splits target rows into a name and a server column that only shows with several servers', function () {
|
||||
$view = file_get_contents(resource_path('views/livewire/terminal/index.blade.php'));
|
||||
$styles = file_get_contents(resource_path('css/app.css'));
|
||||
|
||||
expect($view)
|
||||
->toContain("'name' => \$container['name'],")
|
||||
->toContain("'server' => \$server->name,")
|
||||
->toContain('multipleServers: @js($servers->count() > 1)')
|
||||
->toContain('x-text="target.name"')
|
||||
->toContain('class="terminal-target-item-server" x-text="target.server"')
|
||||
->toContain('x-show="multipleServers"')
|
||||
// The label keeps both parts so filtering still matches the server name.
|
||||
->toContain("'label' => \$server->name.' · '.\$container['name'],")
|
||||
->and($styles)
|
||||
->toContain('.terminal-target-item-server');
|
||||
});
|
||||
|
||||
it('loads targets inside the themed session picker with an accent scrollbar', function () {
|
||||
@@ -100,12 +136,12 @@ it('uses floating rounded controls instead of the legacy terminal header bar', f
|
||||
->not->toContain('application-console-header flex h-[30px]');
|
||||
});
|
||||
|
||||
it('keeps the theme selector identical before and during a terminal session', function () {
|
||||
it('offers the console theme selector only while a session owns the canvas', function () {
|
||||
$view = file_get_contents(resource_path('views/livewire/terminal/index.blade.php'));
|
||||
$selector = file_get_contents(resource_path('views/components/terminal/theme-selector.blade.php'));
|
||||
|
||||
expect(substr_count($view, '<x-terminal.theme-selector'))
|
||||
->toBe(2)
|
||||
->toBe(1)
|
||||
->and($selector)
|
||||
->toContain('terminal-theme-trigger flex h-8 items-center gap-2 rounded-md px-2.5 text-xs font-medium')
|
||||
->and($view)
|
||||
@@ -130,19 +166,20 @@ it('reuses one chevron theme selector before and during terminal sessions', func
|
||||
$selector = file_get_contents(resource_path('views/components/terminal/theme-selector.blade.php'));
|
||||
|
||||
expect(substr_count($globalView.$resourceView, '<x-terminal.theme-selector'))
|
||||
->toBe(3)
|
||||
->toBe(2)
|
||||
->and($selector)
|
||||
->toContain('terminal-theme-trigger')
|
||||
->toContain('viewBox="0 0 12 12"')
|
||||
->toContain('m3.5 4.75 2.5 2.5 2.5-2.5');
|
||||
});
|
||||
|
||||
it('keeps the pre-session theme selector out of the centered picker layout', function () {
|
||||
it('keeps the theme selector in the floating session toolbar', function () {
|
||||
$view = file_get_contents(resource_path('views/livewire/terminal/index.blade.php'));
|
||||
|
||||
expect($view)
|
||||
->toContain('class="absolute top-3 right-3 z-20"')
|
||||
->toContain('<x-terminal.theme-selector');
|
||||
->toContain('terminal-session-toolbar absolute top-3 right-3 left-3')
|
||||
->toContain('<x-terminal.theme-selector')
|
||||
->not->toContain('class="absolute top-3 right-3 z-20"');
|
||||
});
|
||||
|
||||
it('updates the owning terminal theme directly so its label and canvas stay synchronized', function () {
|
||||
@@ -174,8 +211,9 @@ it('locks the terminal page to the viewport so the document does not scroll', fu
|
||||
$appCss = file_get_contents(resource_path('css/app.css'));
|
||||
|
||||
expect($view)
|
||||
->toContain('class="terminal-page application-settings-form"')
|
||||
->toContain('class="terminal-page-console min-h-0 w-full flex-1 overflow-hidden"')
|
||||
// The viewport lock only applies once a session owns the canvas.
|
||||
->toContain("class=\"{{ \$selected_uuid === 'default' ? '' : 'terminal-page' }} application-settings-form\"")
|
||||
->toContain("'terminal-page-console min-h-0 w-full flex-1 overflow-hidden'")
|
||||
->not->toContain('h-[calc(100dvh-11rem)]')
|
||||
->not->toContain('min-h-[32rem]')
|
||||
->and($appCss)
|
||||
|
||||
Reference in new issue
Block a user