Grouping
Use resourceGrouping for team, department, location, room-building, machine-line, or sprint-team grouping. Parent-child resources can render as a tree.
grid.eventSchedulerResources = [ { id: 'north', name: 'North Campus', role: 'Location' }, { id: 'room-a', parentId: 'north', name: 'Room A', role: 'Room', metadata: { floor: '1' } }, { id: 'room-b', parentId: 'north', name: 'Room B', role: 'Room', metadata: { floor: '2' } },];
grid.eventScheduler = { view: 'resourceTimeline', weekStartDate: '2026-06-08', resourceGrouping: { enabled: true, tree: true, groupBy: (resource) => String(resource.metadata?.floor ?? resource.group ?? 'Other'), groupSummaryFormatter: ({ summary }) => `${summary.eventCount} events - ${summary.totalHours}h`, },};Group rows aggregate workload, coverage, and utilization summaries when those features are enabled.
Resource Planner Patterns
Section titled “Resource Planner Patterns”Use resourceTimeline when resources are the main rows and time moves horizontally.
grid.eventScheduler = { view: 'resourceTimeline', weekStartDate: '2026-06-08', dateRange: { start: '2026-06-08', end: '2026-06-14' }, resourceColumnSize: 220, timelineColumnSize: 72, resourceGrouping: { enabled: true, groupBy: (resource) => resource.metadata?.location as string, tree: true, collapsed: false, groupSummaryFormatter: ({ summary }) => `${summary.eventCount} events - ${summary.totalHours}h`, }, resourceMetaFormatter: (resource) => [resource.role, resource.metadata?.location].filter(Boolean).join(' - '),};Events without resourceId, resourceIds, or side-channel assignments render in the generated unassigned row when unassigned.enabled is not false.
grid.eventScheduler = { view: 'resourceTimeline', weekStartDate: '2026-06-08', unassigned: { enabled: true, showCount: true, requiredRoleField: 'metadata.requiredRole', filter: { status: ['draft', 'planned'], role: 'Technician' }, counterFormatter: (summary) => `${summary.visibleCount} open requests`, requiredRoleFormatter: ({ role }) => `Need ${role}`, assignmentValidator: ({ event, resource }) => { const required = event.metadata?.requiredRole; const skills = Array.isArray(resource.metadata?.skills) ? resource.metadata.skills : []; return !required || skills.includes(required) || `${resource.name} cannot fill ${required}.`; }, },};Coverage compares required capacity with assigned event capacity in the visible range. Utilization calculates scheduled workload by resource.
grid.eventScheduler = { view: 'resourceTimeline', weekStartDate: '2026-06-08', coverage: { enabled: true, capacityField: 'capacity', countEvent: ({ event, resource }) => event.status === 'cancelled' ? false : resource.capacity ?? 1, }, utilization: { enabled: true, minHoursField: 'metadata.minHoursPerWeek', targetHoursField: 'metadata.targetHoursPerWeek', maxHoursField: 'metadata.maxHoursPerWeek', excludeStatuses: ['cancelled', 'blocked'], },};Use filters and savedViews to reduce projected data without mutating source arrays:
grid.eventScheduler = { view: 'resourceTimeline', weekStartDate: '2026-06-08', filters: { search: 'security', resourceRoles: 'Security', eventStatuses: ['planned', 'confirmed'], conflictsOnly: false, unassignedOnly: false, }, activeSavedViewId: 'security-week', savedViews: { views: [ { id: 'conflicts', label: 'Conflicts only', filters: { conflictsOnly: true } }, { id: 'unassigned', label: 'Unassigned', filters: { unassignedOnly: true } }, { id: 'security-week', label: 'Security team', dateRange: { start: '2026-06-08', end: '2026-06-12' }, filters: { resourceRoles: 'Security' }, }, ], },};The projection exposes filterSummary with visible and hidden resource/event counts.
Resource columns
Section titled “Resource columns”Group sections use a compact neutral row with the resource count beside the name
and the existing summary aligned on the right of the timeline. Customize the count
with labels.resourceGroupCountLabel; groupSummaryFormatter continues to own the
summary text. Resource avatars use the shared Pro avatar renderer.
Resource Timeline accepts normal RevoGrid column definitions in grid.columns.
Omitted or empty columns use the default Resource column. Reassign grid.columns
to update the resource fields while Scheduler is active.
Their values come from eventSchedulerResources; the grid’s source still owns
scheduled events. Use prop for a resource field or a nested field path. The
legacy resourceLabel prop displays the existing identity template and edits
resource.name.
grid.columns = [ { prop: 'resourceLabel', name: 'Resource', size: 220 }, { prop: 'role', name: 'Role', size: 140, tree: true }, { prop: 'metadata.location', name: 'Location', size: 140 }, { prop: 'capacity', name: 'Capacity', size: 100, filter: 'number' },];grid.eventScheduler = { view: 'resourceTimeline', weekStartDate: '2026-06-08', resourceGrouping: { enabled: true, tree: true },};Registered grid columnTypes are supported, including their editors and readonly defaults. Use ordinary editor, readonly, cellTemplate, cellParser, cellCompare,
filter, sortable, size, minSize, and maxSize settings. Templates and
parsers receive the projected grid row, including its resource entity and raw
column values. Synthetic groups, the unassigned row, and empty rows cannot be
edited. Real parent resources can be edited. Resource IDs remain immutable.
The default Resource column is editable. Set editable: false for Scheduler or
readonly: true on a column to disable editing. Resource locked, readonly,
and disabled flags also prevent resource-cell edits.
Identity can be moved or hidden (hidden: true). Choose the hierarchy control
column with tree: true; if omitted, the first visible resource column is used.
Resource columns remain pinned together on the left; header dragging reorders
that area. On narrow layouts, hide optional columns to leave room for time slots.
Scheduler reuses TreeDataPlugin and native grid sort/filter controls, including Shift-click additive sorting. Tree filters follow that plugin’s existing positive/exclusion filter semantics and expansion behavior. They search loaded resources only. They do not fetch unloaded children, change event membership, redefine group summary totals, or remove hidden demand from conflict checks.
For advanced resource filters, register AdvanceFilterPlugin alongside EventSchedulerPlugin. Use filter: ['selection'] for checkbox value lists, such as resource names, roles, groups, and locations, and filter: ['number'] for numeric capacity conditions. Synthetic section headings do not appear in the value lists. Filtering continues to use the shared grid and tree plugins.
Resource edits and application saves
Section titled “Resource edits and application saves”Resource edits replace eventSchedulerResources immutably and recalculate
scheduling conflicts. Proposed conflicts cover all loaded bookings, including dates and events hidden by the current view or filters. They participate in the existing grid undo/redo history.
By default, edits that create conflicts are accepted and the conflicts displayed.
An application can reject a proposed edit using the cancelable event:
grid.addEventListener('event-scheduler-before-resource-change', event => { if (event.detail.conflicts.length) event.preventDefault();});
grid.addEventListener('event-scheduler-resource-changed', event => { // Save event.detail.resources in your application's persistence layer. // origin is 'edit', 'undo', or 'redo'.});Computed columns use valueGetter(resource). They are read-only unless supplied
with valueSetter(resource, value), which must return a new resource with the
same ID. Nested field edits preserve unrelated metadata.
const doubledCapacity = { prop: 'doubleCapacity', name: 'Double capacity', valueGetter: resource => (resource.capacity ?? 0) * 2, valueSetter: (resource, value) => ({ ...resource, capacity: Number(value) / 2 }),};Column layout state
Section titled “Column layout state”Column widths and dragged order survive refreshes and temporary view switches.
Explicit configuration changes override retained state. Use the Scheduler plugin’s
getResourceColumnState() to inspect column props, widths, visibility, order,
sorting, and filters, and resetResourceColumnState(prop?) to reset all columns or
one column. event-scheduler-resource-column-state-changed reports native
presentation changes. Applications own persistence across page loads.
When grouping is active, the plugin projection retains loaded descendant rows. TreeDataPlugin owns their visible order and collapse/filter trimming through grid providers; collapsing a branch does not remove its rows or events from the underlying projection.