user()->currentTeam()->id; return [ "echo-private:team.{$teamId},FileStorageChanged" => 'refreshStoragesFromEvent', 'refreshStorages', 'addNewVolume', ]; } public function mount() { if (str($this->resource->getMorphClass())->contains('Standalone')) { $this->file_storage_directory_source = database_configuration_dir()."/{$this->resource->uuid}"; } else { $this->file_storage_directory_source = application_configuration_dir()."/{$this->resource->uuid}"; } if ($this->resource->getMorphClass() === \App\Models\Application::class) { if ($this->resource->destination->server->isSwarm()) { $this->isSwarm = true; } } $this->refreshStorages(); } public function refreshStoragesFromEvent() { $this->refreshStorages(); $this->dispatch('warning', 'File storage changed. Usually it means that the file / directory is already defined on the server, so Coolify set it up for you properly on the UI.'); } public function refreshStorages() { $this->fileStorage = $this->resource->fileStorages()->get(); $this->resource->load('persistentStorages.resource'); } public function getFilesProperty() { return $this->fileStorage->where('is_directory', false); } public function getDirectoriesProperty() { return $this->fileStorage->where('is_directory', true); } public function getVolumeCountProperty() { return $this->resource->persistentStorages()->count(); } public function getFileCountProperty() { return $this->files->count(); } public function getDirectoryCountProperty() { return $this->directories->count(); } public function submitPersistentVolume() { try { $this->authorize('update', $this->resource); $this->validate([ 'name' => 'required|string', 'mount_path' => 'required|string', 'host_path' => $this->isSwarm ? 'required|string' : 'string|nullable', ]); $name = $this->resource->uuid.'-'.$this->name; LocalPersistentVolume::create([ 'name' => $name, 'mount_path' => $this->mount_path, 'host_path' => $this->host_path, 'resource_id' => $this->resource->id, 'resource_type' => $this->resource->getMorphClass(), ]); $this->resource->refresh(); $this->dispatch('success', 'Volume added successfully'); $this->dispatch('closeStorageModal', 'volume'); $this->clearForm(); $this->refreshStorages(); } catch (\Throwable $e) { return handleError($e, $this); } } public function submitFileStorage() { try { $this->authorize('update', $this->resource); $this->validate([ 'file_storage_path' => 'required|string', 'file_storage_content' => 'nullable|string', ]); $this->file_storage_path = trim($this->file_storage_path); $this->file_storage_path = str($this->file_storage_path)->start('/')->value(); if ($this->resource->getMorphClass() === \App\Models\Application::class) { $fs_path = application_configuration_dir().'/'.$this->resource->uuid.$this->file_storage_path; } elseif (str($this->resource->getMorphClass())->contains('Standalone')) { $fs_path = database_configuration_dir().'/'.$this->resource->uuid.$this->file_storage_path; } else { throw new \Exception('No valid resource type for file mount storage type!'); } \App\Models\LocalFileVolume::create([ 'fs_path' => $fs_path, 'mount_path' => $this->file_storage_path, 'content' => $this->file_storage_content, 'is_directory' => false, 'resource_id' => $this->resource->id, 'resource_type' => get_class($this->resource), ]); $this->dispatch('success', 'File mount added successfully'); $this->dispatch('closeStorageModal', 'file'); $this->clearForm(); $this->refreshStorages(); } catch (\Throwable $e) { return handleError($e, $this); } } public function submitFileStorageDirectory() { try { $this->authorize('update', $this->resource); $this->validate([ 'file_storage_directory_source' => 'required|string', 'file_storage_directory_destination' => 'required|string', ]); $this->file_storage_directory_source = trim($this->file_storage_directory_source); $this->file_storage_directory_source = str($this->file_storage_directory_source)->start('/')->value(); $this->file_storage_directory_destination = trim($this->file_storage_directory_destination); $this->file_storage_directory_destination = str($this->file_storage_directory_destination)->start('/')->value(); // Validate paths to prevent command injection validateShellSafePath($this->file_storage_directory_source, 'storage source path'); validateShellSafePath($this->file_storage_directory_destination, 'storage destination path'); \App\Models\LocalFileVolume::create([ 'fs_path' => $this->file_storage_directory_source, 'mount_path' => $this->file_storage_directory_destination, 'is_directory' => true, 'resource_id' => $this->resource->id, 'resource_type' => get_class($this->resource), ]); $this->dispatch('success', 'Directory mount added successfully'); $this->dispatch('closeStorageModal', 'directory'); $this->clearForm(); $this->refreshStorages(); } catch (\Throwable $e) { return handleError($e, $this); } } public function clearForm() { $this->name = ''; $this->mount_path = ''; $this->host_path = null; $this->file_storage_path = ''; $this->file_storage_content = null; $this->file_storage_directory_destination = ''; if (str($this->resource->getMorphClass())->contains('Standalone')) { $this->file_storage_directory_source = database_configuration_dir()."/{$this->resource->uuid}"; } else { $this->file_storage_directory_source = application_configuration_dir()."/{$this->resource->uuid}"; } } public function render() { return view('livewire.project.service.storage'); } }