Skip to content

Commit 1082e55

Browse files
authored
improvement(logs): improved logs search (#1985)
* improvement(logs): improved logs search * more * ack PR comments
1 parent 948b657 commit 1082e55

File tree

17 files changed

+1237
-1360
lines changed

17 files changed

+1237
-1360
lines changed

apps/sim/app/api/logs/export/route.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,12 @@ export async function GET(request: NextRequest) {
6060
let conditions: SQL | undefined = eq(workflow.workspaceId, params.workspaceId)
6161

6262
if (params.level && params.level !== 'all') {
63-
conditions = and(conditions, eq(workflowExecutionLogs.level, params.level))
63+
const levels = params.level.split(',').filter(Boolean)
64+
if (levels.length === 1) {
65+
conditions = and(conditions, eq(workflowExecutionLogs.level, levels[0]))
66+
} else if (levels.length > 1) {
67+
conditions = and(conditions, inArray(workflowExecutionLogs.level, levels))
68+
}
6469
}
6570

6671
if (params.workflowIds) {

apps/sim/app/api/logs/route.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,14 @@ export async function GET(request: NextRequest) {
126126
// Build additional conditions for the query
127127
let conditions: SQL | undefined
128128

129-
// Filter by level
129+
// Filter by level (supports comma-separated for OR conditions)
130130
if (params.level && params.level !== 'all') {
131-
conditions = and(conditions, eq(workflowExecutionLogs.level, params.level))
131+
const levels = params.level.split(',').filter(Boolean)
132+
if (levels.length === 1) {
133+
conditions = and(conditions, eq(workflowExecutionLogs.level, levels[0]))
134+
} else if (levels.length > 1) {
135+
conditions = and(conditions, inArray(workflowExecutionLogs.level, levels))
136+
}
132137
}
133138

134139
// Filter by specific workflow IDs

apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/controls.tsx

Lines changed: 20 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { ReactNode } from 'react'
2-
import { Loader2, RefreshCw, Search } from 'lucide-react'
2+
import { ArrowUp, Loader2, RefreshCw, Search } from 'lucide-react'
33
import { Button, Tooltip } from '@/components/emcn'
44
import { Input } from '@/components/ui/input'
55
import { cn } from '@/lib/utils'
@@ -16,7 +16,6 @@ export function Controls({
1616
viewMode,
1717
setViewMode,
1818
searchComponent,
19-
showExport = true,
2019
onExport,
2120
}: {
2221
searchQuery?: string
@@ -72,6 +71,23 @@ export function Controls({
7271
)}
7372

7473
<div className='ml-auto flex flex-shrink-0 items-center gap-3'>
74+
{viewMode !== 'dashboard' && (
75+
<Tooltip.Root>
76+
<Tooltip.Trigger asChild>
77+
<Button
78+
variant='ghost'
79+
onClick={onExport}
80+
className='h-9 w-9 p-0 hover:bg-secondary'
81+
aria-label='Export CSV'
82+
>
83+
<ArrowUp className='h-4 w-4' />
84+
<span className='sr-only'>Export CSV</span>
85+
</Button>
86+
</Tooltip.Trigger>
87+
<Tooltip.Content>Export CSV</Tooltip.Content>
88+
</Tooltip.Root>
89+
)}
90+
7591
<Tooltip.Root>
7692
<Tooltip.Trigger asChild>
7793
<Button
@@ -81,42 +97,16 @@ export function Controls({
8197
disabled={isRefetching}
8298
>
8399
{isRefetching ? (
84-
<Loader2 className='h-5 w-5 animate-spin' />
100+
<Loader2 className='h-4 w-4 animate-spin' />
85101
) : (
86-
<RefreshCw className='h-5 w-5' />
102+
<RefreshCw className='h-4 w-4' />
87103
)}
88104
<span className='sr-only'>Refresh</span>
89105
</Button>
90106
</Tooltip.Trigger>
91107
<Tooltip.Content>{isRefetching ? 'Refreshing...' : 'Refresh'}</Tooltip.Content>
92108
</Tooltip.Root>
93109

94-
<Tooltip.Root>
95-
<Tooltip.Trigger asChild>
96-
<Button
97-
variant='ghost'
98-
onClick={onExport}
99-
className='h-9 w-9 p-0 hover:bg-secondary'
100-
aria-label='Export CSV'
101-
>
102-
<svg
103-
xmlns='http://www.w3.org/2000/svg'
104-
viewBox='0 0 24 24'
105-
fill='none'
106-
stroke='currentColor'
107-
strokeWidth='2'
108-
className='h-5 w-5'
109-
>
110-
<path d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4' />
111-
<polyline points='7 10 12 15 17 10' />
112-
<line x1='12' y1='15' x2='12' y2='3' />
113-
</svg>
114-
<span className='sr-only'>Export CSV</span>
115-
</Button>
116-
</Tooltip.Trigger>
117-
<Tooltip.Content>Export CSV</Tooltip.Content>
118-
</Tooltip.Root>
119-
120110
<div className='inline-flex h-9 items-center rounded-[11px] border bg-card p-1 shadow-sm'>
121111
<Button
122112
variant='ghost'

apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/kpis.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,25 @@ export interface AggregateMetrics {
99
export function KPIs({ aggregate }: { aggregate: AggregateMetrics }) {
1010
return (
1111
<div className='mb-2 grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4'>
12-
<div className='border bg-card p-4 shadow-sm'>
12+
<div className='rounded-[11px] border bg-card p-4 shadow-sm'>
1313
<div className='text-muted-foreground text-xs'>Total executions</div>
1414
<div className='mt-1 font-[440] text-[22px] leading-6'>
1515
{aggregate.totalExecutions.toLocaleString()}
1616
</div>
1717
</div>
18-
<div className='border bg-card p-4 shadow-sm'>
18+
<div className='rounded-[11px] border bg-card p-4 shadow-sm'>
1919
<div className='text-muted-foreground text-xs'>Success rate</div>
2020
<div className='mt-1 font-[440] text-[22px] leading-6'>
2121
{aggregate.successRate.toFixed(1)}%
2222
</div>
2323
</div>
24-
<div className='border bg-card p-4 shadow-sm'>
24+
<div className='rounded-[11px] border bg-card p-4 shadow-sm'>
2525
<div className='text-muted-foreground text-xs'>Failed executions</div>
2626
<div className='mt-1 font-[440] text-[22px] leading-6'>
2727
{aggregate.failedExecutions.toLocaleString()}
2828
</div>
2929
</div>
30-
<div className='border bg-card p-4 shadow-sm'>
30+
<div className='rounded-[11px] border bg-card p-4 shadow-sm'>
3131
<div className='text-muted-foreground text-xs'>Active workflows</div>
3232
<div className='mt-1 font-[440] text-[22px] leading-6'>{aggregate.activeWorkflows}</div>
3333
</div>

apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/line-chart.tsx

Lines changed: 43 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -174,55 +174,48 @@ export function LineChart({
174174
ref={containerRef}
175175
className='w-full overflow-hidden rounded-[11px] border bg-card p-4 shadow-sm'
176176
>
177-
<div className='mb-3 flex items-center justify-between'>
178-
<div className='flex items-center gap-3'>
179-
<h4 className='font-medium text-foreground text-sm'>{label}</h4>
180-
{allSeries.length > 1 && (
181-
<div className='flex items-center gap-2'>
182-
{scaledSeries.slice(1).map((s) => {
183-
const isActive = activeSeriesId ? activeSeriesId === s.id : true
184-
const isHovered = hoverSeriesId === s.id
185-
const dimmed = activeSeriesId ? !isActive : false
186-
return (
187-
<button
188-
key={`legend-${s.id}`}
189-
type='button'
190-
aria-pressed={activeSeriesId === s.id}
191-
aria-label={`Toggle ${s.label}`}
192-
className='inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 text-[10px]'
193-
style={{
194-
color: s.color,
195-
opacity: dimmed ? 0.4 : isHovered ? 1 : 0.9,
196-
border: '1px solid hsl(var(--border))',
197-
background: 'transparent',
198-
}}
199-
onMouseEnter={() => setHoverSeriesId(s.id || null)}
200-
onMouseLeave={() => setHoverSeriesId((prev) => (prev === s.id ? null : prev))}
201-
onKeyDown={(e) => {
202-
if (e.key === 'Enter' || e.key === ' ') {
203-
e.preventDefault()
204-
setActiveSeriesId((prev) => (prev === s.id ? null : s.id || null))
205-
}
206-
}}
207-
onClick={() =>
177+
<div className='mb-3 flex items-center gap-3'>
178+
<h4 className='font-medium text-foreground text-sm'>{label}</h4>
179+
{allSeries.length > 1 && (
180+
<div className='flex items-center gap-2'>
181+
{scaledSeries.slice(1).map((s) => {
182+
const isActive = activeSeriesId ? activeSeriesId === s.id : true
183+
const isHovered = hoverSeriesId === s.id
184+
const dimmed = activeSeriesId ? !isActive : false
185+
return (
186+
<button
187+
key={`legend-${s.id}`}
188+
type='button'
189+
aria-pressed={activeSeriesId === s.id}
190+
aria-label={`Toggle ${s.label}`}
191+
className='inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 text-[10px]'
192+
style={{
193+
color: s.color,
194+
opacity: dimmed ? 0.4 : isHovered ? 1 : 0.9,
195+
border: '1px solid hsl(var(--border))',
196+
background: 'transparent',
197+
}}
198+
onMouseEnter={() => setHoverSeriesId(s.id || null)}
199+
onMouseLeave={() => setHoverSeriesId((prev) => (prev === s.id ? null : prev))}
200+
onKeyDown={(e) => {
201+
if (e.key === 'Enter' || e.key === ' ') {
202+
e.preventDefault()
208203
setActiveSeriesId((prev) => (prev === s.id ? null : s.id || null))
209204
}
210-
>
211-
<span
212-
aria-hidden='true'
213-
className='inline-block h-[6px] w-[6px] rounded-full'
214-
style={{ backgroundColor: s.color }}
215-
/>
216-
<span style={{ color: 'hsl(var(--muted-foreground))' }}>{s.label}</span>
217-
</button>
218-
)
219-
})}
220-
</div>
221-
)}
222-
</div>
223-
{currentHoverDate ? (
224-
<div className='text-[10px] text-muted-foreground'>{currentHoverDate}</div>
225-
) : null}
205+
}}
206+
onClick={() => setActiveSeriesId((prev) => (prev === s.id ? null : s.id || null))}
207+
>
208+
<span
209+
aria-hidden='true'
210+
className='inline-block h-[6px] w-[6px] rounded-full'
211+
style={{ backgroundColor: s.color }}
212+
/>
213+
<span style={{ color: 'hsl(var(--muted-foreground))' }}>{s.label}</span>
214+
</button>
215+
)
216+
})}
217+
</div>
218+
)}
226219
</div>
227220
<div className='relative' style={{ width, height }}>
228221
<svg
@@ -556,6 +549,9 @@ export function LineChart({
556549
className='pointer-events-none absolute rounded-md bg-background/80 px-2 py-1 font-medium text-[11px] shadow-sm ring-1 ring-border backdrop-blur'
557550
style={{ left, top }}
558551
>
552+
{currentHoverDate && (
553+
<div className='mb-1 text-[10px] text-muted-foreground'>{currentHoverDate}</div>
554+
)}
559555
{toDisplay.map((s) => {
560556
const seriesIndex = allSeries.findIndex((x) => x.id === s.id)
561557
const val = allSeries[seriesIndex]?.data?.[hoverIndex]?.value

0 commit comments

Comments
 (0)