|
|
@@ -38,7 +38,6 @@ import {
|
|
|
TooltipTrigger,
|
|
|
} from '@/components/ui/tooltip'
|
|
|
|
|
|
-import { LOG_TYPE_ALL_VALUE, LOG_TYPE_FILTERS } from '../constants'
|
|
|
import { buildSearchParams } from '../lib/filter'
|
|
|
import { getDefaultTimeRange } from '../lib/utils'
|
|
|
import type { CommonLogFilters } from '../types'
|
|
|
@@ -49,37 +48,29 @@ import {
|
|
|
LogsFilterInput,
|
|
|
LogsFilterToolbar,
|
|
|
} from './logs-filter-toolbar'
|
|
|
+import {
|
|
|
+ LOG_TYPE_ALL_VALUE,
|
|
|
+ LOG_TYPE_ENUM,
|
|
|
+ LOG_TYPE_FILTERS,
|
|
|
+} from '../constants'
|
|
|
import { useLogsViewScope, useUsageLogsContext } from './usage-logs-provider'
|
|
|
|
|
|
const route = getRouteApi('/_authenticated/usage-logs/$section')
|
|
|
-
|
|
|
-type LogTypeValue = (typeof LOG_TYPE_FILTERS)[number]['value']
|
|
|
-const logTypeValueSet = new Set<string>(
|
|
|
- LOG_TYPE_FILTERS.map((type) => type.value)
|
|
|
+const auditLogTypeItems = LOG_TYPE_FILTERS.filter(
|
|
|
+ (type) => type.value !== String(LOG_TYPE_ENUM.CONSUME)
|
|
|
)
|
|
|
+const auditLogTypeValues = new Set(auditLogTypeItems.map((type) => type.value))
|
|
|
|
|
|
type CommonLogDraft = {
|
|
|
sourceKey: string
|
|
|
filters: CommonLogFilters
|
|
|
- logType: LogTypeValue
|
|
|
-}
|
|
|
-
|
|
|
-function isLogTypeValue(value: string): value is LogTypeValue {
|
|
|
- return logTypeValueSet.has(value)
|
|
|
-}
|
|
|
-
|
|
|
-function getLogTypeValue(value: unknown): LogTypeValue {
|
|
|
- return Array.isArray(value) &&
|
|
|
- value.length === 1 &&
|
|
|
- typeof value[0] === 'string' &&
|
|
|
- isLogTypeValue(value[0])
|
|
|
- ? value[0]
|
|
|
- : LOG_TYPE_ALL_VALUE
|
|
|
}
|
|
|
|
|
|
function buildSearchSourceKey(values: {
|
|
|
startTime?: unknown
|
|
|
endTime?: unknown
|
|
|
+ consumeType?: unknown
|
|
|
+ type?: unknown
|
|
|
channel?: unknown
|
|
|
model?: unknown
|
|
|
token?: unknown
|
|
|
@@ -87,11 +78,12 @@ function buildSearchSourceKey(values: {
|
|
|
username?: unknown
|
|
|
requestId?: unknown
|
|
|
upstreamRequestId?: unknown
|
|
|
- type?: unknown
|
|
|
}) {
|
|
|
return [
|
|
|
values.startTime,
|
|
|
values.endTime,
|
|
|
+ values.consumeType,
|
|
|
+ Array.isArray(values.type) ? values.type.join(',') : values.type,
|
|
|
values.channel,
|
|
|
values.model,
|
|
|
values.token,
|
|
|
@@ -99,12 +91,19 @@ function buildSearchSourceKey(values: {
|
|
|
values.username,
|
|
|
values.requestId,
|
|
|
values.upstreamRequestId,
|
|
|
- Array.isArray(values.type) ? values.type.join(',') : values.type,
|
|
|
]
|
|
|
.map((value) => String(value ?? ''))
|
|
|
.join('\u001f')
|
|
|
}
|
|
|
|
|
|
+function getAuditLogType(value: unknown): string {
|
|
|
+ const candidate = Array.isArray(value) ? value[0] : value
|
|
|
+ if (typeof candidate === 'string' && auditLogTypeValues.has(candidate)) {
|
|
|
+ return candidate
|
|
|
+ }
|
|
|
+ return LOG_TYPE_ALL_VALUE
|
|
|
+}
|
|
|
+
|
|
|
interface CommonLogsFilterBarProps<TData> {
|
|
|
table: Table<TData>
|
|
|
}
|
|
|
@@ -125,6 +124,8 @@ export function CommonLogsFilterBar<TData>(
|
|
|
const sourceValues = {
|
|
|
startTime: searchParams.startTime,
|
|
|
endTime: searchParams.endTime,
|
|
|
+ consumeType: searchParams.consumeType,
|
|
|
+ type: searchParams.type,
|
|
|
channel: searchParams.channel,
|
|
|
model: searchParams.model,
|
|
|
token: searchParams.token,
|
|
|
@@ -132,13 +133,14 @@ export function CommonLogsFilterBar<TData>(
|
|
|
username: searchParams.username,
|
|
|
requestId: searchParams.requestId,
|
|
|
upstreamRequestId: searchParams.upstreamRequestId,
|
|
|
- type: searchParams.type,
|
|
|
}
|
|
|
const filters: CommonLogFilters = {
|
|
|
startTime: searchParams.startTime
|
|
|
? new Date(searchParams.startTime)
|
|
|
: start,
|
|
|
endTime: searchParams.endTime ? new Date(searchParams.endTime) : end,
|
|
|
+ consumeType: searchParams.consumeType || 'all',
|
|
|
+ logType: getAuditLogType(searchParams.type),
|
|
|
channel: searchParams.channel || undefined,
|
|
|
model: searchParams.model || undefined,
|
|
|
token: searchParams.token || undefined,
|
|
|
@@ -150,11 +152,12 @@ export function CommonLogsFilterBar<TData>(
|
|
|
return {
|
|
|
sourceKey: buildSearchSourceKey(sourceValues),
|
|
|
filters,
|
|
|
- logType: getLogTypeValue(searchParams.type),
|
|
|
}
|
|
|
}, [
|
|
|
searchParams.startTime,
|
|
|
searchParams.endTime,
|
|
|
+ searchParams.consumeType,
|
|
|
+ searchParams.type,
|
|
|
searchParams.channel,
|
|
|
searchParams.model,
|
|
|
searchParams.token,
|
|
|
@@ -162,13 +165,13 @@ export function CommonLogsFilterBar<TData>(
|
|
|
searchParams.username,
|
|
|
searchParams.requestId,
|
|
|
searchParams.upstreamRequestId,
|
|
|
- searchParams.type,
|
|
|
])
|
|
|
const [draft, setDraft] = useState<CommonLogDraft>(() => searchState)
|
|
|
const activeDraft =
|
|
|
draft.sourceKey === searchState.sourceKey ? draft : searchState
|
|
|
const filters = activeDraft.filters
|
|
|
- const logType = activeDraft.logType
|
|
|
+ const params = route.useParams()
|
|
|
+ const section = params.section === 'audit' ? 'audit' : 'common'
|
|
|
|
|
|
const handleChange = useCallback(
|
|
|
(field: keyof CommonLogFilters, value: Date | string | undefined) => {
|
|
|
@@ -178,7 +181,6 @@ export function CommonLogsFilterBar<TData>(
|
|
|
return {
|
|
|
sourceKey: searchState.sourceKey,
|
|
|
filters: { ...base.filters, [field]: value },
|
|
|
- logType: base.logType,
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
@@ -189,42 +191,48 @@ export function CommonLogsFilterBar<TData>(
|
|
|
const filterParams = buildSearchParams(filters, 'common')
|
|
|
navigate({
|
|
|
to: '/usage-logs/$section',
|
|
|
- params: { section: 'common' },
|
|
|
+ params: { section },
|
|
|
search: {
|
|
|
...filterParams,
|
|
|
- type: [logType],
|
|
|
+ ...(section === 'audit' && {
|
|
|
+ type: [filters.logType || LOG_TYPE_ALL_VALUE],
|
|
|
+ }),
|
|
|
page: 1,
|
|
|
},
|
|
|
})
|
|
|
queryClient.invalidateQueries({ queryKey: ['logs'] })
|
|
|
queryClient.invalidateQueries({ queryKey: ['usage-logs-stats'] })
|
|
|
- }, [filters, logType, navigate, queryClient])
|
|
|
+ }, [filters, navigate, queryClient, section])
|
|
|
|
|
|
const handleReset = useCallback(() => {
|
|
|
const { start, end } = getDefaultTimeRange()
|
|
|
- const resetFilters: CommonLogFilters = { startTime: start, endTime: end }
|
|
|
+ const resetFilters: CommonLogFilters = {
|
|
|
+ startTime: start,
|
|
|
+ endTime: end,
|
|
|
+ consumeType: 'all',
|
|
|
+ logType: LOG_TYPE_ALL_VALUE,
|
|
|
+ }
|
|
|
const resetSearch = {
|
|
|
- type: [LOG_TYPE_ALL_VALUE],
|
|
|
startTime: start.getTime(),
|
|
|
endTime: end.getTime(),
|
|
|
}
|
|
|
setDraft({
|
|
|
sourceKey: buildSearchSourceKey(resetSearch),
|
|
|
filters: resetFilters,
|
|
|
- logType: LOG_TYPE_ALL_VALUE,
|
|
|
})
|
|
|
|
|
|
navigate({
|
|
|
to: '/usage-logs/$section',
|
|
|
- params: { section: 'common' },
|
|
|
+ params: { section },
|
|
|
search: {
|
|
|
page: 1,
|
|
|
...resetSearch,
|
|
|
+ ...(section === 'audit' && { type: [LOG_TYPE_ALL_VALUE] }),
|
|
|
},
|
|
|
})
|
|
|
queryClient.invalidateQueries({ queryKey: ['logs'] })
|
|
|
queryClient.invalidateQueries({ queryKey: ['usage-logs-stats'] })
|
|
|
- }, [navigate, queryClient])
|
|
|
+ }, [navigate, queryClient, section])
|
|
|
|
|
|
const handleKeyDown = useCallback(
|
|
|
(e: React.KeyboardEvent) => {
|
|
|
@@ -233,6 +241,8 @@ export function CommonLogsFilterBar<TData>(
|
|
|
[handleApply]
|
|
|
)
|
|
|
|
|
|
+ const showConsumeTypeFilter = section === 'common'
|
|
|
+ const showAuditLogTypeFilter = section === 'audit'
|
|
|
const hasExpandedFilters =
|
|
|
!!filters.token ||
|
|
|
!!filters.username ||
|
|
|
@@ -240,9 +250,13 @@ export function CommonLogsFilterBar<TData>(
|
|
|
!!filters.requestId ||
|
|
|
!!filters.upstreamRequestId
|
|
|
|
|
|
- const hasTypeFilter = logType !== LOG_TYPE_ALL_VALUE
|
|
|
const hasAdditionalFilters =
|
|
|
- !!filters.model || !!filters.group || hasTypeFilter || hasExpandedFilters
|
|
|
+ (showConsumeTypeFilter && (filters.consumeType ?? 'all') !== 'all') ||
|
|
|
+ (section === 'audit' &&
|
|
|
+ (filters.logType || LOG_TYPE_ALL_VALUE) !== LOG_TYPE_ALL_VALUE) ||
|
|
|
+ !!filters.model ||
|
|
|
+ !!filters.group ||
|
|
|
+ hasExpandedFilters
|
|
|
|
|
|
const expandedFilterCount = [
|
|
|
filters.token,
|
|
|
@@ -252,17 +266,19 @@ export function CommonLogsFilterBar<TData>(
|
|
|
filters.upstreamRequestId,
|
|
|
].filter(Boolean).length
|
|
|
const sensitiveType = sensitiveVisible ? 'text' : 'password'
|
|
|
- const logTypeItems = useMemo(
|
|
|
- () =>
|
|
|
- LOG_TYPE_FILTERS.map((type) => ({
|
|
|
- value: type.value,
|
|
|
- label: t(type.label),
|
|
|
- })),
|
|
|
- [t]
|
|
|
- )
|
|
|
- const logTypeLabel =
|
|
|
- logTypeItems.find((type) => type.value === logType)?.label ?? t('All Types')
|
|
|
-
|
|
|
+ const consumeTypeItems = [
|
|
|
+ { value: 'all', label: t('All') },
|
|
|
+ { value: 'platform', label: t('Platform') },
|
|
|
+ { value: 'user', label: t('User') },
|
|
|
+ ]
|
|
|
+ const consumeTypeLabel =
|
|
|
+ consumeTypeItems.find((item) => item.value === filters.consumeType)?.label ??
|
|
|
+ t('All')
|
|
|
+ const auditLogTypeLabel =
|
|
|
+ t(
|
|
|
+ auditLogTypeItems.find((item) => item.value === filters.logType)?.label ??
|
|
|
+ 'All Types'
|
|
|
+ )
|
|
|
const statsBar = (
|
|
|
<div className='flex flex-wrap items-center gap-2'>
|
|
|
<CommonLogsStats />
|
|
|
@@ -301,6 +317,63 @@ export function CommonLogsFilterBar<TData>(
|
|
|
/>
|
|
|
</LogsFilterField>
|
|
|
)
|
|
|
+ const consumeTypeFilter = (
|
|
|
+ <LogsFilterField>
|
|
|
+ <Select
|
|
|
+ items={consumeTypeItems}
|
|
|
+ value={filters.consumeType || 'all'}
|
|
|
+ onValueChange={(value) => {
|
|
|
+ handleChange(
|
|
|
+ 'consumeType',
|
|
|
+ value === 'platform' || value === 'user' ? value : 'all'
|
|
|
+ )
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <SelectTrigger>
|
|
|
+ <SelectValue>{consumeTypeLabel}</SelectValue>
|
|
|
+ </SelectTrigger>
|
|
|
+ <SelectContent alignItemWithTrigger={false}>
|
|
|
+ <SelectGroup>
|
|
|
+ {consumeTypeItems.map((item) => (
|
|
|
+ <SelectItem key={item.value} value={item.value}>
|
|
|
+ {item.label}
|
|
|
+ </SelectItem>
|
|
|
+ ))}
|
|
|
+ </SelectGroup>
|
|
|
+ </SelectContent>
|
|
|
+ </Select>
|
|
|
+ </LogsFilterField>
|
|
|
+ )
|
|
|
+ const auditLogTypeFilter = (
|
|
|
+ <LogsFilterField>
|
|
|
+ <Select
|
|
|
+ items={auditLogTypeItems.map((item) => ({
|
|
|
+ value: item.value,
|
|
|
+ label: t(item.label),
|
|
|
+ }))}
|
|
|
+ value={filters.logType || LOG_TYPE_ALL_VALUE}
|
|
|
+ onValueChange={(value) => {
|
|
|
+ handleChange(
|
|
|
+ 'logType',
|
|
|
+ auditLogTypeValues.has(value) ? value : LOG_TYPE_ALL_VALUE
|
|
|
+ )
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <SelectTrigger>
|
|
|
+ <SelectValue>{auditLogTypeLabel}</SelectValue>
|
|
|
+ </SelectTrigger>
|
|
|
+ <SelectContent alignItemWithTrigger={false}>
|
|
|
+ <SelectGroup>
|
|
|
+ {auditLogTypeItems.map((item) => (
|
|
|
+ <SelectItem key={item.value} value={item.value}>
|
|
|
+ {t(item.label)}
|
|
|
+ </SelectItem>
|
|
|
+ ))}
|
|
|
+ </SelectGroup>
|
|
|
+ </SelectContent>
|
|
|
+ </Select>
|
|
|
+ </LogsFilterField>
|
|
|
+ )
|
|
|
const modelFilter = (
|
|
|
<LogsFilterField>
|
|
|
<LogsFilterInput
|
|
|
@@ -322,42 +395,6 @@ export function CommonLogsFilterBar<TData>(
|
|
|
/>
|
|
|
</LogsFilterField>
|
|
|
)
|
|
|
- const typeFilter = (
|
|
|
- <LogsFilterField>
|
|
|
- <Select
|
|
|
- items={logTypeItems}
|
|
|
- value={logType}
|
|
|
- onValueChange={(value) => {
|
|
|
- const nextLogType =
|
|
|
- value !== null && isLogTypeValue(value) ? value : LOG_TYPE_ALL_VALUE
|
|
|
- setDraft((current) => {
|
|
|
- const base =
|
|
|
- current.sourceKey === searchState.sourceKey
|
|
|
- ? current
|
|
|
- : searchState
|
|
|
- return {
|
|
|
- sourceKey: searchState.sourceKey,
|
|
|
- filters: base.filters,
|
|
|
- logType: nextLogType,
|
|
|
- }
|
|
|
- })
|
|
|
- }}
|
|
|
- >
|
|
|
- <SelectTrigger>
|
|
|
- <SelectValue>{logTypeLabel}</SelectValue>
|
|
|
- </SelectTrigger>
|
|
|
- <SelectContent alignItemWithTrigger={false}>
|
|
|
- <SelectGroup>
|
|
|
- {LOG_TYPE_FILTERS.map((type) => (
|
|
|
- <SelectItem key={type.value} value={type.value}>
|
|
|
- {t(type.label)}
|
|
|
- </SelectItem>
|
|
|
- ))}
|
|
|
- </SelectGroup>
|
|
|
- </SelectContent>
|
|
|
- </Select>
|
|
|
- </LogsFilterField>
|
|
|
- )
|
|
|
const advancedFilters = (
|
|
|
<>
|
|
|
<LogsFilterField>
|
|
|
@@ -417,9 +454,10 @@ export function CommonLogsFilterBar<TData>(
|
|
|
primaryFilters={
|
|
|
<>
|
|
|
{dateRangeFilter}
|
|
|
+ {showConsumeTypeFilter && consumeTypeFilter}
|
|
|
+ {showAuditLogTypeFilter && auditLogTypeFilter}
|
|
|
{modelFilter}
|
|
|
{groupFilter}
|
|
|
- {typeFilter}
|
|
|
</>
|
|
|
}
|
|
|
advancedFilters={advancedFilters}
|
|
|
@@ -428,12 +466,21 @@ export function CommonLogsFilterBar<TData>(
|
|
|
<>
|
|
|
{modelFilter}
|
|
|
{groupFilter}
|
|
|
- {typeFilter}
|
|
|
{advancedFilters}
|
|
|
</>
|
|
|
}
|
|
|
mobileFilterCount={
|
|
|
- [filters.model, filters.group, hasTypeFilter].filter(Boolean).length +
|
|
|
+ [
|
|
|
+ showConsumeTypeFilter && filters.consumeType !== 'all'
|
|
|
+ ? filters.consumeType
|
|
|
+ : undefined,
|
|
|
+ showAuditLogTypeFilter &&
|
|
|
+ (filters.logType || LOG_TYPE_ALL_VALUE) !== LOG_TYPE_ALL_VALUE
|
|
|
+ ? filters.logType
|
|
|
+ : undefined,
|
|
|
+ filters.model,
|
|
|
+ filters.group,
|
|
|
+ ].filter(Boolean).length +
|
|
|
expandedFilterCount
|
|
|
}
|
|
|
hasAdvancedActiveFilters={hasExpandedFilters}
|