feat: add local search filter to My Apps view
Adds a search input to the Apps page that filters installed apps by title, description, or app ID. Styled consistently with the Marketplace search bar. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f6cce7c82e
commit
a49dd83c5c
@ -79,7 +79,7 @@ After getting Claude Max OAuth working on the live server, hardening the deploy
|
||||
- **Change**: Compare `get_app_config()` port mappings with nginx proxies. Add missing nginx proxies for: Grafana (3000), Jellyfin (8096), Uptime Kuma (3001), Portainer (9000), OnlyOffice (9980). Add to both HTTP and HTTPS blocks. Verify `extract_lan_address()` correctness.
|
||||
- **Verify**: Each app launches correctly from Apps page
|
||||
|
||||
### Task 14: Local search within Apps view
|
||||
### Task 14: Local search within Apps view [DONE]
|
||||
- **Files**: `neode-ui/src/views/Apps.vue`
|
||||
- **Change**: Add search input with `ref('')`. Filter `sortedPackageEntries` by query against `manifest.title` and `manifest.description.short`. Style like Marketplace search.
|
||||
- **Verify**: Type in search — only matching apps shown
|
||||
|
||||
@ -5,6 +5,16 @@
|
||||
<p class="text-white/70">Manage your installed applications</p>
|
||||
</div>
|
||||
|
||||
<!-- Search Bar -->
|
||||
<div class="mb-4">
|
||||
<input
|
||||
v-model="searchQuery"
|
||||
type="text"
|
||||
placeholder="Search installed apps..."
|
||||
class="w-full px-4 py-3 md:py-2 bg-white/10 border border-white/20 rounded-lg text-white placeholder-white/50 focus:outline-none focus:border-white/40 transition-colors"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Empty State - This should never show since we always show dummy apps -->
|
||||
<div v-if="false" class="text-center py-16 pb-6">
|
||||
<div class="glass-card p-12 max-w-md mx-auto">
|
||||
@ -22,10 +32,15 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- No Results -->
|
||||
<div v-if="filteredPackageEntries.length === 0 && searchQuery" class="text-center py-12">
|
||||
<p class="text-white/70">No apps matching "{{ searchQuery }}"</p>
|
||||
</div>
|
||||
|
||||
<!-- Apps Grid (alphabetically by title, stable across run state) -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 pb-6">
|
||||
<div
|
||||
v-for="[id, pkg] in sortedPackageEntries"
|
||||
v-for="[id, pkg] in filteredPackageEntries"
|
||||
:key="id"
|
||||
data-controller-container
|
||||
:data-controller-launch="canLaunch(pkg) ? '' : undefined"
|
||||
@ -181,6 +196,9 @@ import { useModalKeyboard } from '@/composables/useModalKeyboard'
|
||||
const router = useRouter()
|
||||
const store = useAppStore()
|
||||
|
||||
// Search
|
||||
const searchQuery = ref('')
|
||||
|
||||
// Track loading states for each app action
|
||||
const loadingActions = ref<Record<string, boolean>>({})
|
||||
|
||||
@ -199,6 +217,16 @@ const sortedPackageEntries = computed(() => {
|
||||
)
|
||||
})
|
||||
|
||||
const filteredPackageEntries = computed(() => {
|
||||
if (!searchQuery.value) return sortedPackageEntries.value
|
||||
const q = searchQuery.value.toLowerCase()
|
||||
return sortedPackageEntries.value.filter(([id, pkg]) =>
|
||||
(pkg.manifest?.title ?? '').toLowerCase().includes(q) ||
|
||||
(pkg.manifest?.description?.short ?? '').toLowerCase().includes(q) ||
|
||||
id.toLowerCase().includes(q)
|
||||
)
|
||||
})
|
||||
|
||||
const uninstallModal = ref({
|
||||
show: false,
|
||||
appId: '',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user