+
{log.workflow && (
- {log.workflow.name}
+ {log.workflow.name}
)}
+ {/* ID column - hidden on small screens */}
+
+
+ {log.executionId ? `#${log.executionId.substring(0, 4)}` : '—'}
+
+
+
{/* Trigger column - hidden on medium screens and below */}
{log.trigger && (
- {log.trigger}
+ {log.trigger}
)}
- {/* Message column - expanded on medium screens when trigger is hidden */}
-
+ {/* Message column - smaller on small screens to give space to status and workflow */}
+
{log.message}
diff --git a/app/w/logs/stores/store.ts b/app/w/logs/stores/store.ts
new file mode 100644
index 0000000000..7ff9af536e
--- /dev/null
+++ b/app/w/logs/stores/store.ts
@@ -0,0 +1,101 @@
+import { create } from 'zustand'
+import { WorkflowLog } from './types'
+
+export type TimeRange = 'Past 30 minutes' | 'Past hour' | 'Past 24 hours' | 'All time'
+export type LogLevel = 'error' | 'info' | 'all'
+
+interface FilterState {
+ // Original logs from API
+ logs: WorkflowLog[]
+ // Filtered logs to display
+ filteredLogs: WorkflowLog[]
+ // Filter states
+ timeRange: TimeRange
+ level: LogLevel
+ workflowId: string | null
+ // Loading state
+ loading: boolean
+ error: string | null
+ // Actions
+ setLogs: (logs: WorkflowLog[]) => void
+ setTimeRange: (timeRange: TimeRange) => void
+ setLevel: (level: LogLevel) => void
+ setWorkflowId: (workflowId: string | null) => void
+ setLoading: (loading: boolean) => void
+ setError: (error: string | null) => void
+ // Apply filters
+ applyFilters: () => void
+}
+
+export const useFilterStore = create
((set, get) => ({
+ logs: [],
+ filteredLogs: [],
+ timeRange: 'All time',
+ level: 'all',
+ workflowId: null,
+ loading: true,
+ error: null,
+
+ setLogs: (logs) => {
+ set({ logs, filteredLogs: logs, loading: false })
+ },
+
+ setTimeRange: (timeRange) => {
+ set({ timeRange })
+ get().applyFilters()
+ },
+
+ setLevel: (level) => {
+ set({ level })
+ get().applyFilters()
+ },
+
+ setWorkflowId: (workflowId) => {
+ set({ workflowId })
+ get().applyFilters()
+ },
+
+ setLoading: (loading) => set({ loading }),
+
+ setError: (error) => set({ error }),
+
+ applyFilters: () => {
+ const { logs, timeRange, level, workflowId } = get()
+
+ let filtered = [...logs]
+
+ // Apply time range filter
+ if (timeRange !== 'All time') {
+ const now = new Date()
+ let cutoffTime: Date
+
+ switch (timeRange) {
+ case 'Past 30 minutes':
+ cutoffTime = new Date(now.getTime() - 30 * 60 * 1000)
+ break
+ case 'Past hour':
+ cutoffTime = new Date(now.getTime() - 60 * 60 * 1000)
+ break
+ case 'Past 24 hours':
+ cutoffTime = new Date(now.getTime() - 24 * 60 * 60 * 1000)
+ break
+ default:
+ cutoffTime = new Date(0) // Beginning of time
+ }
+
+ filtered = filtered.filter((log) => new Date(log.createdAt) >= cutoffTime)
+ }
+
+ // Apply level filter
+ if (level !== 'all') {
+ filtered = filtered.filter((log) => log.level.toLowerCase() === level)
+ }
+
+ // Apply workflow filter
+ if (workflowId) {
+ filtered = filtered.filter((log) => log.workflowId === workflowId)
+ }
+
+ set({ filteredLogs: filtered })
+ },
+}))
diff --git a/app/w/logs/stores/types.ts b/app/w/logs/stores/types.ts
new file mode 100644
index 0000000000..f7d02a20d0
--- /dev/null
+++ b/app/w/logs/stores/types.ts
@@ -0,0 +1,28 @@
+export interface WorkflowData {
+ id: string
+ name: string
+ description: string | null
+ color: string
+ state: any
+ // Add other workflow fields as needed
+}
+
+export interface WorkflowLog {
+ id: string
+ workflowId: string
+ executionId: string | null
+ level: string
+ message: string
+ duration: string | null
+ trigger: string | null
+ createdAt: string
+ workflow?: WorkflowData | null
+}
+
+export interface LogsResponse {
+ data: WorkflowLog[]
+ total: number
+ page: number
+ pageSize: number
+ totalPages: number
+}