Background Jobs Components

3 Components

Pre-built React components for scheduling one-time and recurring jobs, viewing job status, and building cron expressions visually.

JobScheduler

Schedule one-time and recurring cron jobs

JobList

View and manage all scheduled jobs

CronBuilder

Visual cron expression builder

Installation

All job components are included in the SDK. Import them from @sylphx/platform-sdk/react.

JobScheduler

A comprehensive form component for scheduling background jobs. Supports one-time jobs, delayed jobs, and recurring cron schedules with a clean, intuitive interface.

Basic Usage

app/admin/jobs/new/page.tsx
import { JobScheduler } from '@sylphx/platform-sdk/react'

export default function NewJobPage() {
  return (
    <JobScheduler
      onSchedule={(job) => {
        console.log('Job scheduled:', job.id)
      }}
    />
  )
}

Props

PropertyTypeDescription
onSchedulerequired(job: Job) => voidCallback when job is successfully scheduled
defaultUrlstringPre-fill the job URL endpoint
defaultPayloadobjectPre-fill the job payload/body
defaultMode"immediate" | "delayed" | "cron"= "immediate"Initial scheduling mode
allowedModesScheduleMode[]Limit available scheduling modes
endpointsEndpoint[]Predefined endpoints for dropdown selection
showRetryConfigboolean= trueShow retry configuration options
showTimeoutConfigboolean= trueShow timeout configuration
showHeadersboolean= falseAllow custom headers
maxRetriesnumber= 10Maximum allowed retry attempts
maxTimeoutnumber= 900Maximum timeout in seconds
onError(error: Error) => voidCallback when scheduling fails
onCancel() => voidCallback when user cancels
submitLabelstring= "Schedule Job"Custom submit button text
loadingboolean= falseShow loading state
disabledboolean= falseDisable the form
classNamestringAdditional CSS classes

Advanced Configuration

With endpoints
import { JobScheduler, type Endpoint } from '@sylphx/platform-sdk/react'

const endpoints: Endpoint[] = [
  {
    label: 'Send Email',
    url: '/api/jobs/send-email',
    description: 'Send transactional emails',
    payloadSchema: {
      to: { type: 'string', required: true },
      template: { type: 'string', required: true },
      data: { type: 'object' },
    },
  },
  {
    label: 'Generate Report',
    url: '/api/jobs/generate-report',
    description: 'Generate PDF reports',
    payloadSchema: {
      reportType: { type: 'string', required: true },
      dateRange: { type: 'object' },
    },
  },
  {
    label: 'Process Upload',
    url: '/api/jobs/process-upload',
    description: 'Process uploaded files',
  },
]

<JobScheduler
  endpoints={endpoints}
  onSchedule={(job) => console.log('Scheduled:', job)}
/>

URL Validation

JobScheduler validates that URLs are absolute HTTPS URLs in production. Local development allows HTTP URLs for testing.

JobList

A data table component for viewing, filtering, and managing scheduled jobs. Supports pagination, filtering by status, and bulk actions.

Basic Usage

app/admin/jobs/page.tsx
import { JobList } from '@sylphx/platform-sdk/react'

export default function JobsPage() {
  return (
    <JobList
      title="Scheduled Jobs"
      onJobClick={(job) => router.push(`/admin/jobs/${job.id}`)}
    />
  )
}

Props

PropertyTypeDescription
titlestring= "Jobs"Title displayed above the list
statusJobStatus | JobStatus[]Filter by job status
type"one-time" | "cron"Filter by job type
limitnumber= 25Jobs per page
showFiltersboolean= trueShow filter controls
showSearchboolean= trueShow search input
showPaginationboolean= trueShow pagination controls
showActionsboolean= trueShow action buttons (pause, cancel, retry)
selectableboolean= falseEnable row selection for bulk actions
autoRefreshboolean= falseAuto-refresh list every 10 seconds
refreshIntervalnumber= 10000Auto-refresh interval in ms
columnsColumn[]Custom columns to display
onJobClick(job: Job) => voidCallback when job row is clicked
onPause(job: Job) => voidCallback when job is paused
onResume(job: Job) => voidCallback when job is resumed
onCancel(job: Job) => voidCallback when job is cancelled
onRetry(job: Job) => voidCallback when job is retried
onBulkAction(action: string, jobs: Job[]) => voidCallback for bulk actions
emptyMessagestring= "No jobs found"Message when no jobs found
loadingboolean= falseShow loading state
classNamestringAdditional CSS classes

