Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ function LineChartComponent({
)}
style={{ width, height }}
>
<p className='text-muted-foreground text-sm'>No data</p>
<p className='text-[var(--text-muted)] text-sm'>No data</p>
</div>
)
}
Expand All @@ -256,7 +256,7 @@ function LineChartComponent({
>
{!hasExternalWrapper && (
<div className='mb-3 flex items-center gap-3'>
<h4 className='font-medium text-foreground text-sm'>{label}</h4>
<h4 className='font-medium text-[var(--text-primary)] text-sm'>{label}</h4>
{allSeries.length > 1 && (
<div className='flex items-center gap-2'>
{scaledSeries.slice(1).map((s) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client'

import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { memo, useCallback, useMemo, useRef, useState } from 'react'
import { Loader2 } from 'lucide-react'
import { useParams } from 'next/navigation'
import { useShallow } from 'zustand/react/shallow'
Expand Down Expand Up @@ -441,10 +441,13 @@ function DashboardInner({ stats, isLoading, error }: DashboardProps) {
[]
)

useEffect(() => {
setSelectedSegments((prev) => (Object.keys(prev).length > 0 ? {} : prev))
setLastAnchorIndices((prev) => (Object.keys(prev).length > 0 ? {} : prev))
}, [stats, timeRange, workflowIds, searchQuery])
const resetKey = `${JSON.stringify(stats?.workflows?.map((w) => w.workflowId))}-${timeRange}-${workflowIds.join(',')}-${searchQuery}`
const prevResetKeyRef = useRef(resetKey)
if (resetKey !== prevResetKeyRef.current) {
prevResetKeyRef.current = resetKey
if (Object.keys(selectedSegments).length > 0) setSelectedSegments({})
if (Object.keys(lastAnchorIndices).length > 0) setLastAnchorIndices({})
}

if (isLoading) {
return <DashboardSkeleton />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,13 +296,10 @@ export const LogDetails = memo(function LogDetails({
}
}, [log?.id])

const isWorkflowExecutionLog = useMemo(() => {
if (!log) return false
return (
(log.trigger === 'manual' && !!log.duration) ||
(log.executionData?.enhanced && log.executionData?.traceSpans)
)
}, [log])
const isWorkflowExecutionLog =
!!log &&
((log.trigger === 'manual' && !!log.duration) ||
!!(log.executionData?.enhanced && log.executionData?.traceSpans))

const hasCostInfo = isWorkflowExecutionLog && log?.cost

Expand Down Expand Up @@ -337,10 +334,7 @@ export const LogDetails = memo(function LogDetails({
return () => window.removeEventListener('keydown', handleKeyDown)
}, [isOpen, onClose, hasPrev, hasNext, onNavigatePrev, onNavigateNext])

const formattedTimestamp = useMemo(
() => (log ? formatDate(log.createdAt) : null),
[log?.createdAt]
)
const formattedTimestamp = log ? formatDate(log.createdAt) : null

const logStatus = getDisplayStatus(log?.status)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,14 @@ const LogRow = memo(
? DELETED_WORKFLOW_COLOR
: log.workflow?.color

const handleClick = useCallback(() => onClick(log), [onClick, log])

const handleMouseEnter = useCallback(() => onHover?.(log), [onHover, log])

const handleContextMenu = useCallback(
(e: React.MouseEvent) => {
if (onContextMenu) {
e.preventDefault()
onContextMenu(e, log)
}
},
[onContextMenu, log]
)
const handleClick = () => onClick(log)
const handleMouseEnter = () => onHover?.(log)
const handleContextMenu = (e: React.MouseEvent) => {
if (onContextMenu) {
e.preventDefault()
onContextMenu(e, log)
}
}

return (
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,7 @@ export function WorkflowSelector({
* When allWorkflows is true, pass empty array so the "All" option is selected.
* Otherwise, pass the selected workflow IDs.
*/
const currentValues = useMemo(() => {
return allWorkflows ? [] : selectedIds
}, [allWorkflows, selectedIds])
const currentValues = allWorkflows ? [] : selectedIds

/**
* Handle multi-select changes from Combobox.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,9 @@ export const NotificationSettings = memo(function NotificationSettings({
// Show form if user explicitly opened it OR if loading is complete with no subscriptions
const displayForm = showForm || (!isLoading && !hasSubscriptions && !editingId)

const getSubscriptionsForTab = useCallback(
(tab: NotificationType) => {
return subscriptions.filter((s) => s.notificationType === tab)
},
[subscriptions]
)
const getSubscriptionsForTab = (tab: NotificationType) => {
return subscriptions.filter((s) => s.notificationType === tab)
}

const resetForm = useCallback(() => {
setFormData({
Expand Down
194 changes: 81 additions & 113 deletions apps/sim/app/workspace/[workspaceId]/logs/logs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,8 @@ export default function Logs() {
}
}, [selectedLogId, selectedLogIndex])

const effectiveSidebarOpen = isSidebarOpen && selectedLogIndex !== -1

const handleRefresh = useCallback(() => {
setIsVisuallyRefreshing(true)
const timerId = window.setTimeout(() => {
Expand Down Expand Up @@ -777,7 +779,7 @@ export default function Logs() {
() => (
<LogDetails
log={selectedLog}
isOpen={isSidebarOpen}
isOpen={effectiveSidebarOpen}
onClose={handleCloseSidebar}
onNavigateNext={handleNavigateNext}
onNavigatePrev={handleNavigatePrev}
Expand All @@ -787,7 +789,7 @@ export default function Logs() {
),
[
selectedLog,
isSidebarOpen,
effectiveSidebarOpen,
handleCloseSidebar,
handleNavigateNext,
handleNavigatePrev,
Expand Down Expand Up @@ -1260,20 +1262,10 @@ function LogsFilterPanel({ searchQuery, onSearchQueryChange }: LogsFilterPanelPr
const { data: folders = {} } = useFolderMap(workspaceId)
const { data: allWorkflowList = [] } = useWorkflows(workspaceId)

const workflows = useMemo(
() => allWorkflowList.map((w) => ({ id: w.id, name: w.name, color: w.color })),
[allWorkflowList]
)
const workflows = allWorkflowList.map((w) => ({ id: w.id, name: w.name, color: w.color }))
const folderList = Object.values(folders).filter((f) => f.workspaceId === workspaceId)

const folderList = useMemo(
() => Object.values(folders).filter((f) => f.workspaceId === workspaceId),
[folders, workspaceId]
)

const selectedStatuses = useMemo((): string[] => {
if (level === 'all' || !level) return []
return level.split(',').filter(Boolean)
}, [level])
const selectedStatuses = level === 'all' || !level ? [] : level.split(',').filter(Boolean)

const statusOptions: ComboboxOption[] = useMemo(
() =>
Expand All @@ -1285,58 +1277,46 @@ function LogsFilterPanel({ searchQuery, onSearchQueryChange }: LogsFilterPanelPr
[]
)

const handleStatusChange = useCallback(
(values: string[]) => {
setLevel(values.length === 0 ? 'all' : values.join(','))
},
[setLevel]
)

const statusDisplayLabel = useMemo(() => {
if (selectedStatuses.length === 0) return 'Status'
if (selectedStatuses.length === 1) {
const status = statusOptions.find((s) => s.value === selectedStatuses[0])
return status?.label || '1 selected'
}
return `${selectedStatuses.length} selected`
}, [selectedStatuses, statusOptions])

const selectedStatusColor = useMemo(() => {
if (selectedStatuses.length !== 1) return null
const status = selectedStatuses[0] as LogStatus
return STATUS_CONFIG[status]?.color ?? null
}, [selectedStatuses])

const workflowOptions: ComboboxOption[] = useMemo(
() => workflows.map((w) => ({ value: w.id, label: w.name, icon: getColorIcon(w.color, true) })),
[workflows]
)
const handleStatusChange = (values: string[]) => {
setLevel(values.length === 0 ? 'all' : values.join(','))
}

const workflowDisplayLabel = useMemo(() => {
if (workflowIds.length === 0) return 'Workflow'
if (workflowIds.length === 1) {
const workflow = workflows.find((w) => w.id === workflowIds[0])
return workflow?.name || '1 selected'
}
return `${workflowIds.length} workflows`
}, [workflowIds, workflows])
const statusDisplayLabel =
selectedStatuses.length === 0
? 'Status'
: selectedStatuses.length === 1
? statusOptions.find((s) => s.value === selectedStatuses[0])?.label || '1 selected'
: `${selectedStatuses.length} selected`

const selectedStatusColor =
selectedStatuses.length === 1
? (STATUS_CONFIG[selectedStatuses[0] as LogStatus]?.color ?? null)
: null

const workflowOptions: ComboboxOption[] = workflows.map((w) => ({
value: w.id,
label: w.name,
icon: getColorIcon(w.color, true),
}))

const workflowDisplayLabel =
workflowIds.length === 0
? 'Workflow'
: workflowIds.length === 1
? workflows.find((w) => w.id === workflowIds[0])?.name || '1 selected'
: `${workflowIds.length} workflows`

const selectedWorkflow =
workflowIds.length === 1 ? workflows.find((w) => w.id === workflowIds[0]) : null

const folderOptions: ComboboxOption[] = useMemo(
() => folderList.map((f) => ({ value: f.id, label: f.name })),
[folderList]
)
const folderOptions: ComboboxOption[] = folderList.map((f) => ({ value: f.id, label: f.name }))

const folderDisplayLabel = useMemo(() => {
if (folderIds.length === 0) return 'Folder'
if (folderIds.length === 1) {
const folder = folderList.find((f) => f.id === folderIds[0])
return folder?.name || '1 selected'
}
return `${folderIds.length} folders`
}, [folderIds, folderList])
const folderDisplayLabel =
folderIds.length === 0
? 'Folder'
: folderIds.length === 1
? folderList.find((f) => f.id === folderIds[0])?.name || '1 selected'
: `${folderIds.length} folders`

const triggerOptions: ComboboxOption[] = useMemo(
() =>
Expand All @@ -1348,69 +1328,57 @@ function LogsFilterPanel({ searchQuery, onSearchQueryChange }: LogsFilterPanelPr
[]
)

const triggerDisplayLabel = useMemo(() => {
if (triggers.length === 0) return 'Trigger'
if (triggers.length === 1) {
const trigger = triggerOptions.find((t) => t.value === triggers[0])
return trigger?.label || '1 selected'
}
return `${triggers.length} triggers`
}, [triggers, triggerOptions])

const timeDisplayLabel = useMemo(() => {
if (timeRange === 'All time') return 'Time'
if (timeRange === 'Custom range' && startDate && endDate) {
return `${formatDateShort(startDate)} - ${formatDateShort(endDate)}`
const triggerDisplayLabel =
triggers.length === 0
? 'Trigger'
: triggers.length === 1
? triggerOptions.find((t) => t.value === triggers[0])?.label || '1 selected'
: `${triggers.length} triggers`

const timeDisplayLabel =
timeRange === 'All time'
? 'Time'
: timeRange === 'Custom range' && startDate && endDate
? `${formatDateShort(startDate)} - ${formatDateShort(endDate)}`
: timeRange === 'Custom range'
? 'Custom range'
: timeRange

const handleTimeRangeChange = (val: string) => {
if (val === 'Custom range') {
setPreviousTimeRange(timeRange)
setDatePickerOpen(true)
} else {
clearDateRange()
setTimeRange(val as typeof timeRange)
}
if (timeRange === 'Custom range') return 'Custom range'
return timeRange
}, [timeRange, startDate, endDate])

const handleTimeRangeChange = useCallback(
(val: string) => {
if (val === 'Custom range') {
setPreviousTimeRange(timeRange)
setDatePickerOpen(true)
} else {
clearDateRange()
setTimeRange(val as typeof timeRange)
}
},
[timeRange, setTimeRange, clearDateRange]
)
}

const handleDateRangeApply = useCallback(
(start: string, end: string) => {
setDateRange(start, end)
setDatePickerOpen(false)
},
[setDateRange]
)
const handleDateRangeApply = (start: string, end: string) => {
setDateRange(start, end)
setDatePickerOpen(false)
}

const handleDatePickerCancel = useCallback(() => {
const handleDatePickerCancel = () => {
if (timeRange === 'Custom range' && !startDate) {
setTimeRange(previousTimeRange)
}
setDatePickerOpen(false)
}, [timeRange, startDate, previousTimeRange, setTimeRange])
}

const filtersActive = useMemo(
() =>
hasActiveFilters({
timeRange,
level,
workflowIds,
folderIds,
triggers,
searchQuery,
}),
[timeRange, level, workflowIds, folderIds, triggers, searchQuery]
)
const filtersActive = hasActiveFilters({
timeRange,
level,
workflowIds,
folderIds,
triggers,
searchQuery,
})

const handleClearFilters = useCallback(() => {
const handleClearFilters = () => {
resetFilters()
onSearchQueryChange('')
}, [resetFilters, onSearchQueryChange])
}

return (
<div className='flex w-[240px] flex-col gap-3 p-3'>
Expand Down
Loading
Loading