fix: move base directory path normalization to frontend

Change wire:model.blur to wire:model.defer to prevent backend requests
during form navigation. Add Alpine.js path normalization functions that
run on blur, fixing tab focus issues while keeping path validation
purely on the frontend.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Andras Bacsai 2025-12-01 13:51:21 +01:00
parent b55aaf34d3
commit 981fc127b5
5 changed files with 77 additions and 45 deletions

View file

@ -75,16 +75,6 @@ public function mount()
$this->github_apps = GithubApp::private(); $this->github_apps = GithubApp::private();
} }
public function updatedBaseDirectory()
{
if ($this->base_directory) {
$this->base_directory = rtrim($this->base_directory, '/');
if (! str($this->base_directory)->startsWith('/')) {
$this->base_directory = '/'.$this->base_directory;
}
}
}
public function updatedBuildPack() public function updatedBuildPack()
{ {
if ($this->build_pack === 'nixpacks') { if ($this->build_pack === 'nixpacks') {

View file

@ -107,26 +107,6 @@ public function mount()
$this->query = request()->query(); $this->query = request()->query();
} }
public function updatedBaseDirectory()
{
if ($this->base_directory) {
$this->base_directory = rtrim($this->base_directory, '/');
if (! str($this->base_directory)->startsWith('/')) {
$this->base_directory = '/'.$this->base_directory;
}
}
}
public function updatedDockerComposeLocation()
{
if ($this->docker_compose_location) {
$this->docker_compose_location = rtrim($this->docker_compose_location, '/');
if (! str($this->docker_compose_location)->startsWith('/')) {
$this->docker_compose_location = '/'.$this->docker_compose_location;
}
}
}
public function updatedBuildPack() public function updatedBuildPack()
{ {
if ($this->build_pack === 'nixpacks') { if ($this->build_pack === 'nixpacks') {

View file

@ -61,12 +61,33 @@ class="loading loading-xs dark:text-warning loading-spinner"></span>
@endif @endif
</div> </div>
@if ($build_pack === 'dockercompose') @if ($build_pack === 'dockercompose')
<div x-data="{ baseDir: '{{ $base_directory }}', composeLocation: '{{ $docker_compose_location }}' }" class="gap-2 flex flex-col"> <div x-data="{
<x-forms.input placeholder="/" wire:model.blur="base_directory" label="Base Directory" baseDir: '{{ $base_directory }}',
helper="Directory to use as root. Useful for monorepos." x-model="baseDir" /> composeLocation: '{{ $docker_compose_location }}',
<x-forms.input placeholder="/docker-compose.yaml" wire:model.blur="docker_compose_location" normalizePath(path) {
if (!path || path.trim() === '') return '/';
path = path.trim();
// Remove trailing slashes
path = path.replace(/\/+$/, '');
// Ensure leading slash
if (!path.startsWith('/')) {
path = '/' + path;
}
return path;
},
normalizeBaseDir() {
this.baseDir = this.normalizePath(this.baseDir);
},
normalizeComposeLocation() {
this.composeLocation = this.normalizePath(this.composeLocation);
}
}" class="gap-2 flex flex-col">
<x-forms.input placeholder="/" wire:model.defer="base_directory" label="Base Directory"
helper="Directory to use as root. Useful for monorepos." x-model="baseDir"
@blur="normalizeBaseDir()" />
<x-forms.input placeholder="/docker-compose.yaml" wire:model.defer="docker_compose_location"
label="Docker Compose Location" helper="It is calculated together with the Base Directory." label="Docker Compose Location" helper="It is calculated together with the Base Directory."
x-model="composeLocation" /> x-model="composeLocation" @blur="normalizeComposeLocation()" />
<div class="pt-2"> <div class="pt-2">
<span> <span>
Compose file location in your repository: </span><span class='dark:text-warning' Compose file location in your repository: </span><span class='dark:text-warning'

View file

@ -95,15 +95,35 @@
@endif @endif
</div> </div>
@if ($build_pack === 'dockercompose') @if ($build_pack === 'dockercompose')
<div x-data="{ baseDir: '{{ $base_directory }}', composeLocation: '{{ $docker_compose_location }}' }" class="gap-2 flex flex-col"> <div x-data="{
<x-forms.input placeholder="/" wire:model.blur="base_directory" baseDir: '{{ $base_directory }}',
composeLocation: '{{ $docker_compose_location }}',
normalizePath(path) {
if (!path || path.trim() === '') return '/';
path = path.trim();
// Remove trailing slashes
path = path.replace(/\/+$/, '');
// Ensure leading slash
if (!path.startsWith('/')) {
path = '/' + path;
}
return path;
},
normalizeBaseDir() {
this.baseDir = this.normalizePath(this.baseDir);
},
normalizeComposeLocation() {
this.composeLocation = this.normalizePath(this.composeLocation);
}
}" class="gap-2 flex flex-col">
<x-forms.input placeholder="/" wire:model.defer="base_directory"
label="Base Directory" label="Base Directory"
helper="Directory to use as root. Useful for monorepos." helper="Directory to use as root. Useful for monorepos."
x-model="baseDir" /> x-model="baseDir" @blur="normalizeBaseDir()" />
<x-forms.input placeholder="/docker-compose.yaml" <x-forms.input placeholder="/docker-compose.yaml"
wire:model.blur="docker_compose_location" label="Docker Compose Location" wire:model.defer="docker_compose_location" label="Docker Compose Location"
helper="It is calculated together with the Base Directory." helper="It is calculated together with the Base Directory."
x-model="composeLocation" /> x-model="composeLocation" @blur="normalizeComposeLocation()" />
<div class="pt-2"> <div class="pt-2">
<span> <span>
Compose file location in your repository: </span><span Compose file location in your repository: </span><span

View file

@ -52,12 +52,33 @@
@endif @endif
</div> </div>
@if ($build_pack === 'dockercompose') @if ($build_pack === 'dockercompose')
<div x-data="{ baseDir: '{{ $base_directory }}', composeLocation: '{{ $docker_compose_location }}' }" class="gap-2 flex flex-col"> <div x-data="{
<x-forms.input placeholder="/" wire:model.blur="base_directory" label="Base Directory" baseDir: '{{ $base_directory }}',
helper="Directory to use as root. Useful for monorepos." x-model="baseDir" /> composeLocation: '{{ $docker_compose_location }}',
<x-forms.input placeholder="/docker-compose.yaml" wire:model.blur="docker_compose_location" normalizePath(path) {
if (!path || path.trim() === '') return '/';
path = path.trim();
// Remove trailing slashes
path = path.replace(/\/+$/, '');
// Ensure leading slash
if (!path.startsWith('/')) {
path = '/' + path;
}
return path;
},
normalizeBaseDir() {
this.baseDir = this.normalizePath(this.baseDir);
},
normalizeComposeLocation() {
this.composeLocation = this.normalizePath(this.composeLocation);
}
}" class="gap-2 flex flex-col">
<x-forms.input placeholder="/" wire:model.defer="base_directory" label="Base Directory"
helper="Directory to use as root. Useful for monorepos." x-model="baseDir"
@blur="normalizeBaseDir()" />
<x-forms.input placeholder="/docker-compose.yaml" wire:model.defer="docker_compose_location"
label="Docker Compose Location" helper="It is calculated together with the Base Directory." label="Docker Compose Location" helper="It is calculated together with the Base Directory."
x-model="composeLocation" /> x-model="composeLocation" @blur="normalizeComposeLocation()" />
<div class="pt-2"> <div class="pt-2">
<span> <span>
Compose file location in your repository: </span><span class='dark:text-warning' Compose file location in your repository: </span><span class='dark:text-warning'