feat(dedicated): filter drive bay options to chassis-compatible combos
Per-chassis page hides drive combos that require more bays than the
chassis has. R440 (4-bay) no longer shows 8× / 12× options; R640
(8-bay SFF) no longer shows 16× / 24×; R640 NVMe (10-bay) hides
16× NVMe.
Implementation:
- routes/marketing.php /dedicated-servers/{slug}: post-load filter
on configGroups. For any group whose name contains "Drive Bays",
parses the leading bay-count digit from each value's slug
(e.g. "8x8tb-hdd" → 8) and drops values where bay_count >
chassis features.bay_count. Non-quantity values (e.g. "none")
always pass through.
- ConfigOptionSeeder: dropped the now-redundant "(R740xd LFF
only)"/"(R740 16-bay only)" parentheticals from the labels —
the filter handles compatibility, the labels stay clean.
New test asserts:
- R440 (4 bays) drops 8× and 12× LFF combos
- R740xd LFF (12 bays) keeps all combos
- R640 NVMe (10 bays) drops 16× NVMe combo
13/13 dedicated tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -518,8 +518,8 @@ class ConfigOptionSeeder extends Seeder
|
|||||||
['label' => '4× 4 TB SATA HDD', 'value' => '4x4tb-hdd', 'monthly' => 48.00],
|
['label' => '4× 4 TB SATA HDD', 'value' => '4x4tb-hdd', 'monthly' => 48.00],
|
||||||
['label' => '2× 8 TB SATA HDD', 'value' => '2x8tb-hdd', 'monthly' => 40.00],
|
['label' => '2× 8 TB SATA HDD', 'value' => '2x8tb-hdd', 'monthly' => 40.00],
|
||||||
['label' => '4× 8 TB SATA HDD', 'value' => '4x8tb-hdd', 'monthly' => 80.00],
|
['label' => '4× 8 TB SATA HDD', 'value' => '4x8tb-hdd', 'monthly' => 80.00],
|
||||||
['label' => '8× 8 TB SATA HDD (R540 / R740xd LFF only)', 'value' => '8x8tb-hdd', 'monthly' => 160.00],
|
['label' => '8× 8 TB SATA HDD', 'value' => '8x8tb-hdd', 'monthly' => 160.00],
|
||||||
['label' => '12× 8 TB SATA HDD (R740xd LFF only)', 'value' => '12x8tb-hdd', 'monthly' => 240.00],
|
['label' => '12× 8 TB SATA HDD', 'value' => '12x8tb-hdd', 'monthly' => 240.00],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$gen14LffPlanSlugs = ['r440-4lff', 'r540-8lff', 'r740xd-12lff'];
|
$gen14LffPlanSlugs = ['r440-4lff', 'r540-8lff', 'r740xd-12lff'];
|
||||||
@@ -546,8 +546,8 @@ class ConfigOptionSeeder extends Seeder
|
|||||||
['label' => '2× 1.92 TB SATA SSD', 'value' => '2x1920gb-ssd', 'monthly' => 36.00],
|
['label' => '2× 1.92 TB SATA SSD', 'value' => '2x1920gb-ssd', 'monthly' => 36.00],
|
||||||
['label' => '4× 1.92 TB SATA SSD', 'value' => '4x1920gb-ssd', 'monthly' => 72.00],
|
['label' => '4× 1.92 TB SATA SSD', 'value' => '4x1920gb-ssd', 'monthly' => 72.00],
|
||||||
['label' => '8× 1.92 TB SATA SSD', 'value' => '8x1920gb-ssd', 'monthly' => 144.00],
|
['label' => '8× 1.92 TB SATA SSD', 'value' => '8x1920gb-ssd', 'monthly' => 144.00],
|
||||||
['label' => '16× 1.92 TB SATA SSD (R740 16-bay / R740xd 24-SFF only)', 'value' => '16x1920gb-ssd', 'monthly' => 288.00],
|
['label' => '16× 1.92 TB SATA SSD', 'value' => '16x1920gb-ssd', 'monthly' => 288.00],
|
||||||
['label' => '24× 1.92 TB SATA SSD (R740xd 24-SFF only)', 'value' => '24x1920gb-ssd', 'monthly' => 432.00],
|
['label' => '24× 1.92 TB SATA SSD', 'value' => '24x1920gb-ssd', 'monthly' => 432.00],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$gen14SffPlanSlugs = ['r640-8sff', 'r740-16sff', 'r740xd-24sff'];
|
$gen14SffPlanSlugs = ['r640-8sff', 'r740-16sff', 'r740xd-24sff'];
|
||||||
@@ -573,8 +573,8 @@ class ConfigOptionSeeder extends Seeder
|
|||||||
['label' => '4× 1 TB U.2 NVMe', 'value' => '4x1tb-nvme', 'monthly' => 88.00],
|
['label' => '4× 1 TB U.2 NVMe', 'value' => '4x1tb-nvme', 'monthly' => 88.00],
|
||||||
['label' => '2× 2 TB U.2 NVMe', 'value' => '2x2tb-nvme', 'monthly' => 96.00],
|
['label' => '2× 2 TB U.2 NVMe', 'value' => '2x2tb-nvme', 'monthly' => 96.00],
|
||||||
['label' => '4× 2 TB U.2 NVMe', 'value' => '4x2tb-nvme', 'monthly' => 192.00],
|
['label' => '4× 2 TB U.2 NVMe', 'value' => '4x2tb-nvme', 'monthly' => 192.00],
|
||||||
['label' => '8× 2 TB U.2 NVMe (R640 NVMe 10-bay / R740xd NVMe 24-bay)', 'value' => '8x2tb-nvme', 'monthly' => 384.00],
|
['label' => '8× 2 TB U.2 NVMe', 'value' => '8x2tb-nvme', 'monthly' => 384.00],
|
||||||
['label' => '16× 2 TB U.2 NVMe (R740xd NVMe 24-bay only)', 'value' => '16x2tb-nvme', 'monthly' => 768.00],
|
['label' => '16× 2 TB U.2 NVMe', 'value' => '16x2tb-nvme', 'monthly' => 768.00],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$gen14NvmePlanSlugs = ['r640-10nvme', 'r740xd-24nvme'];
|
$gen14NvmePlanSlugs = ['r640-10nvme', 'r740xd-24nvme'];
|
||||||
|
|||||||
@@ -114,6 +114,31 @@ Route::get('/dedicated-servers/{slug}', function (string $slug) {
|
|||||||
->orderBy('sort_order')
|
->orderBy('sort_order')
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
|
// Drive-bay combos are seeded with value slugs that start with the
|
||||||
|
// bay count (e.g. "8x8tb-hdd" → 8 bays). Filter out combos that
|
||||||
|
// don't fit this chassis so customers never see options that can't
|
||||||
|
// physically deploy on their build.
|
||||||
|
$bayCount = (int) ($plan->features['bay_count'] ?? 0);
|
||||||
|
if ($bayCount > 0) {
|
||||||
|
foreach ($configGroups as $group) {
|
||||||
|
if (! str_contains($group->name, 'Drive Bays')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach ($group->options as $option) {
|
||||||
|
$filtered = $option->values->filter(function ($value) use ($bayCount): bool {
|
||||||
|
if (preg_match('/^(\d+)x/', $value->value, $m)) {
|
||||||
|
return (int) $m[1] <= $bayCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'none' (and any other non-quantity value) always passes.
|
||||||
|
return true;
|
||||||
|
})->values();
|
||||||
|
|
||||||
|
$option->setRelation('values', $filtered);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Inertia::render('Marketing/DedicatedServerDetail', [
|
return Inertia::render('Marketing/DedicatedServerDetail', [
|
||||||
'plan' => $plan,
|
'plan' => $plan,
|
||||||
'configGroups' => $configGroups,
|
'configGroups' => $configGroups,
|
||||||
|
|||||||
@@ -133,6 +133,31 @@ test('seeder creates the 9 dedicated 14th-gen config groups', function (): void
|
|||||||
expect($names)->toContain('Dedicated 14th Gen — NVMe Drive Bays');
|
expect($names)->toContain('Dedicated 14th Gen — NVMe Drive Bays');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('drive bay options are filtered to those that fit chassis bay count', function (): void {
|
||||||
|
// R440 has 4 LFF bays — combos requiring more bays should be hidden.
|
||||||
|
$r440Response = $this->get('/dedicated-servers/r440-4lff');
|
||||||
|
$r440Groups = collect($r440Response->viewData('page')['props']['configGroups']);
|
||||||
|
$lff = $r440Groups->firstWhere('name', 'Dedicated 14th Gen — LFF Drive Bays');
|
||||||
|
$values = collect($lff['options'][0]['values'])->pluck('value')->all();
|
||||||
|
expect($values)->toContain('none', '2x4tb-hdd', '4x4tb-hdd', '2x8tb-hdd', '4x8tb-hdd');
|
||||||
|
expect($values)->not->toContain('8x8tb-hdd', '12x8tb-hdd'); // 8 and 12 bays don't fit in 4
|
||||||
|
|
||||||
|
// R740xd LFF has 12 bays — should see all combos.
|
||||||
|
$r740xdResponse = $this->get('/dedicated-servers/r740xd-12lff');
|
||||||
|
$r740xdGroups = collect($r740xdResponse->viewData('page')['props']['configGroups']);
|
||||||
|
$lff740 = $r740xdGroups->firstWhere('name', 'Dedicated 14th Gen — LFF Drive Bays');
|
||||||
|
$values740 = collect($lff740['options'][0]['values'])->pluck('value')->all();
|
||||||
|
expect($values740)->toContain('8x8tb-hdd', '12x8tb-hdd');
|
||||||
|
|
||||||
|
// R640 NVMe has 10 bays — 16× shouldn't fit but 8× should.
|
||||||
|
$r640Response = $this->get('/dedicated-servers/r640-10nvme');
|
||||||
|
$r640Groups = collect($r640Response->viewData('page')['props']['configGroups']);
|
||||||
|
$nvme = $r640Groups->firstWhere('name', 'Dedicated 14th Gen — NVMe Drive Bays');
|
||||||
|
$valuesNvme = collect($nvme['options'][0]['values'])->pluck('value')->all();
|
||||||
|
expect($valuesNvme)->toContain('8x2tb-nvme');
|
||||||
|
expect($valuesNvme)->not->toContain('16x2tb-nvme'); // 16 bays don't fit in 10
|
||||||
|
});
|
||||||
|
|
||||||
test('drive bay groups are attached to chassis by bay type', function (): void {
|
test('drive bay groups are attached to chassis by bay type', function (): void {
|
||||||
// LFF chassis should have LFF Drive Bays attached
|
// LFF chassis should have LFF Drive Bays attached
|
||||||
$r440 = Plan::where('slug', 'r440-4lff')->first();
|
$r440 = Plan::where('slug', 'r440-4lff')->first();
|
||||||
|
|||||||
Reference in New Issue
Block a user