Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<!-- Author: mrveiss -->
<!-- Issue #566 - Code Intelligence Dashboard -->
<!-- Issue #4037 - Virtual scrolling for large findings tables (500+ rows) -->
<!-- Issue #4035 - Add debounce to search filters -->

<template>
<div class="findings-table">
Expand Down Expand Up @@ -110,13 +111,13 @@
</template>

<script setup lang="ts">
import { ref, computed } from 'vue'
import { ref, computed, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useVirtualList } from '@/composables/useVirtualList'
import { useDebounce } from '@/composables/useDebounce'
import type { Severity } from '@/types/codeIntelligence'

const { t } = useI18n()
const containerRef = ref<HTMLElement | null>(null)

interface Finding {
severity: Severity
Expand All @@ -143,19 +144,24 @@ const selectedSeverities = ref<Severity[]>([...severityLevels])
const searchQuery = ref('')
const expandedRow = ref<number | null>(null)

const filteredFindings = computed(() => {
// Debounce search query for performance (Issue #4035)
// Reduces unnecessary filtering operations during rapid typing
const debouncedSearchQuery = useDebounce(searchQuery, 350)

const filteredFindings = computed<(Finding & { id: string })[]>(() => {
return props.findings
.filter(f => {
const matchesSeverity = selectedSeverities.value.includes(f.severity)
const matchesSearch = searchQuery.value === '' ||
f.file_path.toLowerCase().includes(searchQuery.value.toLowerCase()) ||
f.message.toLowerCase().includes(searchQuery.value.toLowerCase())
// Use debounced search query to prevent filtering on every keystroke
const matchesSearch = debouncedSearchQuery.value === '' ||
f.file_path.toLowerCase().includes(debouncedSearchQuery.value.toLowerCase()) ||
f.message.toLowerCase().includes(debouncedSearchQuery.value.toLowerCase())
return matchesSeverity && matchesSearch
})
.map((f, idx) => ({
...f,
id: f.id || `finding_${idx}`
}))
})) as (Finding & { id: string })[]
})

// Virtual scrolling composable - Issue #4037
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*
* Issue #874: Frontend Collaborative Session UI (#608 Phase 6)
* Issue #3985: Replace hardcoded mock users with real API
* Issue #4035: Add debounce to search filter
*
* Modal dialog for inviting users to collaborate on a session.
* Supports role selection and email-based invitations.
Expand All @@ -14,6 +15,7 @@ import { ref, computed, onMounted } from 'vue'
import { useI18n } from 'vue-i18n'
import { useSessionCollaboration } from '@/composables/useSessionCollaboration'
import { useChatStore } from '@/stores/useChatStore'
import { useDebounce } from '@/composables/useDebounce'
import { getApiBase } from '@/config/ssot-config'
import apiClient from '@/utils/ApiClient'
import { createLogger } from '@/utils/debugUtils'
Expand Down Expand Up @@ -66,21 +68,18 @@ const errorMessage = ref<string | null>(null)
const loading = ref(false)
const users = ref<User[]>([])

// Debounce search query for performance (Issue #4035)
// Reduces unnecessary filtering operations during rapid typing
const debouncedSearchQuery = useDebounce(searchQuery, 350)

// Fetch users from API
const fetchUsers = async () => {
loading.value = true
errorMessage.value = null

try {
const response = await apiClient.get<UserListResponse>(
`${getApiBase()}/user-management/users`,
{
params: {
limit: 100,
offset: 0,
include_inactive: false
}
}
`${getApiBase()}/user-management/users?limit=100&offset=0&include_inactive=false`
)

if (response && response.users && Array.isArray(response.users)) {
Expand Down Expand Up @@ -111,11 +110,11 @@ onMounted(() => {
}
})

// Filter users by search query
// Filter users by debounced search query
const filteredUsers = computed(() => {
if (!searchQuery.value) return users.value
if (!debouncedSearchQuery.value) return users.value

const query = searchQuery.value.toLowerCase()
const query = debouncedSearchQuery.value.toLowerCase()
return users.value.filter(user =>
user.username.toLowerCase().includes(query) ||
user.email.toLowerCase().includes(query) ||
Expand Down
Loading