diff --git a/app/View/Components/Forms/InputWithSelect.php b/app/View/Components/Forms/InputWithSelect.php
new file mode 100644
index 000000000..1ce139cec
--- /dev/null
+++ b/app/View/Components/Forms/InputWithSelect.php
@@ -0,0 +1,82 @@
+canGate && $this->canResource && $this->autoDisable) {
+ $hasPermission = Gate::allows($this->canGate, $this->canResource);
+
+ if (!$hasPermission) {
+ $this->disabled = true;
+ }
+ }
+ }
+
+ public function render(): View|Closure|string
+ {
+ // Store original ID for wire:model binding (property name)
+ $this->modelBinding = $this->id;
+
+ if (is_null($this->id)) {
+ $this->id = new Cuid2;
+ // Don't create wire:model binding for auto-generated IDs
+ $this->modelBinding = 'null';
+ }
+ // Generate unique HTML ID by adding random suffix
+ // This prevents duplicate IDs when multiple forms are on the same page
+ if ($this->modelBinding && $this->modelBinding !== 'null') {
+ // Use original ID with random suffix for uniqueness
+ $uniqueSuffix = new Cuid2;
+ $this->htmlId = $this->modelBinding . '-' . $uniqueSuffix;
+ } else {
+ $this->htmlId = (string) $this->id;
+ }
+
+ if (is_null($this->name)) {
+ $this->name = $this->modelBinding !== 'null' ? $this->modelBinding : (string) $this->id;
+ }
+
+ // Set default option if not provided and options exist
+ if (is_null($this->defaultOption) && !empty($this->options)) {
+ $this->defaultOption = array_key_first($this->options);
+ }
+
+ return view('components.forms.input-with-select');
+ }
+}
diff --git a/resources/views/components/forms/input-with-select.blade.php b/resources/views/components/forms/input-with-select.blade.php
new file mode 100644
index 000000000..f9b1f4c9b
--- /dev/null
+++ b/resources/views/components/forms/input-with-select.blade.php
@@ -0,0 +1,169 @@
+@php
+ $inputId = $htmlId !== 'null' ? $htmlId . '-input' : null;
+ $selectId = $htmlId !== 'null' ? $htmlId . '-select' : null;
+@endphp
+
+
+ @if ($label)
+
+ @endif
+
+
+ {{-- Input --}}
+
+
+ {{-- Select --}}
+
+
+
+ @if (!$label && $helper)
+
+ @endif
+ @error($modelBinding)
+
+ @enderror
+
+
+
diff --git a/resources/views/livewire/project/shared/resource-limits.blade.php b/resources/views/livewire/project/shared/resource-limits.blade.php
index 99ff249e9..da1cf3722 100644
--- a/resources/views/livewire/project/shared/resource-limits.blade.php
+++ b/resources/views/livewire/project/shared/resource-limits.blade.php
@@ -20,21 +20,33 @@
Limit Memory
diff --git a/tests/Unit/InputWithSelectComponentTest.php b/tests/Unit/InputWithSelectComponentTest.php
new file mode 100644
index 000000000..2d7565cb0
--- /dev/null
+++ b/tests/Unit/InputWithSelectComponentTest.php
@@ -0,0 +1,77 @@
+required)->toBeFalse()
+ ->and($component->disabled)->toBeFalse()
+ ->and($component->readonly)->toBeFalse()
+ ->and($component->defaultClass)->toBe('input')
+ ->and($component->type)->toBe('text')
+ ->and($component->options)->toBe([]);
+});
+
+it('uses provided id', function () {
+ $component = new InputWithSelect(id: 'test-input-select');
+
+ expect($component->id)->toBe('test-input-select');
+});
+
+it('accepts options array', function () {
+ $options = ['b' => 'B', 'k' => 'KiB', 'm' => 'MiB', 'g' => 'GiB'];
+ $component = new InputWithSelect(options: $options);
+
+ expect($component->options)->toBe($options);
+});
+
+it('sets default option to first option when not provided', function () {
+ $options = ['b' => 'B', 'k' => 'KiB', 'm' => 'MiB'];
+ $component = new InputWithSelect(options: $options);
+
+ // defaultOption is set in render(), so we test the logic directly
+ if (is_null($component->defaultOption) && !empty($component->options)) {
+ $component->defaultOption = array_key_first($component->options);
+ }
+
+ expect($component->defaultOption)->toBe('b');
+});
+
+it('uses provided default option', function () {
+ $options = ['b' => 'B', 'k' => 'KiB', 'm' => 'MiB'];
+ $component = new InputWithSelect(options: $options, defaultOption: 'm');
+
+ expect($component->defaultOption)->toBe('m');
+});
+
+it('accepts min and max values', function () {
+ $component = new InputWithSelect(min: 0, max: 100);
+
+ expect($component->min)->toBe(0.0)
+ ->and($component->max)->toBe(100.0);
+});
+
+it('accepts type parameter', function () {
+ $component = new InputWithSelect(type: 'number');
+
+ expect($component->type)->toBe('number');
+});
+
+it('accepts authorization properties', function () {
+ $component = new InputWithSelect(
+ canGate: 'update',
+ canResource: 'resource',
+ autoDisable: false
+ );
+
+ expect($component->canGate)->toBe('update')
+ ->and($component->canResource)->toBe('resource')
+ ->and($component->autoDisable)->toBeFalse();
+});
+
+it('can be manually disabled', function () {
+ $component = new InputWithSelect(disabled: true);
+
+ expect($component->disabled)->toBeTrue();
+});