fix: increase z-index of face detail navigation arrows
- Navigation arrows z-index increased from 10010 to 10100 - Fixes issue where modal overlay was covering the arrows - Left/right buttons now clickable in face detail modal
This commit is contained in:
@@ -1097,7 +1097,14 @@ const faceMoveTarget = ref('')
|
||||
const faceMoveNewGroupName = ref('')
|
||||
|
||||
// Cluster results (synced with store for cross-navigation persistence)
|
||||
const clusterResults = computed(() => clusterResultsCache.value[selectedFileUuid.value] || [])
|
||||
const clusterResults = computed(() => {
|
||||
const results = clusterResultsCache.value[selectedFileUuid.value] || []
|
||||
console.log('[clusterResults] cache for', selectedFileUuid.value, ':', results.length, 'groups')
|
||||
if (results.length > 0) {
|
||||
console.log('[clusterResults] first group:', JSON.stringify(results[0], null, 2))
|
||||
}
|
||||
return results
|
||||
})
|
||||
const clusterTracesMap = ref<Record<string, any>>({})
|
||||
const clusterRunning = computed(() => isClusterRunning(selectedFileUuid.value))
|
||||
|
||||
@@ -1131,6 +1138,10 @@ const faceGroups = computed(() => {
|
||||
}
|
||||
const defaultName = `group ${String(idx + 1).padStart(2, '0')}`
|
||||
if (!c.name) c.name = defaultName
|
||||
// Convert Person_X to Group_X for display
|
||||
if (c.name && c.name.startsWith('Person_')) {
|
||||
c.name = 'Group_' + c.name.substring(7)
|
||||
}
|
||||
const visibleTraceIds = ffFilterActive.value
|
||||
? traceIds.filter(tid => !ffHiddenTraces.value.has(tid))
|
||||
: traceIds
|
||||
@@ -1176,11 +1187,19 @@ const clusterDetailCluster = computed(() => {
|
||||
// Map trace_id → group name for Faces section
|
||||
const traceGroupMap = computed(() => {
|
||||
const map: Record<string, string> = {}
|
||||
console.log('[traceGroupMap] clusterResults:', clusterResults.value.length, 'groups')
|
||||
for (const c of clusterResults.value) {
|
||||
let name = c.name || ''
|
||||
// Convert Person_X to Group_X for display
|
||||
if (name.startsWith('Person_')) {
|
||||
name = 'Group_' + name.substring(7)
|
||||
}
|
||||
console.log('[traceGroupMap] cluster:', c.cluster_id, 'name:', name, 'trace_ids:', c.trace_ids)
|
||||
for (const tid of c.trace_ids || []) {
|
||||
map[String(tid)] = c.name
|
||||
map[String(tid)] = name
|
||||
}
|
||||
}
|
||||
console.log('[traceGroupMap] final map:', map)
|
||||
return map
|
||||
})
|
||||
|
||||
@@ -1218,7 +1237,25 @@ const facesTotalPages = computed(() => {
|
||||
})
|
||||
|
||||
function traceLabel(tr: any): string {
|
||||
const n = tr?.name || traceGroupMap.value[String(tr.trace_id)]
|
||||
// Prefer cluster name from clusterResultsCache
|
||||
const clusters = clusterResultsCache.value[selectedFileUuid.value] || []
|
||||
console.log('[traceLabel] trace_id:', tr.trace_id, 'clusters in cache:', clusters.length)
|
||||
if (clusters.length > 0) {
|
||||
console.log('[traceLabel] first cluster:', clusters[0])
|
||||
}
|
||||
for (const c of clusters) {
|
||||
if (c.trace_ids && c.trace_ids.includes(tr.trace_id)) {
|
||||
let name = c.name || ''
|
||||
// Convert Person_X to Group_X for display
|
||||
if (name.startsWith('Person_')) {
|
||||
name = 'Group_' + name.substring(7)
|
||||
}
|
||||
console.log('[traceLabel] Found cluster name:', name)
|
||||
return name
|
||||
}
|
||||
}
|
||||
const n = tr?.name
|
||||
console.log('[traceLabel] Fallback to:', n || t('people.section.unassigned'))
|
||||
return n || t('people.section.unassigned')
|
||||
}
|
||||
|
||||
@@ -2028,6 +2065,11 @@ async function loadClusterResults() {
|
||||
}
|
||||
const groups = results?.face_groups || results?.clusters || []
|
||||
const frames = results?.frames || []
|
||||
console.log('[loadClusterResults] groups:', groups.length, 'frames:', frames.length)
|
||||
if (frames.length > 0) {
|
||||
console.log('[loadClusterResults] first frame faces:', frames[0].faces)
|
||||
console.log('[loadClusterResults] first group:', groups[0])
|
||||
}
|
||||
// 統一 group_id → cluster_id, 並添加 group_uuid
|
||||
for (const g of groups) {
|
||||
if (g.group_id !== undefined && g.cluster_id === undefined) {
|
||||
@@ -2069,6 +2111,7 @@ async function loadClusterResults() {
|
||||
const cid = c.cluster_id || c.group_id
|
||||
c.member_faces = clusterFacesMap[cid] || []
|
||||
c.face_count = c.member_faces.length
|
||||
console.log(`[loadClusterResults] group ${c.name} (cid=${cid}): member_faces=${c.member_faces.length}`)
|
||||
c.trace_ids = Array.from(clusterTraceIdsMap[cid] || [])
|
||||
// Set representative_trace from representative_face
|
||||
if (c.representative_face?.face_id) {
|
||||
@@ -2083,7 +2126,10 @@ async function loadClusterResults() {
|
||||
}
|
||||
}
|
||||
if (groups.length) {
|
||||
console.log('[loadClusterResults] Calling setClusterResults with', groups.length, 'groups')
|
||||
console.log('[loadClusterResults] First group trace_ids:', groups[0]?.trace_ids)
|
||||
setClusterResults(fileUuid, groups)
|
||||
console.log('[loadClusterResults] After setClusterResults, cache:', clusterResultsCache.value[fileUuid]?.length)
|
||||
|
||||
// Load trace profiles for names in background (non-blocking)
|
||||
loadClusterNames(fileUuid, groups).catch(() => {})
|
||||
@@ -2749,7 +2795,7 @@ function closeClusterCtxMenu(e?: MouseEvent) {
|
||||
clusterCtxMenu.value.show = false
|
||||
}
|
||||
|
||||
function clusterCtxAction(action: string) {
|
||||
async function clusterCtxAction(action: string) {
|
||||
const c = clusterCtxMenu.value.cluster
|
||||
if (!c) return
|
||||
clusterCtxMenu.value.show = false
|
||||
@@ -2766,7 +2812,7 @@ function clusterCtxAction(action: string) {
|
||||
// Update trace profiles via API
|
||||
const traceIds = clusters[idx]?.trace_ids || []
|
||||
if (traceIds.length && selectedFileUuid.value) {
|
||||
updateTraceProfileGroup(selectedFileUuid.value, traceIds, { name })
|
||||
await updateTraceProfileGroup(selectedFileUuid.value, traceIds, { name })
|
||||
}
|
||||
}
|
||||
} else if (action === 'skip') {
|
||||
@@ -3297,24 +3343,75 @@ async function executeMerge(targetGroupId: string) {
|
||||
const sourceGroupIds = groupIds.filter(id => id !== targetGroupId)
|
||||
const sourceGroups = faceGroups.value.filter((c: any) => sourceGroupIds.includes(c.group_uuid))
|
||||
|
||||
const sourceGroupNames = sourceGroups.map(g => g.name).filter(Boolean)
|
||||
// Collect all trace_ids from source groups
|
||||
const allTraceIds: number[] = []
|
||||
for (const g of sourceGroups) {
|
||||
if (g.trace_ids) {
|
||||
allTraceIds.push(...g.trace_ids)
|
||||
}
|
||||
}
|
||||
|
||||
if (sourceGroupNames.length === 0) {
|
||||
alert('No valid source groups to merge')
|
||||
if (allTraceIds.length === 0) {
|
||||
alert('No traces to merge')
|
||||
return
|
||||
}
|
||||
|
||||
if (!confirm(`Merge ${sourceGroupNames.length} group(s) into "${targetGroupName}"?`)) return
|
||||
if (!confirm(`Merge ${sourceGroups.length} group(s) with ${allTraceIds.length} trace(s) into "${targetGroupName}"?`)) return
|
||||
|
||||
operationLoading.value = true
|
||||
operationMessage.value = `Merging ${sourceGroupNames.length} group(s)...`
|
||||
operationMessage.value = `Merging ${sourceGroups.length} group(s)...`
|
||||
|
||||
try {
|
||||
const result = await apiCall('merge_groups', {
|
||||
fileUuid: selectedFileUuid.value,
|
||||
sourceGroups: sourceGroupNames,
|
||||
targetGroupName: targetGroupName
|
||||
})
|
||||
// Update all source traces to target group name
|
||||
console.log('[executeMerge] Updating trace_ids:', allTraceIds, 'to name:', targetGroupName)
|
||||
|
||||
// 1. Update trace_profiles via API
|
||||
const result = await updateTraceProfileGroup(selectedFileUuid.value, allTraceIds, { name: targetGroupName })
|
||||
console.log('[executeMerge] API Result:', result)
|
||||
|
||||
// 2. Update clusterResultsCache locally
|
||||
const clusters = getClusterResults(selectedFileUuid.value)
|
||||
|
||||
// Find target cluster
|
||||
const targetCluster = clusters.find((c: any) => c.name === targetGroupName || c.cluster_id === targetGroup.cluster_id)
|
||||
|
||||
if (targetCluster) {
|
||||
// Add source trace_ids to target cluster (avoid duplicates)
|
||||
if (!targetCluster.trace_ids) targetCluster.trace_ids = []
|
||||
for (const tid of allTraceIds) {
|
||||
if (!targetCluster.trace_ids.includes(tid)) {
|
||||
targetCluster.trace_ids.push(tid)
|
||||
}
|
||||
}
|
||||
targetCluster.trace_count = targetCluster.trace_ids.length
|
||||
}
|
||||
|
||||
// Remove trace_ids from source clusters
|
||||
for (const sourceGroup of sourceGroups) {
|
||||
const sourceCluster = clusters.find((c: any) => c.cluster_id === sourceGroup.cluster_id || c.group_id === sourceGroup.group_id)
|
||||
if (sourceCluster && sourceCluster.trace_ids) {
|
||||
sourceCluster.trace_ids = sourceCluster.trace_ids.filter((tid: number) => !allTraceIds.includes(tid))
|
||||
sourceCluster.trace_count = sourceCluster.trace_ids.length
|
||||
}
|
||||
}
|
||||
|
||||
// Remove empty source clusters
|
||||
const nonEmptyClusters = clusters.filter((c: any) => !sourceGroups.some(sg =>
|
||||
(c.cluster_id === sg.cluster_id || c.group_id === sg.group_id) && (!c.trace_ids || c.trace_ids.length === 0)
|
||||
))
|
||||
|
||||
setClusterResults(selectedFileUuid.value, nonEmptyClusters)
|
||||
console.log('[executeMerge] Updated cache')
|
||||
|
||||
// Reload thumbnails for updated clusters
|
||||
for (const c of nonEmptyClusters) {
|
||||
if (c.trace_ids && c.trace_ids.length > 0) {
|
||||
const repId = c.representative_trace || c.trace_ids[0]
|
||||
if (repId) {
|
||||
loadTraceThumb({ trace_id: repId, file_uuid: selectedFileUuid.value, best_face_id: 0 })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (result?.success) {
|
||||
@@ -4121,7 +4218,7 @@ h1 { margin: 0; }
|
||||
|
||||
/* Face detail side navigation arrows */
|
||||
.ms-fs-nav-arrow {
|
||||
position: fixed; top: 50%; transform: translateY(-50%); z-index: 10010;
|
||||
position: fixed; top: 50%; transform: translateY(-50%); z-index: 10100;
|
||||
width: 44px; height: 44px; border-radius: 50%; border: none;
|
||||
background: rgba(0,0,0,0.5); color: #fff; cursor: pointer;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
|
||||
Reference in New Issue
Block a user