feat: option to select all events for countdown

This commit is contained in:
arc-alex
2025-09-16 16:59:29 +02:00
parent 9288566a7f
commit 6397d33eaa
4 changed files with 49 additions and 17 deletions
@@ -1,6 +1,6 @@
import { useMemo, useState } from 'react';
import { IoAdd } from 'react-icons/io5';
import { EntryId, isOntimeEvent, isPlayableEvent, OntimeEvent, OntimeView } from 'ontime-types';
import { isOntimeEvent, isPlayableEvent, OntimeEvent, OntimeView } from 'ontime-types';
import Button from '../../common/components/buttons/Button';
import Empty from '../../common/components/state/Empty';
@@ -16,7 +16,7 @@ import { useTranslation } from '../../translation/TranslationProvider';
import Loader from '../common/loader/Loader';
import { getCountdownOptions, useCountdownOptions } from './countdown.options';
import { getOrderedSubscriptions } from './countdown.utils';
import { CountdownSubscription, getOrderedSubscriptions } from './countdown.utils';
import CountdownSelect from './CountdownSelect';
import CountdownSubscriptions from './CountdownSubscriptions';
import SingleEventCountdown from './SingleEventCountdown';
@@ -59,6 +59,8 @@ function Countdown({ customFields, rundownData, projectData, isMirrored, setting
[defaultFormat, customFields, subscriptions],
);
console.log(subscriptions)
return (
<div className={`countdown ${isMirrored ? 'mirror' : ''}`} data-testid='countdown-view'>
<ViewParamsEditor target={OntimeView.Countdown} viewOptions={countdownOptions} />
@@ -87,7 +89,7 @@ function Countdown({ customFields, rundownData, projectData, isMirrored, setting
interface CountdownContentsProps {
playableEvents: ExtendedEntry<OntimeEvent>[];
subscriptions: EntryId[];
subscriptions: CountdownSubscription;
goToEditMode: () => void;
}
@@ -1,5 +1,5 @@
import { useState } from 'react';
import { IoArrowBack, IoClose, IoSaveOutline } from 'react-icons/io5';
import { IoArrowBack, IoClose, IoSaveOutline, IoAlbumsOutline } from 'react-icons/io5';
import { useNavigate } from 'react-router';
import { EntryId, OntimeEvent } from 'ontime-types';
@@ -7,18 +7,19 @@ import Button from '../../common/components/buttons/Button';
import { cx } from '../../common/utils/styleUtils';
import ClockTime from '../../features/viewers/common/clock-time/ClockTime';
import { makeSubscriptionsUrl } from './countdown.utils';
import { CountdownSubscription, makeSubscriptionsUrl } from './countdown.utils';
import './Countdown.scss';
interface CountdownSelectProps {
events: OntimeEvent[];
subscriptions: EntryId[];
subscriptions: CountdownSubscription;
disableEdit: () => void;
}
export default function CountdownSelect({ events, subscriptions, disableEdit }: CountdownSelectProps) {
const [selected, setSelected] = useState<EntryId[]>(subscriptions);
const maybeAllSubscriptions: EntryId[] = subscriptions === 'all' ? events.map((event) => event.id) : subscriptions;
const [selected, setSelected] = useState<EntryId[]>(maybeAllSubscriptions);
const navigate = useNavigate();
/**
@@ -47,6 +48,18 @@ export default function CountdownSelect({ events, subscriptions, disableEdit }:
navigate(url.search.toString());
};
/**
* Creates a URL with all
* and navigates to it
*/
const applyAll = () => {
// we remove events that no longer exist to avoid stale subscriptions
const url = makeSubscriptionsUrl(window.location.href, 'all');
disableEdit();
setSelected([]);
navigate(url.search.toString());
};
// make a copy of the selected array for quick lookup
const selectedIds = new Set(selected);
@@ -86,6 +99,10 @@ export default function CountdownSelect({ events, subscriptions, disableEdit }:
<Button variant='subtle' size='xlarge' onClick={disableEdit}>
<IoArrowBack /> Go back
</Button>
<Button variant='subtle' size='xlarge' onClick={applyAll}>
{/* TODO: icon ??? */}
<IoAlbumsOutline /> Use All
</Button>
<Button variant='subtle' size='xlarge' onClick={() => setSelected([])} disabled={selected.length === 0}>
<IoClose /> Clear
</Button>
@@ -8,11 +8,12 @@ import { ViewOption } from '../../common/components/view-params-editor/viewParam
import { makeOptionsFromCustomFields } from '../../common/components/view-params-editor/viewParams.utils';
import { PresetContext } from '../../common/context/PresetContext';
import { isStringBoolean } from '../../features/viewers/common/viewUtils';
import { CountdownSubscription } from './countdown.utils';
export const getCountdownOptions = (
timeFormat: string,
customFields: CustomFields,
persistedSubscriptions: EntryId[],
persistedSubscriptions: CountdownSubscription,
): ViewOption[] => {
const secondaryOptions = makeOptionsFromCustomFields(customFields, [
{ value: 'none', label: 'None' },
@@ -55,7 +56,7 @@ export const getCountdownOptions = (
id: 'sub',
title: 'Event subscription',
description: 'The events to follow',
values: persistedSubscriptions,
values: persistedSubscriptions === 'all' ? ['all'] : persistedSubscriptions,
type: 'persist',
},
],
@@ -64,7 +65,7 @@ export const getCountdownOptions = (
};
type CountdownOptions = {
subscriptions: EntryId[];
subscriptions: CountdownSubscription;
secondarySource: keyof OntimeEvent | null;
showExpected: boolean;
};
@@ -85,8 +86,10 @@ function getOptionsFromParams(searchParams: URLSearchParams, defaultValues?: URL
return searchParams.getAll(key) as EntryId[];
};
const subscriptions = getArrayValues('sub');
return {
subscriptions: getArrayValues('sub'),
subscriptions: subscriptions.at(0) === 'all' ? 'all' : subscriptions,
secondarySource: getValue('secondary-src') as keyof OntimeEvent | null,
showExpected: isStringBoolean(getValue('showExpected')),
};
@@ -14,6 +14,8 @@ export function sanitiseTitle(title: string | null) {
return title ?? '{no title}';
}
export type CountdownSubscription = EntryId[] | 'all';
export const preferredFormat12 = 'h:mm a';
export const preferredFormat24 = 'HH:mm';
@@ -120,7 +122,7 @@ export function useSubscriptionDisplayData(
/**
* Adds a set of subscriptions to the URL parameters
*/
export function makeSubscriptionsUrl(urlRef: string, subscriptions: EntryId[]) {
export function makeSubscriptionsUrl(urlRef: string, subscriptions: CountdownSubscription) {
const url = new URL(urlRef);
const newParams = new URLSearchParams();
@@ -131,10 +133,14 @@ export function makeSubscriptionsUrl(urlRef: string, subscriptions: EntryId[]) {
}
}
// add new subscriptions
subscriptions.forEach((id) => {
newParams.append('sub', id);
});
if (subscriptions === 'all') {
newParams.append('sub', 'all');
} else {
// add new subscriptions
subscriptions.forEach((id) => {
newParams.append('sub', id);
});
}
url.search = newParams.toString();
@@ -146,7 +152,11 @@ export function makeSubscriptionsUrl(urlRef: string, subscriptions: EntryId[]) {
* Since the original array is already ordered, we simply filter out the events
* which are not in the subscriptions list.
*/
export function getOrderedSubscriptions<T extends OntimeEntry>(subscriptions: EntryId[], playableEvents: T[]): T[] {
export function getOrderedSubscriptions<T extends OntimeEntry>(
subscriptions: CountdownSubscription,
playableEvents: T[],
): T[] {
if (subscriptions === 'all') return playableEvents;
return playableEvents.filter((event) => subscriptions.includes(event.id));
}