mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 01:45:10 +03:00
warehouse fixes (#29212)
* fix clicking on sidebar item opening it * update filters after curl is used * fix refresh not using latest date * add fallback when result is empty * fix not showing latest results when pressing refresh * cleanup * Update apps/studio/components/interfaces/DataWarehouse/WarehouseCollectionDetail.tsx Co-authored-by: Charis <26616127+charislam@users.noreply.github.com> * simplify copy, comment out search temporarily --------- Co-authored-by: Charis <26616127+charislam@users.noreply.github.com>
This commit is contained in:
1 parent
93053bbb07
commit
2ab2f0e26b
5 files changed
+63
-57
No files matched your search
@@ -20,28 +20,27 @@ import { DatetimeHelper } from '../Settings/Logs/Logs.types'
|
||||
import dayjs from 'dayjs'
|
||||
import { useKeyboardShortcuts } from 'components/grid/components/common/Hooks'
|
||||
|
||||
const djs = dayjs()
|
||||
const INTERVALS: DatetimeHelper[] = [
|
||||
{
|
||||
text: 'Last hour',
|
||||
calcFrom: () => djs.subtract(1, 'hour').toISOString(),
|
||||
calcTo: () => djs.toISOString(),
|
||||
calcFrom: () => dayjs().subtract(1, 'hour').toISOString(),
|
||||
calcTo: () => dayjs().toISOString(),
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
text: 'Last 12 hours',
|
||||
calcFrom: () => djs.subtract(12, 'hour').toISOString(),
|
||||
calcTo: () => djs.toISOString(),
|
||||
calcFrom: () => dayjs().subtract(12, 'hour').toISOString(),
|
||||
calcTo: () => dayjs().toISOString(),
|
||||
},
|
||||
{
|
||||
text: 'Last day',
|
||||
calcFrom: () => djs.subtract(1, 'day').toISOString(),
|
||||
calcTo: () => djs.toISOString(),
|
||||
calcFrom: () => dayjs().subtract(1, 'day').toISOString(),
|
||||
calcTo: () => dayjs().toISOString(),
|
||||
},
|
||||
{
|
||||
text: 'Last 7 days',
|
||||
calcFrom: () => djs.subtract(7, 'day').toISOString(),
|
||||
calcTo: () => djs.toISOString(),
|
||||
calcFrom: () => dayjs().subtract(7, 'day').toISOString(),
|
||||
calcTo: () => dayjs().toISOString(),
|
||||
},
|
||||
]
|
||||
|
||||
@@ -57,51 +56,43 @@ export const WarehouseCollectionDetail = () => {
|
||||
{ projectRef },
|
||||
{ enabled: hasWarehouse }
|
||||
)
|
||||
const collection = (collections || []).find((c) => c.token === collectionToken)
|
||||
const [params, setParams] = useState({
|
||||
sql: ``,
|
||||
})
|
||||
const collection = collections?.find((c) => c.token === collectionToken)
|
||||
const [search, setSearch] = useState('')
|
||||
|
||||
const [filters, setFilters] = useState({
|
||||
limit: 100,
|
||||
offset: 0,
|
||||
search: '',
|
||||
interval: {
|
||||
to: INTERVALS[0].calcTo(),
|
||||
from: INTERVALS[0].calcFrom(),
|
||||
to: INTERVALS[0].calcTo,
|
||||
from: INTERVALS[0].calcFrom,
|
||||
},
|
||||
})
|
||||
const [sql, setSQL] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
if (collection) {
|
||||
const from = filters.interval?.from
|
||||
const to = filters.interval?.to
|
||||
const from = filters.interval.from()
|
||||
const to = filters.interval.to()
|
||||
|
||||
const sql = `select id, timestamp, event_message from \`${collection.name}\`
|
||||
const sql = `select id, timestamp from \`${collection.name}\`
|
||||
where timestamp >= TIMESTAMP('${from}')
|
||||
${to ? `and timestamp <= TIMESTAMP('${to}')` : ''}
|
||||
and event_message like '%${filters.search}%'
|
||||
and timestamp <= TIMESTAMP('${to}')
|
||||
order by timestamp desc limit ${filters.limit} offset ${filters.offset}
|
||||
`
|
||||
|
||||
setParams((prevParams) => ({
|
||||
...prevParams,
|
||||
sql,
|
||||
}))
|
||||
setSQL(sql)
|
||||
}
|
||||
}, [collection, filters])
|
||||
}, [filters.interval, filters.limit, filters.offset, collection])
|
||||
|
||||
const {
|
||||
isLoading: queryLoading,
|
||||
data: queryData,
|
||||
refetch,
|
||||
isError,
|
||||
isRefetching,
|
||||
} = useWarehouseQueryQuery(
|
||||
{ ref: projectRef, sql: params.sql },
|
||||
{ ref: projectRef, sql },
|
||||
{
|
||||
enabled: !!params.sql && hasWarehouse,
|
||||
enabled: !!sql && hasWarehouse,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -128,14 +119,20 @@ order by timestamp desc limit ${filters.limit} offset ${filters.offset}
|
||||
|
||||
const isLoading = queryLoading || collectionsLoading || isRefetching
|
||||
|
||||
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
|
||||
e.preventDefault()
|
||||
setFilters({ ...filters, search })
|
||||
refetch()
|
||||
function refreshResults(e?: React.FormEvent<HTMLFormElement>) {
|
||||
e?.preventDefault()
|
||||
setFilters({
|
||||
...filters,
|
||||
search,
|
||||
interval: {
|
||||
to: () => dayjs().toISOString(),
|
||||
from: () => filters.interval.from() || dayjs().subtract(1, 'hour').toISOString(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const queryUrl = `/project/${projectRef}/logs/explorer?q=${encodeURIComponent(
|
||||
params.sql || ''
|
||||
sql || ''
|
||||
)}&source=warehouse`
|
||||
|
||||
useKeyboardShortcuts(
|
||||
@@ -163,7 +160,7 @@ order by timestamp desc limit ${filters.limit} offset ${filters.offset}
|
||||
<LoadingOpacity active={isLoading}>
|
||||
<div className="flex flex-col w-full">
|
||||
<div className="flex justify-between items-center h-12 px-5">
|
||||
<form onSubmit={handleSubmit} className="flex items-center gap-2">
|
||||
<form onSubmit={refreshResults} className="flex items-center gap-2">
|
||||
<h2 className="text-foreground-light max-w-60 truncate" title={collection?.name}>
|
||||
{collection?.name}
|
||||
</h2>
|
||||
@@ -183,7 +180,7 @@ order by timestamp desc limit ${filters.limit} offset ${filters.offset}
|
||||
Refresh <KeyboardShortcut>R</KeyboardShortcut>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<Input
|
||||
{/* <Input
|
||||
type="search"
|
||||
id="search-input"
|
||||
className="w-52"
|
||||
@@ -191,17 +188,17 @@ order by timestamp desc limit ${filters.limit} offset ${filters.offset}
|
||||
placeholder="Search by event message"
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
/>
|
||||
/> */}
|
||||
<DatePickers
|
||||
to={filters.interval?.to}
|
||||
from={filters.interval?.from}
|
||||
to={filters.interval?.to()}
|
||||
from={filters.interval?.from()}
|
||||
helpers={INTERVALS}
|
||||
onChange={(e) =>
|
||||
setFilters({
|
||||
...filters,
|
||||
interval: {
|
||||
to: e.to || '',
|
||||
from: e.from || '',
|
||||
to: () => e.to || '',
|
||||
from: () => e.from || '',
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -231,7 +228,7 @@ order by timestamp desc limit ${filters.limit} offset ${filters.offset}
|
||||
open={testDialogOpen}
|
||||
onOpenChange={setTestDialogOpen}
|
||||
onSubmit={() => {
|
||||
refetch()
|
||||
refreshResults()
|
||||
setTestDialogOpen(false)
|
||||
}}
|
||||
/>
|
||||
@@ -252,22 +249,26 @@ order by timestamp desc limit ${filters.limit} offset ${filters.offset}
|
||||
projectRef={projectRef}
|
||||
isLoading={isLoading}
|
||||
data={results}
|
||||
params={params}
|
||||
params={{ sql }}
|
||||
maxHeight="calc(100vh - 139px)"
|
||||
showHeader={false}
|
||||
emptyState={
|
||||
<ProductEmptyState
|
||||
title="No events found"
|
||||
size="large"
|
||||
ctaButtonLabel="Send test event"
|
||||
onClickCta={() => setTestDialogOpen(true)}
|
||||
>
|
||||
<>
|
||||
<p>
|
||||
No events match your current search criteria. <br />
|
||||
Try adjusting your filters or send a test event to populate this collection.
|
||||
</p>
|
||||
</>
|
||||
<ProductEmptyState title="No events found" size="large">
|
||||
<div className="space-y-4">
|
||||
<p>Try adjusting your filters, send a test event or refresh the results.</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
onClick={() => {
|
||||
setTestDialogOpen(true)
|
||||
}}
|
||||
>
|
||||
Send test event
|
||||
</Button>
|
||||
<Button type="outline" onClick={() => refreshResults()}>
|
||||
Refresh
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</ProductEmptyState>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -99,6 +99,9 @@ export const WarehouseMenuItem = ({ item }: Props) => {
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
}}
|
||||
loading={isLoading}
|
||||
type="text"
|
||||
className="px-1 opacity-50 hover:opacity-100 !bg-transparent"
|
||||
|
||||
@@ -92,7 +92,7 @@ const LogSelection = ({
|
||||
switch (queryType) {
|
||||
case 'warehouse':
|
||||
if (!warehouseQueryData) return null
|
||||
return <DefaultPreviewSelectionRenderer log={warehouseQueryData.result[0]} />
|
||||
return <DefaultPreviewSelectionRenderer log={warehouseQueryData.result?.[0] || {}} />
|
||||
case 'api':
|
||||
if (!fullLog) return null
|
||||
if (!fullLog.metadata) return <DefaultPreviewSelectionRenderer log={fullLog} />
|
||||
@@ -148,7 +148,7 @@ const LogSelection = ({
|
||||
|
||||
const rawLog = useMemo(() => {
|
||||
if (queryType === 'warehouse') {
|
||||
return warehouseQueryData?.result[0]
|
||||
return warehouseQueryData?.result?.[0] || {}
|
||||
}
|
||||
return fullLog || partialLog
|
||||
}, [queryType, warehouseQueryData, fullLog, partialLog])
|
||||
|
||||
@@ -103,6 +103,7 @@ const LogsLayout = ({ title, children }: PropsWithChildren<LogsLayoutProps>) =>
|
||||
{collectionQueryEnabled && collectionsLoading ? (
|
||||
<GenericSkeletonLoader />
|
||||
) : (
|
||||
collections?.length &&
|
||||
collections?.map((item) => (
|
||||
<WarehouseMenuItem item={item} key={item.id + '-collection-item'} />
|
||||
))
|
||||
|
||||
@@ -201,6 +201,7 @@ export const CodeBlock = ({
|
||||
e.preventDefault()
|
||||
return false
|
||||
}}
|
||||
suppressContentEditableWarning={true}
|
||||
>
|
||||
{codeValue}
|
||||
</SyntaxHighlighter>
|
||||
|
||||
Reference in new issue
Block a user