feat: add category filter dropdown to service selection

Add a searchable category dropdown filter on the new resource page to help users filter services by category.

Features:
- Category dropdown positioned next to search input
- Auto-focus on search field when dropdown opens
- Case-insensitive category filtering
- Proper acronym formatting (AI, API, CI, etc. displayed in uppercase)
- Loading/disabled state while categories are being fetched
- Category search/filter within dropdown
- Alphabetical sorting (case-insensitive)

Backend changes:
- Extract unique categories from service templates
- Handle comma-separated categories
- Format common acronyms to uppercase
- Case-insensitive natural sorting

Frontend changes:
- Searchable dropdown component with Alpine.js
- Category filter integration with existing search
- Disabled state placeholder during loading
- Auto-focus behavior for better UX

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Andras Bacsai
2025-10-23 21:02:12 +02:00
parent 2d3a980594
commit 4ef0a50e09
2 changed files with 106 additions and 10 deletions

View File

@@ -102,6 +102,36 @@ class Select extends Component
: asset($default_logo),
] + (array) $service;
})->all();
// Extract unique categories from services
$categories = collect($services)
->pluck('category')
->filter()
->unique()
->map(function ($category) {
// Handle multiple categories separated by comma
if (str_contains($category, ',')) {
return collect(explode(',', $category))->map(fn ($cat) => trim($cat));
}
return [$category];
})
->flatten()
->unique()
->map(function ($category) {
// Format common acronyms to uppercase
$acronyms = ['ai', 'api', 'ci', 'cd', 'cms', 'crm', 'erp', 'iot', 'vpn', 'vps', 'dns', 'ssl', 'tls', 'ssh', 'ftp', 'http', 'https', 'smtp', 'imap', 'pop3', 'sql', 'nosql', 'json', 'xml', 'yaml', 'csv', 'pdf', 'sms', 'mfa', '2fa', 'oauth', 'saml', 'jwt', 'rest', 'soap', 'grpc', 'graphql', 'websocket', 'webrtc', 'p2p', 'b2b', 'b2c', 'seo', 'sem', 'ppc', 'roi', 'kpi', 'ui', 'ux', 'ide', 'sdk', 'api', 'cli', 'gui', 'cdn', 'ddos', 'dos', 'xss', 'csrf', 'sqli', 'rce', 'lfi', 'rfi', 'ssrf', 'xxe', 'idor', 'owasp', 'gdpr', 'hipaa', 'pci', 'dss', 'iso', 'nist', 'cve', 'cwe', 'cvss'];
$lower = strtolower($category);
if (in_array($lower, $acronyms)) {
return strtoupper($category);
}
return $category;
})
->sort(SORT_NATURAL | SORT_FLAG_CASE)
->values()
->all();
$gitBasedApplications = [
[
'id' => 'public',
@@ -202,6 +232,7 @@ class Select extends Component
return [
'services' => $services,
'categories' => $categories,
'gitBasedApplications' => $gitBasedApplications,
'dockerBasedApplications' => $dockerBasedApplications,
'databases' => $databases,