JobStatus Type

type JobStatus =
  | 'pending'    // Job is queued, waiting to run
  | 'running'    // Job is currently executing
  | 'completed'  // Job finished successfully
  | 'failed'     // Job failed after all retries
  | 'cancelled'  // Job was manually cancelled
  | 'paused'     // Recurring job is paused

Advanced Usage

Filtered by status
import { JobList } from '@sylphx/platform-sdk/react'

// Show only failed jobs
<JobList
  title="Failed Jobs"
  status="failed"
  showFilters={false}
/>

// Show active jobs (pending or running)
<JobList
  title="Active Jobs"
  status={['pending', 'running']}
  autoRefresh={true}
  refreshInterval={5000}
/>

// Show only cron jobs
<JobList
  title="Recurring Jobs"
  type="cron"
  showActions={true}
/>

Real-time Updates

Enable autoRefresh for dashboards that need to show live job status. The component will poll for updates at the specified interval.

CronBuilder

A visual cron expression builder that makes it easy to create complex schedules without memorizing cron syntax. Includes a human-readable preview and next run times.

Basic Usage

components/schedule-picker.tsx
import { CronBuilder } from '@sylphx/platform-sdk/react'

export function SchedulePicker() {
  const [cron, setCron] = useState('0 9 * * *')

  return (
    <CronBuilder
      value={cron}
      onChange={setCron}
    />
  )
}

Props

PropertyTypeDescription
valuerequiredstringCurrent cron expression
onChangerequired(cron: string) => voidCallback when expression changes
mode"simple" | "advanced"= "simple"UI mode - simple shows presets, advanced shows full editor
showPreviewboolean= trueShow human-readable description
showNextRunsboolean= trueShow next scheduled run times
nextRunCountnumber= 5Number of next runs to display
timezonestring= browser timezoneTimezone for display
showTimezoneboolean= trueShow timezone selector
presetsCronPreset[]Custom preset options
minIntervalnumber= 1Minimum interval in minutes
disabledFieldsCronField[]Disable specific fields (minute, hour, etc.)
onError(error: string) => voidCallback for validation errors
compactboolean= falseUse compact layout
disabledboolean= falseDisable the builder
classNamestringAdditional CSS classes

CronPreset Type

interface CronPreset {
  label: string        // Display name (e.g., "Every hour")
  value: string        // Cron expression (e.g., "0 * * * *")
  description?: string // Optional description
  icon?: ReactNode     // Optional icon
}

Built-in Presets

PresetExpressionDescription
Every minute* * * * *Runs every minute
Every hour0 * * * *Runs at the start of every hour
Daily at midnight0 0 * * *Runs every day at 00:00
Weekdays at 9am0 9 * * 1-5Runs Monday-Friday at 9:00 AM
Weekly on Sunday0 0 * * 0Runs every Sunday at midnight
Monthly0 0 1 * *Runs on the 1st of every month

Examples

Simple presets
import { CronBuilder } from '@sylphx/platform-sdk/react'

// Simple mode with presets (default)
<CronBuilder
  value={cron}
  onChange={setCron}
  mode="simple"
  showPreview={true}
  showNextRuns={true}
/>

Minimum Interval

Use minInterval to prevent users from scheduling jobs too frequently. This helps avoid overwhelming your job handlers with excessive requests.

Complete Example

Here is a complete example combining all job components into a job management interface:

app/admin/jobs/page.tsx
'use client'

