@@ -27,9 +27,11 @@ interface Props {
2727 priorityCounts: Record <ReportPriority , number >
2828 assignees: Assignee []
2929 tags: Array <{ name: string ; count: number }>
30+ sourceCounts: { web: number ; expo: number ; ios: number ; android: number }
3031 selectedPriority: ReportPriority []
3132 selectedAssignee: string []
3233 selectedTags: string []
34+ selectedSource: string []
3335 sessionUserId: string
3436}
3537
@@ -38,6 +40,7 @@ const emit = defineEmits<{
3840 priority: [ReportPriority []]
3941 assignee: [string []]
4042 tag: [string []]
43+ source: [string []]
4144}>()
4245
4346const PRIORITIES: ReportPriority [] = [" urgent" , " high" , " normal" , " low" ]
@@ -60,6 +63,13 @@ function toggleTag(name: string) {
6063 const has = props .selectedTags .includes (name )
6164 emit (" tag" , has ? props .selectedTags .filter ((x ) => x !== name ) : [... props .selectedTags , name ])
6265}
66+ function toggleSource(token : string ) {
67+ const has = props .selectedSource .includes (token )
68+ emit (
69+ " source" ,
70+ has ? props .selectedSource .filter ((x ) => x !== token ) : [... props .selectedSource , token ],
71+ )
72+ }
6373
6474function isAssigneeSelected(a : Assignee ): boolean {
6575 if (a .id === null ) return props .selectedAssignee .includes (" unassigned" )
@@ -81,6 +91,12 @@ function priorityLabel(p: ReportPriority): string {
8191 return p .charAt (0 ).toUpperCase () + p .slice (1 )
8292}
8393
94+ const sourceItems = computed (() => [
95+ { token: " web" , label: " Web" , count: props .sourceCounts .web },
96+ { token: " ios" , label: " iOS" , count: props .sourceCounts .ios },
97+ { token: " android" , label: " Android" , count: props .sourceCounts .android },
98+ ])
99+
84100// Priority rows get a colored leading dot (urgent=red, high=orange,
85101// normal=teal, low=muted). That single dot carries more signal than a
86102// pill badge and pairs visually with the priority column in the table.
@@ -195,5 +211,41 @@ const priorityDot: Record<ReportPriority, string> = {
195211 </li >
196212 </ul >
197213 </section >
214+
215+ <section >
216+ <h3 class =" px-2 mb-2 text-xs font-semibold uppercase tracking-[0.14em] text-muted" >Source</h3 >
217+ <ul >
218+ <li v-for =" item in sourceItems" :key =" item.token" >
219+ <button
220+ type =" button"
221+ :aria-pressed =" selectedSource.includes(item.token)"
222+ class =" group w-full flex items-center gap-2 rounded-lg px-2.5 py-1.5 transition-colors"
223+ :class ="
224+ selectedSource.includes(item.token)
225+ ? 'bg-elevated text-default font-semibold'
226+ : 'text-muted hover:text-default hover:bg-elevated/60'
227+ "
228+ @click =" toggleSource(item.token)"
229+ >
230+ <span
231+ class =" size-1.5 rounded-full shrink-0"
232+ :class ="
233+ selectedSource.includes(item.token)
234+ ? 'bg-primary'
235+ : 'bg-transparent group-hover:bg-muted/60'
236+ "
237+ aria-hidden =" true"
238+ />
239+ <span class =" flex-1 text-left font-medium" >{{ item.label }}</span >
240+ <span
241+ class =" text-xs font-medium tabular-nums"
242+ :class =" selectedSource.includes(item.token) ? 'text-primary' : 'text-muted'"
243+ >
244+ {{ item.count }}
245+ </span >
246+ </button >
247+ </li >
248+ </ul >
249+ </section >
198250 </aside >
199251</template >
0 commit comments