diff --git a/apps/client/src/views/backstage/backstage.options.ts b/apps/client/src/views/backstage/backstage.options.ts index d591577c0..5d87123e5 100644 --- a/apps/client/src/views/backstage/backstage.options.ts +++ b/apps/client/src/views/backstage/backstage.options.ts @@ -10,13 +10,14 @@ import { makeProjectDataOptions, } from '../../common/components/view-params-editor/viewParams.utils'; import { PresetContext } from '../../common/context/PresetContext'; -import { scheduleOptions } from '../common/schedule/schedule.options'; +import { getScheduleOptions } from '../common/schedule/schedule.options'; export const getBackstageOptions = ( timeFormat: string, customFields: CustomFields, projectData: ProjectData, ): ViewOption[] => { + const customFieldOptions = makeOptionsFromCustomFields(customFields, []); const secondaryOptions = makeOptionsFromCustomFields(customFields, [ { value: 'none', label: 'None' }, { value: 'note', label: 'Note' }, @@ -39,7 +40,7 @@ export const getBackstageOptions = ( }, ], }, - scheduleOptions, + getScheduleOptions(customFieldOptions), { title: OptionTitle.ElementVisibility, collapsible: true, diff --git a/apps/client/src/views/common/schedule/ScheduleContext.tsx b/apps/client/src/views/common/schedule/ScheduleContext.tsx index 968f19e28..ba699c6c3 100644 --- a/apps/client/src/views/common/schedule/ScheduleContext.tsx +++ b/apps/client/src/views/common/schedule/ScheduleContext.tsx @@ -1,14 +1,5 @@ -import { - createContext, - PropsWithChildren, - RefObject, - useContext, - useEffect, - useLayoutEffect, - useRef, - useState, -} from 'react'; -import { isOntimeEvent, OntimeEntry, OntimeEvent } from 'ontime-types'; +import { createContext, PropsWithChildren, RefObject, use, useEffect, useLayoutEffect, useRef, useState } from 'react'; +import { EntryId, isOntimeEvent, OntimeEntry, OntimeEvent } from 'ontime-types'; import { usePartialRundown } from '../../../common/hooks-query/useRundown'; @@ -25,13 +16,18 @@ interface ScheduleContextState { const ScheduleContext = createContext(undefined); interface ScheduleProviderProps { - selectedEventId: string | null; + selectedEventId: EntryId | null; } export const ScheduleProvider = ({ children, selectedEventId }: PropsWithChildren) => { - const { cycleInterval, stopCycle } = useScheduleOptions(); - const { data: events } = usePartialRundown((event: OntimeEntry) => { - return isOntimeEvent(event); + const { cycleInterval, stopCycle, filter } = useScheduleOptions(); + const { data: events } = usePartialRundown((entry: OntimeEntry) => { + if (filter) { + // custom keys are prepended with custom- + const customKey = filter.startsWith('custom-') ? filter.slice('custom-'.length) : filter; + return isOntimeEvent(entry) && Boolean(entry.custom[customKey]); + } + return isOntimeEvent(entry); }); const [firstIndex, setFirstIndex] = useState(-1); @@ -135,7 +131,7 @@ export const ScheduleProvider = ({ children, selectedEventId }: PropsWithChildre selectedEventIndex = 0; return ( - {children} - + ); }; export const useSchedule = () => { - const context = useContext(ScheduleContext); + const context = use(ScheduleContext); if (!context) { throw new Error('useSchedule() can only be used inside a ScheduleContext'); } diff --git a/apps/client/src/views/common/schedule/schedule.options.ts b/apps/client/src/views/common/schedule/schedule.options.ts index d2342d365..3e22ed432 100644 --- a/apps/client/src/views/common/schedule/schedule.options.ts +++ b/apps/client/src/views/common/schedule/schedule.options.ts @@ -1,14 +1,23 @@ import { useMemo } from 'react'; import { useSearchParams } from 'react-router'; +import { SelectOption } from '../../../common/components/select/Select'; import { OptionTitle } from '../../../common/components/view-params-editor/constants'; -import { ViewOption } from '../../../common/components/view-params-editor/viewParams.types'; +import type { ViewOption } from '../../../common/components/view-params-editor/viewParams.types'; import { isStringBoolean } from '../../../features/viewers/common/viewUtils'; -export const scheduleOptions: ViewOption = { +export const getScheduleOptions = (customFieldOptions: SelectOption[]): ViewOption => ({ title: OptionTitle.Schedule, collapsible: true, options: [ + { + id: 'filter', + title: 'Filter', + description: 'Hide events without data in the selected custom field', + type: 'option', + values: customFieldOptions, + defaultValue: 'None', + }, { id: 'stopCycle', title: 'Stop cycling through event pages', @@ -31,9 +40,10 @@ export const scheduleOptions: ViewOption = { defaultValue: false, }, ], -}; +}); type ScheduleOptions = { + filter: string | null; cycleInterval: number; stopCycle: boolean; showExpected: boolean; @@ -41,6 +51,7 @@ type ScheduleOptions = { function getScheduleOptionsFromParams(searchParams: URLSearchParams): ScheduleOptions { return { + filter: searchParams.get('filter'), cycleInterval: Number(searchParams.get('cycleInterval')) || 10, stopCycle: isStringBoolean(searchParams.get('stopCycle')), showExpected: isStringBoolean(searchParams.get('showExpected')),