Simulation Filters
A composite filter component with project, template, calendar, and simulation selectors
Live Example
Basic Filters (3 components)
Project, Template, and Calendar selectors
Full Filters (4 components)
Project, Template, Calendar, and Simulation selectors
Multiselect Templates
Project and multi-template selectors
Multiselect Templates and Simulations
All components with multi-select for templates and simulations
Prerequisites
This component requires sgerp-frontend-lib to be installed in your project. See the Installation guide for setup instructions.
Dependencies
This component will automatically install:
react-day-picker- Calendar componentdate-fns- Date utilitiesdate-fns-tz- Timezone supportlucide-react- For icons- shadcn/ui components:
button,input,popover
Usage
import { SimulationFilters } from "@/components/ui/sgerp-simulation-filters"
export function MyComponent() {
return (
<SimulationFilters
onProjectChange={(id, project) => console.log("Project:", project)}
onDateChange={(date) => console.log("Date:", date)}
showTemplateSelector={true}
showCalendar={true}
/>
)
}
Props
| Prop | Type | Description |
|---|---|---|
onProjectChange | (projectId: number | null, project?: Project) => void | Optional. Callback when project selection changes |
onTemplateChange | (templateId: number | null, template?: Simulation) => void | Optional. Callback when template selection changes (single-select mode) |
onTemplatesChange | (templateIds: number[], templates?: Simulation[]) => void | Optional. Callback when template selection changes (multi-select mode) |
onDateChange | (date: Date | undefined) => void | Optional. Callback when calendar date changes |
onSimulationChange | (simulationId: number | null, simulation?: Simulation) => void | Optional. Callback when simulation selection changes (single-select mode) |
onSimulationsChange | (simulationIds: number[], simulations?: Simulation[]) => void | Optional. Callback when simulation selection changes (multi-select mode) |
showTemplateSelector | boolean | Optional. Show template selector. Default: true |
showCalendar | boolean | Optional. Show calendar dropdown. Default: true |
showSimulationSelector | boolean | Optional. Show simulation selector. Default: false |
multiSelectTemplates | boolean | Optional. Use multiselect for templates instead of single-select. Default: false |
multiSelectSimulations | boolean | Optional. Use multiselect for simulations instead of single-select. Default: false |
className | string | Optional. Additional CSS classes |
autoFetchSimulations | boolean | Optional. Automatically fetch simulations when filters change. Default: true |
Features
- Dependent Filtering: Automatically handles filter dependencies (template depends on project, etc.)
- Single or Multi-select: Choose between single-select or multi-select mode for templates and simulations
- Auto-selection: Automatically selects items when only one option is available:
- If user has access to only one project, it's auto-selected
- If only one template exists for the project, it's auto-selected (in both single and multi-select modes)
- If simulation selector is shown, the first simulation is auto-selected (single-select) or only item is auto-selected (multi-select)
- Timezone Support: Date ranges respect project timezone for accurate filtering
- Auto-fetch: Automatically fetches simulations when project/template/month changes
- Flexible Layout: Show/hide individual filter components as needed
- Type-safe Callbacks: Receive both IDs and full objects in callbacks
- Responsive: Works on all screen sizes
Examples
Basic Three-Component Filter
Project, template, and calendar selectors:
import { SimulationFilters } from "@/components/ui/sgerp-simulation-filters"
import { useState } from "react"
export function BasicFilter() {
const [selectedDate, setSelectedDate] = useState<Date>()
return (
<SimulationFilters
onDateChange={setSelectedDate}
showTemplateSelector={true}
showCalendar={true}
showSimulationSelector={false}
/>
)
}
Four-Component Filter with Simulation Selector
Add individual simulation selection:
import { SimulationFilters } from "@/components/ui/sgerp-simulation-filters"
import { useState } from "react"
import type { Simulation } from "sgerp-frontend-lib"
export function FullFilter() {
const [selectedSimulation, setSelectedSimulation] = useState<Simulation | null>(null)
return (
<SimulationFilters
onSimulationChange={(id, simulation) => {
setSelectedSimulation(simulation || null)
}}
showTemplateSelector={true}
showCalendar={true}
showSimulationSelector={true}
/>
)
}
Project and Calendar Only
Minimal filter without template selector:
<SimulationFilters
onProjectChange={(id, project) => console.log("Project:", project)}
onDateChange={(date) => console.log("Date:", date)}
showTemplateSelector={false}
showCalendar={true}
showSimulationSelector={false}
/>
With All Callbacks
Handle all selection changes:
import { SimulationFilters } from "@/components/ui/sgerp-simulation-filters"
import { useState } from "react"
import type { Project, Simulation } from "sgerp-frontend-lib"
export function CompleteExample() {
const [project, setProject] = useState<Project | null>(null)
const [template, setTemplate] = useState<Simulation | null>(null)
const [date, setDate] = useState<Date>()
const [simulation, setSimulation] = useState<Simulation | null>(null)
return (
<div>
<SimulationFilters
onProjectChange={(id, proj) => setProject(proj || null)}
onTemplateChange={(id, tmpl) => setTemplate(tmpl || null)}
onDateChange={setDate}
onSimulationChange={(id, sim) => setSimulation(sim || null)}
showTemplateSelector={true}
showCalendar={true}
showSimulationSelector={true}
/>
{/* Display selected values */}
{project && <div>Project: {project.name} (Timezone: {project.timezone})</div>}
{template && <div>Template: {template.name}</div>}
{date && <div>Date: {date.toLocaleDateString()}</div>}
{simulation && <div>Simulation: {simulation.name}</div>}
</div>
)
}
Custom Styling
Apply custom classes to the container:
<SimulationFilters
className="p-4 bg-muted rounded-lg"
showTemplateSelector={true}
showCalendar={true}
showSimulationSelector={false}
/>
Multi-select Templates
Use multiselect dropdown for template selection:
import { SimulationFilters } from "@/components/ui/sgerp-simulation-filters"
import { useState } from "react"
import type { Simulation } from "sgerp-frontend-lib"
export function MultiSelectTemplates() {
const [templateIds, setTemplateIds] = useState<number[]>([])
const [templates, setTemplates] = useState<Simulation[]>([])
return (
<SimulationFilters
onTemplatesChange={(ids, tmpls) => {
setTemplateIds(ids)
setTemplates(tmpls || [])
}}
showTemplateSelector={true}
showCalendar={false}
showSimulationSelector={false}
multiSelectTemplates={true}
/>
)
}
Multi-select Templates and Simulations
Use multiselect for both templates and simulations:
import { SimulationFilters } from "@/components/ui/sgerp-simulation-filters"
import { useState } from "react"
import type { Simulation } from "sgerp-frontend-lib"
export function FullMultiSelect() {
const [templateIds, setTemplateIds] = useState<number[]>([])
const [templates, setTemplates] = useState<Simulation[]>([])
const [simulationIds, setSimulationIds] = useState<number[]>([])
const [simulations, setSimulations] = useState<Simulation[]>([])
return (
<SimulationFilters
onTemplatesChange={(ids, tmpls) => {
setTemplateIds(ids)
setTemplates(tmpls || [])
}}
onSimulationsChange={(ids, sims) => {
setSimulationIds(ids)
setSimulations(sims || [])
}}
showTemplateSelector={true}
showCalendar={true}
showSimulationSelector={true}
multiSelectTemplates={true}
multiSelectSimulations={true}
/>
)
}
Manual Fetch Control
Disable auto-fetching and handle it manually:
import { SimulationFilters } from "@/components/ui/sgerp-simulation-filters"
import { useSGERP } from "sgerp-frontend-lib"
import { useState } from "react"
import type { Project } from "sgerp-frontend-lib"
export function ManualFetch() {
const api = useSGERP()
const [projectId, setProjectId] = useState<number | null>(null)
const handleProjectChange = async (id: number | null, project?: Project) => {
setProjectId(id)
// Manually fetch simulations with custom logic
if (id && api) {
await api.collections.simulation.fetch({
project_id: id,
limit: 100,
})
}
}
return (
<SimulationFilters
onProjectChange={handleProjectChange}
autoFetchSimulations={false}
showTemplateSelector={true}
showCalendar={true}
/>
)
}
Filter Logic
The component implements these filtering rules:
-
Template Selector:
- Disabled until project is selected
- Filters by:
project_idandsimulation_mode: 'template' - Resets when project changes
- Single-select mode: Uses SGERPAutocomplete, calls
onTemplateChange - Multi-select mode: Uses SGERPMultiselect, calls
onTemplatesChange
-
Calendar:
- Disabled until project is selected
- Fetches simulations for visible month
- Uses project timezone for date ranges
- Shows dots on dates with simulations
- Works with both single and multiple template IDs
-
Simulation Selector (when enabled):
- Disabled until project is selected
- If calendar is shown, disabled until date is selected
- Filters by project, template(s) (if set), and date (if set)
- Resets when filters change
- Single-select mode: Uses SGERPAutocomplete, calls
onSimulationChange - Multi-select mode: Uses SGERPMultiselect, calls
onSimulationsChange
Auto-selection Behavior
The component automatically selects items to streamline the user experience:
Project Auto-selection
When the component mounts, it fetches all available projects. If exactly one project is found, it's automatically selected:
// Triggers automatically on mount
if (projects.models.length === 1) {
// Auto-select the single project
// Calls onProjectChange callback
}
Template Auto-selection
When a project is selected (manually or automatically), templates are fetched. If exactly one template exists for that project, it's automatically selected:
Single-select mode:
// Triggered when projectId changes
if (templates.length === 1) {
// Auto-select the single template
// Calls onTemplateChange callback
}
Multi-select mode:
// Triggered when projectId changes
if (templates.length === 1) {
// Auto-select the single template
// Calls onTemplatesChange callback with array
}
Simulation Auto-selection
When simulations are fetched (and showSimulationSelector={true}), simulations are automatically selected based on mode:
Single-select mode:
// Triggered when simulations are loaded
if (simulations.models.length > 0) {
// Auto-select first simulation
// Calls onSimulationChange callback
}
Multi-select mode:
// Triggered when simulations are loaded
if (simulations.models.length === 1) {
// Auto-select the single simulation
// Calls onSimulationsChange callback with array
}
Resetting Auto-selection
Auto-selection flags are reset when users manually change selections, allowing them to choose different options at any time.
Timezone Handling
The component automatically respects project timezones:
// When fetching simulations for a month, dates are formatted in project timezone
const timezone = project.timezone || "UTC"
const startDate = formatInTimeZone(monthStart, timezone, "yyyy-MM-dd")
const endDate = formatInTimeZone(monthEnd, timezone, "yyyy-MM-dd")
// API filters use timezone-aware dates
filters = {
start_time__gte: startDate + "T00:00:00",
start_time__lte: endDate + "T23:59:59",
}
This ensures accurate filtering for projects in different timezones.
Performance
The component is optimized for performance:
- Auto-fetch: Only fetches when filters change (project, template, month)
- Efficient queries: Uses
only_fieldsto limit data transfer - Smart dependencies: Template and simulation selectors only fetch when dependencies are met
- Memoized calculations: Date filtering uses React.useMemo
API Integration
The component uses the SGERP Collections API:
Single-select mode:
// Auto-fetches simulations based on filters
await api.collections.simulation.fetch({
limit: 1000,
start_time__gte: startDate + "T00:00:00",
start_time__lte: endDate + "T23:59:59",
project_id: projectId,
template_id__in: templateId, // if single template selected
})
Multi-select mode:
// Auto-fetches simulations based on filters
await api.collections.simulation.fetch({
limit: 1000,
start_time__gte: startDate + "T00:00:00",
start_time__lte: endDate + "T23:59:59",
project_id: projectId,
template_id__in: templateIds.join(','), // if multiple templates selected
})
Make sure you have set up a connection before using this component. See the Try It Out page for connection setup.
Styling
The component uses a flex layout with equal-width columns:
display: flex
gap: 0.75rem (12px)
each child: flex: 1
Customize spacing and layout with the className prop.