import { useState } from 'react'
import {
  JobScheduler,
  JobList,
  CronBuilder,
} from '@sylphx/platform-sdk/react'
import { platform } from '@/lib/platform'
import { Plus, Calendar, List, Clock } from 'lucide-react'

export default function JobsManagementPage() {
  const [view, setView] = useState<'list' | 'schedule'>('list')
  const [cronValue, setCronValue] = useState('0 9 * * *')

  const handleSchedule = async (job) => {
    await platform.jobs.schedule(job)
    toast.success('Job scheduled successfully!')
    setView('list') // Return to list view
  }

  const handleCancel = async (job) => {
    await platform.jobs.cancel(job.id)
    toast.success('Job cancelled')
  }

  const handleRetry = async (job) => {
    await platform.jobs.retry(job.id)
    toast.success('Job queued for retry')
  }

  return (
    <div className="max-w-6xl mx-auto p-6 space-y-8">
      <div className="flex items-center justify-between">
        <h1 className="text-3xl font-bold">Background Jobs</h1>

        <div className="flex gap-2">
          <button
            onClick={() => setView('list')}
            className={`px-4 py-2 rounded-lg flex items-center gap-2 ${
              view === 'list'
                ? 'bg-primary text-primary-foreground'
                : 'bg-muted'
            }`}
          >
            <List className="w-4 h-4" />
            View Jobs
          </button>
          <button
            onClick={() => setView('schedule')}
            className={`px-4 py-2 rounded-lg flex items-center gap-2 ${
              view === 'schedule'
                ? 'bg-primary text-primary-foreground'
                : 'bg-muted'
            }`}
          >
            <Plus className="w-4 h-4" />
            New Job
          </button>
        </div>
      </div>

      {view === 'list' ? (
        <JobList
          title="All Jobs"
          showFilters={true}
          showSearch={true}
          showActions={true}
          autoRefresh={true}
          refreshInterval={10000}
          onCancel={handleCancel}
          onRetry={handleRetry}
          onJobClick={(job) => router.push(`/admin/jobs/${job.id}`)}
        />
      ) : (
        <div className="grid grid-cols-2 gap-8">
          <div>
            <h2 className="text-xl font-semibold mb-4 flex items-center gap-2">
              <Clock className="w-5 h-5" />
              Schedule a Job
            </h2>
            <JobScheduler
              onSchedule={handleSchedule}
              onCancel={() => setView('list')}
              showRetryConfig={true}
              showTimeoutConfig={true}
              endpoints={[
                { label: 'Send Email', url: '/api/jobs/send-email' },
                { label: 'Generate Report', url: '/api/jobs/report' },
                { label: 'Sync Data', url: '/api/jobs/sync' },
              ]}
            />
          </div>

          <div>
            <h2 className="text-xl font-semibold mb-4 flex items-center gap-2">
              <Calendar className="w-5 h-5" />
              Cron Schedule Builder
            </h2>
            <CronBuilder
              value={cronValue}
              onChange={setCronValue}
              mode="simple"
              showPreview={true}
              showNextRuns={true}
              showTimezone={true}
            />
          </div>
        </div>
      )}
    </div>
  )
}

Theming

All job components inherit theming from the SylphxProvider:

import { SylphxProvider, JobList, JobScheduler } from '@sylphx/platform-sdk/react'

// Global theming via provider
<SylphxProvider
  theme={{
    colorPrimary: '#6366f1',
    colorSuccess: '#10b981',
    colorWarning: '#f59e0b',
    colorDanger: '#ef4444',
    borderRadius: '0.75rem',
  }}
>
  <JobList title="Jobs" />
  <JobScheduler onSchedule={handleSchedule} />
</SylphxProvider>

// Individual component styling
<JobList
  title="Jobs"
  className="border-2 border-primary/20 rounded-2xl"
/>

<CronBuilder
  value={cron}
  onChange={setCron}
  className="bg-muted p-4 rounded-xl"
/>

Server Components

These components use client-side interactivity. When using in Next.js App Router, import them in a Client Component or add 'use client' at the top of your page.