mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
Unified logs add facet count to filter options if operator is eq (#47121)
## Context Changes are mainly within the `FilterBar` component in UI patterns Supports a `count` option in `filterProperties` for `FilterBar` - which will render as a filter option but only if the operator is set to `eq`(opting for this as we don't have the numbers up front for the `neq` operator) <img width="389" height="319" alt="image" src="https://github.com/user-attachments/assets/1d6e7dae-5350-4110-910b-88a5517fbb6e" /> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Filter options in Unified Logs now display item counts for log type, method, level, and other enum filters, providing visibility into result distribution across filter choices. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
1 parent
e9a976aa74
commit
2207d7f665
4 files changed
+38
-9
No files matched your search
@@ -275,13 +275,20 @@ export const UnifiedLogs = () => {
|
||||
|
||||
// For hardcoded enum fields, keep the predefined options (facets only used for counts)
|
||||
if (field.value === 'log_type' || field.value === 'method' || field.value === 'level') {
|
||||
return field
|
||||
const fieldWithCounts = {
|
||||
...field,
|
||||
options: field.options.map((x) => {
|
||||
return { ...x, count: facetsField.rows.find((y) => y.value === x.value)?.total ?? 0 }
|
||||
}),
|
||||
}
|
||||
return fieldWithCounts
|
||||
}
|
||||
|
||||
// For dynamic fields, use faceted options
|
||||
const options: Option[] = facetsField.rows.map(({ value }) => ({
|
||||
const options: Option[] = facetsField.rows.map(({ value, total }) => ({
|
||||
label: `${value}`,
|
||||
value,
|
||||
count: total,
|
||||
}))
|
||||
|
||||
return { ...field, options }
|
||||
|
||||
@@ -25,7 +25,7 @@ export function CommandListItem({
|
||||
role="option"
|
||||
onClick={() => onSelect(item)}
|
||||
className={cn(
|
||||
'relative flex items-center justify-between gap-2 px-2 py-1.5 text-xs cursor-pointer select-none outline-hidden text-foreground',
|
||||
'relative flex items-center justify-between gap-2 px-2 h-[28px] text-xs cursor-pointer select-none outline-hidden text-foreground',
|
||||
isHighlighted && 'bg-surface-300',
|
||||
!isHighlighted && 'hover:bg-surface-200'
|
||||
)}
|
||||
@@ -35,6 +35,9 @@ export function CommandListItem({
|
||||
{includeIcon && item.icon}
|
||||
<span className="truncate">{getActionItemLabel(item)}</span>
|
||||
</span>
|
||||
{item.count !== undefined && (
|
||||
<code className="text-code-inline text-foreground-light">{item.count}</code>
|
||||
)}
|
||||
{item.operatorSymbol && <OperatorSymbolBadge symbol={item.operatorSymbol} />}
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -156,7 +156,14 @@ export function buildValueItems(
|
||||
} else if (loadingOptions[property.name]) {
|
||||
items.push({ value: 'loading', label: 'Loading options...' })
|
||||
} else if (Array.isArray(property.options)) {
|
||||
items.push(...getArrayOptionItems(property.options, inputValue, hasTypedSinceFocus))
|
||||
items.push(
|
||||
...getArrayOptionItems({
|
||||
options: property.options,
|
||||
inputValue,
|
||||
hasTypedSinceFocus,
|
||||
showCount: activeCondition?.operator === '=',
|
||||
})
|
||||
)
|
||||
} else if (propertyOptionsCache[property.name]) {
|
||||
items.push(...getCachedOptionItems(propertyOptionsCache[property.name].options))
|
||||
}
|
||||
@@ -164,11 +171,17 @@ export function buildValueItems(
|
||||
return items
|
||||
}
|
||||
|
||||
function getArrayOptionItems(
|
||||
options: any[],
|
||||
inputValue: string,
|
||||
function getArrayOptionItems({
|
||||
options,
|
||||
inputValue,
|
||||
hasTypedSinceFocus,
|
||||
showCount,
|
||||
}: {
|
||||
options: any[]
|
||||
inputValue: string
|
||||
hasTypedSinceFocus: boolean
|
||||
): MenuItem[] {
|
||||
showCount?: boolean
|
||||
}): MenuItem[] {
|
||||
const items: MenuItem[] = []
|
||||
const normalizedInput = inputValue.toLowerCase()
|
||||
|
||||
@@ -182,7 +195,11 @@ function getArrayOptionItems(
|
||||
}
|
||||
} else if (isFilterOptionObject(option)) {
|
||||
if (!shouldFilter || option.label.toLowerCase().includes(normalizedInput)) {
|
||||
items.push({ value: option.value, label: option.label })
|
||||
items.push({
|
||||
value: option.value,
|
||||
label: option.label,
|
||||
count: showCount ? option.count : undefined,
|
||||
})
|
||||
}
|
||||
} else if (isCustomOptionObject(option)) {
|
||||
if (!shouldFilter || (option.label?.toLowerCase().includes(normalizedInput) ?? true)) {
|
||||
|
||||
@@ -9,6 +9,7 @@ export type CustomOptionProps = {
|
||||
export type FilterOptionObject = {
|
||||
label: string
|
||||
value: string
|
||||
count?: number
|
||||
}
|
||||
|
||||
export type CustomOptionObject = {
|
||||
@@ -89,6 +90,7 @@ export type FilterBarAction = {
|
||||
export type MenuItem = {
|
||||
value: string
|
||||
label: string
|
||||
count?: number
|
||||
icon?: React.ReactNode
|
||||
isCustom?: boolean
|
||||
customOption?: (props: CustomOptionProps) => React.ReactElement
|
||||
|
||||
Reference in new issue
Block a user