mirror of
https://github.com/supabase/supabase.git
synced 2026-10-10 11:55:05 +03:00
Added preset searching, custom queries, new logs loading
This commit is contained in:
1 parent
8710928923
commit
8aded7968c
3 files changed
+50
-20
No files matched your search
@@ -5,23 +5,33 @@ import Panel from 'components/to-be-cleaned/Panel'
|
||||
interface Props {
|
||||
onRefresh?: () => void
|
||||
onSearch?: (query: string) => void
|
||||
onCustomClick?: () => void
|
||||
isLoading: boolean
|
||||
children?: JSX.Element
|
||||
heading?: JSX.Element
|
||||
searchValue?: string
|
||||
presets?: {
|
||||
label: string
|
||||
onClick: () => void
|
||||
}[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs control panel header + wrapper
|
||||
*/
|
||||
const LogPanel = ({ onRefresh, isLoading, heading, children, onSearch }: Props) => (
|
||||
const LogPanel = ({ onRefresh, isLoading, searchValue, children, onSearch, onCustomClick, presets = [] }: Props) => (
|
||||
<Panel
|
||||
title={
|
||||
<div className="flex items-center justify-between w-full" >
|
||||
<Button type="secondary">Recent - All</Button>
|
||||
<div className="flex flex-row gap-x-4">
|
||||
{presets.map(p =>
|
||||
<Button key={p.label} type="secondary" onClick={p.onClick}>{p.label}</Button>
|
||||
)}
|
||||
<Button type="primary" onClick={onCustomClick}>Custom Query</Button>
|
||||
</div>
|
||||
<div className="flex flex-row gap-x-4">
|
||||
<Input className="max-w-32" placeholder="Search" onChange={e => {
|
||||
if(onSearch) onSearch(e.target.value)
|
||||
}} />
|
||||
if (onSearch) onSearch(e.target.value)
|
||||
}} value={searchValue} />
|
||||
<Button
|
||||
type="outline"
|
||||
loading={isLoading}
|
||||
@@ -30,6 +40,7 @@ const LogPanel = ({ onRefresh, isLoading, heading, children, onSearch }: Props)
|
||||
>
|
||||
Refresh
|
||||
</Button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ export const LogPage = () => {
|
||||
const [search, setSearch] = useState<string>('')
|
||||
const [queryParams, setQueryParams] = useState<string>('')
|
||||
const [where, setWhere] = useState<string>('')
|
||||
const [mode, setMode] = useState<'simple' | 'custom'>('simple')
|
||||
const [latestRefresh, setLatestRefresh] = useState<string>(new Date().toISOString())
|
||||
|
||||
const title = LOG_TYPE_LABEL_MAPPING[type as string]
|
||||
@@ -53,7 +54,7 @@ export const LogPage = () => {
|
||||
}
|
||||
const qs = new URLSearchParams(params).toString()
|
||||
setQueryParams(qs)
|
||||
}, [search, where])
|
||||
}, [search, where, type])
|
||||
|
||||
const countKey = `${API_URL}/projects/${ref}/logs?${queryParams}&count=true&period_start=${latestRefresh}`
|
||||
const { data: countData } = useSWR<{ data: [CountData] | []; error?: any }>(countKey, get, {
|
||||
@@ -66,24 +67,39 @@ export const LogPage = () => {
|
||||
setLatestRefresh(new Date().toISOString())
|
||||
mutate()
|
||||
}
|
||||
const handleModeToggle = () => {
|
||||
if (mode === 'simple') {
|
||||
setMode('custom')
|
||||
setSearch('')
|
||||
} else {
|
||||
setMode('simple')
|
||||
}
|
||||
}
|
||||
return (
|
||||
<SettingsLayout title={title} className="p-4 space-y-4">
|
||||
<LogPanel isLoading={isLoading} onRefresh={handleRefresh} onSearch={debouncedSearch} />
|
||||
<div className="h-24">
|
||||
<CodeEditor
|
||||
className="p-4"
|
||||
hideLineNumbers
|
||||
id={'logs-where-editor'}
|
||||
language="pgsql"
|
||||
defaultValue={where}
|
||||
onInputChange={(v) => debouncedWhere(v || '')}
|
||||
onInputRun={handleRefresh}
|
||||
/>
|
||||
</div>
|
||||
<LogPanel
|
||||
presets={[
|
||||
{ label: "Recent - All", onClick: () => setSearch('') },
|
||||
{ label: "Recent - Errors", onClick: () => setSearch('[Ee]rror|\\s[45][0-9][0-9]\\s') },
|
||||
]}
|
||||
searchValue={search}
|
||||
onCustomClick={handleModeToggle} isLoading={isLoading} onRefresh={handleRefresh} onSearch={debouncedSearch} />
|
||||
{mode === 'custom' &&
|
||||
<div>
|
||||
<CodeEditor
|
||||
className="p-4 h-24"
|
||||
hideLineNumbers
|
||||
id={'logs-where-editor'}
|
||||
language="pgsql"
|
||||
defaultValue={where}
|
||||
onInputChange={(v) => debouncedWhere(v || '')}
|
||||
onInputRun={handleRefresh}
|
||||
/>
|
||||
</div>}
|
||||
{error && (
|
||||
<Typography.Text className="text-center w-full block">Could not fetch data</Typography.Text>
|
||||
)}
|
||||
{newCount && newCount > 0 && <Button onClick={handleRefresh}>Load new logs</Button>}
|
||||
{newCount ? <Button type="dashed" onClick={handleRefresh} block>Load new logs</Button> : null}
|
||||
<LogTable data={logData} />
|
||||
</SettingsLayout>
|
||||
)
|
||||
|
||||
@@ -154,7 +154,10 @@ test("where clause will trigger a log refresh", async () => {
|
||||
return { data: [] }
|
||||
})
|
||||
const { container } = render(<LogPage />)
|
||||
const editor = container.querySelector('.monaco-editor');
|
||||
let editor = container.querySelector('.monaco-editor');
|
||||
expect(editor).toBeFalsy()
|
||||
userEvent.click(screen.getAllByText("Custom Query"))
|
||||
editor = container.querySelector('.monaco-editor');
|
||||
userEvent.type(editor, "metadata.field = something")
|
||||
await waitFor(() => {
|
||||
expect(get).toHaveBeenCalledWith(expect.stringContaining("where"))
|
||||
|
||||
Reference in new issue
Block a user