mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-18 21:54:09 +00:00
Feat: unify view search params (#1947)
* feat: main src in backstage view * feat: main src in timeline view * feat: main src in countdown view * feat: main src in studio view * feat: hide past events in countdown view * notes can not be set as main src * feat: show group title as secondary src * chore: spelling Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com> --------- Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
ec1890c275
commit
026e24bf84
@@ -6,6 +6,7 @@ import { dayInMs, getLastEvent, MILLIS_PER_HOUR } from 'ontime-utils';
|
||||
import useHorizontalFollowComponent from '../../common/hooks/useHorizontalFollowComponent';
|
||||
import { ExtendedEntry } from '../../common/utils/rundownMetadata';
|
||||
import { cx } from '../../common/utils/styleUtils';
|
||||
import { getPropertyValue } from '../common/viewUtils';
|
||||
|
||||
import TimelineMarkers from './timeline-markers/TimelineMarkers';
|
||||
import { useTimelineOptions } from './timeline.options';
|
||||
@@ -24,7 +25,7 @@ interface TimelineProps {
|
||||
export default memo(Timeline);
|
||||
function Timeline({ firstStart, rundown, selectedEventId, totalDuration }: TimelineProps) {
|
||||
const { width: screenWidth } = useViewportSize();
|
||||
const { hidePast, fixedSize } = useTimelineOptions();
|
||||
const { mainSource, hidePast, fixedSize } = useTimelineOptions();
|
||||
const selectedRef = useRef<HTMLDivElement>(null);
|
||||
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
@@ -86,6 +87,8 @@ function Timeline({ firstStart, rundown, selectedEventId, totalDuration }: Timel
|
||||
const position = positions[index];
|
||||
if (!position) return null;
|
||||
|
||||
const displayTitle = getPropertyValue(event, mainSource ?? 'title') || event.title;
|
||||
|
||||
return (
|
||||
<TimelineEntry
|
||||
key={event.id}
|
||||
@@ -100,7 +103,7 @@ function Timeline({ firstStart, rundown, selectedEventId, totalDuration }: Timel
|
||||
totalGap={event.totalGap}
|
||||
isLinkedToLoaded={event.isLinkedToLoaded}
|
||||
dayOffset={event.dayOffset}
|
||||
title={event.title}
|
||||
title={displayTitle}
|
||||
cue={event.cue}
|
||||
width={position.width}
|
||||
/>
|
||||
|
||||
@@ -12,7 +12,7 @@ import Loader from '../common/loader/Loader';
|
||||
import SuperscriptTime from '../common/superscript-time/SuperscriptTime';
|
||||
|
||||
import Timeline from './Timeline';
|
||||
import { getTimelineOptions } from './timeline.options';
|
||||
import { getTimelineOptions, useTimelineOptions } from './timeline.options';
|
||||
import { getUpcomingEvents, useScopedRundown } from './timeline.utils';
|
||||
import TimelineSections from './TimelineSections';
|
||||
import { TimelineData, useTimelineData } from './useTimelineData';
|
||||
@@ -35,8 +35,9 @@ export default function TimelinePageLoader() {
|
||||
return <TimelinePage {...data} />;
|
||||
}
|
||||
|
||||
function TimelinePage({ events, projectData, settings }: TimelineData) {
|
||||
function TimelinePage({ events, customFields, projectData, settings }: TimelineData) {
|
||||
const { selectedEventId } = useSelectedEventId();
|
||||
const { mainSource } = useTimelineOptions();
|
||||
// holds copy of the rundown with only relevant events
|
||||
const { scopedRundown, firstStart, totalDuration } = useScopedRundown(events, selectedEventId);
|
||||
|
||||
@@ -47,7 +48,7 @@ function TimelinePage({ events, projectData, settings }: TimelineData) {
|
||||
|
||||
// populate options
|
||||
const defaultFormat = getDefaultFormat(settings?.timeFormat);
|
||||
const progressOptions = useMemo(() => getTimelineOptions(defaultFormat), [defaultFormat]);
|
||||
const progressOptions = useMemo(() => getTimelineOptions(defaultFormat, customFields), [defaultFormat, customFields]);
|
||||
|
||||
return (
|
||||
<div className='timeline' data-testid='timeline-view'>
|
||||
@@ -58,7 +59,7 @@ function TimelinePage({ events, projectData, settings }: TimelineData) {
|
||||
<TimelineClock />
|
||||
</div>
|
||||
|
||||
<TimelineSections now={now} next={next} followedBy={followedBy} />
|
||||
<TimelineSections now={now} next={next} followedBy={followedBy} mainSource={mainSource} />
|
||||
|
||||
<Timeline
|
||||
firstStart={firstStart}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useExpectedStartData } from '../../common/hooks/useSocket';
|
||||
import { ExtendedEntry } from '../../common/utils/rundownMetadata';
|
||||
import { formatDuration, getExpectedTimesFromExtendedEvent } from '../../common/utils/time';
|
||||
import { useTranslation } from '../../translation/TranslationProvider';
|
||||
import { getPropertyValue } from '../common/viewUtils';
|
||||
|
||||
import TimelineSection from './timeline-section/TimelineSection';
|
||||
|
||||
@@ -12,17 +13,18 @@ interface TimelineSectionsProps {
|
||||
now: ExtendedEntry<OntimeEvent> | null;
|
||||
next: ExtendedEntry<OntimeEvent> | null;
|
||||
followedBy: ExtendedEntry<OntimeEvent> | null;
|
||||
mainSource: keyof OntimeEvent | null;
|
||||
}
|
||||
|
||||
export default function TimelineSections({ now, next, followedBy }: TimelineSectionsProps) {
|
||||
export default function TimelineSections({ now, next, followedBy, mainSource }: TimelineSectionsProps) {
|
||||
const { getLocalizedString } = useTranslation();
|
||||
const state = useExpectedStartData();
|
||||
|
||||
// gather card data
|
||||
const titleNow = now?.title ?? '-';
|
||||
const titleNow = getPropertyValue(now, mainSource ?? 'title') ?? '-';
|
||||
const dueText = getLocalizedString('timeline.due').toUpperCase();
|
||||
const nextText = next !== null ? next.title : '-';
|
||||
const followedByText = followedBy !== null ? followedBy.title : '-';
|
||||
const nextText = getPropertyValue(next, mainSource ?? 'title') ?? '-';
|
||||
const followedByText = getPropertyValue(followedBy, mainSource ?? 'title') ?? '-';
|
||||
let nextStatus: string | undefined;
|
||||
let followedByStatus: string | undefined;
|
||||
|
||||
|
||||
@@ -1,15 +1,33 @@
|
||||
import { use, useMemo } from 'react';
|
||||
import { useSearchParams } from 'react-router';
|
||||
import { CustomFields, OntimeEvent } from 'ontime-types';
|
||||
|
||||
import { getTimeOption } from '../../common/components/view-params-editor/common.options';
|
||||
import { OptionTitle } from '../../common/components/view-params-editor/constants';
|
||||
import { ViewOption } from '../../common/components/view-params-editor/viewParams.types';
|
||||
import { makeOptionsFromCustomFields } from '../../common/components/view-params-editor/viewParams.utils';
|
||||
import { PresetContext } from '../../common/context/PresetContext';
|
||||
import { isStringBoolean } from '../common/viewUtils';
|
||||
|
||||
export const getTimelineOptions = (timeFormat: string): ViewOption[] => {
|
||||
export const getTimelineOptions = (timeFormat: string, customFields: CustomFields): ViewOption[] => {
|
||||
const mainOptions = makeOptionsFromCustomFields(customFields, [{ value: 'title', label: 'Title' }]);
|
||||
|
||||
return [
|
||||
{ title: OptionTitle.ClockOptions, collapsible: true, options: [getTimeOption(timeFormat)] },
|
||||
{
|
||||
title: OptionTitle.DataSources,
|
||||
collapsible: true,
|
||||
options: [
|
||||
{
|
||||
id: 'main',
|
||||
title: 'Main text',
|
||||
description: 'Select the data source for the main text',
|
||||
type: 'option',
|
||||
values: mainOptions,
|
||||
defaultValue: 'title',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: OptionTitle.ElementVisibility,
|
||||
collapsible: true,
|
||||
@@ -34,6 +52,7 @@ export const getTimelineOptions = (timeFormat: string): ViewOption[] => {
|
||||
};
|
||||
|
||||
type TimelineOptions = {
|
||||
mainSource: keyof OntimeEvent | null;
|
||||
hidePast: boolean;
|
||||
fixedSize: boolean;
|
||||
};
|
||||
@@ -47,6 +66,7 @@ function getOptionsFromParams(searchParams: URLSearchParams, defaultValues?: URL
|
||||
const getValue = (key: string) => defaultValues?.get(key) ?? searchParams.get(key);
|
||||
|
||||
return {
|
||||
mainSource: getValue('main') as keyof OntimeEvent | null,
|
||||
hidePast: isStringBoolean(getValue('hidePast')),
|
||||
fixedSize: isStringBoolean(getValue('fixedSize')),
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { OntimeEntry, ProjectData, Settings } from 'ontime-types';
|
||||
import { CustomFields, OntimeEntry, ProjectData, Settings } from 'ontime-types';
|
||||
|
||||
import useCustomFields from '../../common/hooks-query/useCustomFields';
|
||||
import useProjectData from '../../common/hooks-query/useProjectData';
|
||||
import { useFlatRundownWithMetadata } from '../../common/hooks-query/useRundown';
|
||||
import useSettings from '../../common/hooks-query/useSettings';
|
||||
@@ -8,6 +9,7 @@ import { aggregateQueryStatus, ViewData } from '../utils/viewLoader.utils';
|
||||
|
||||
export interface TimelineData {
|
||||
events: ExtendedEntry<OntimeEntry>[];
|
||||
customFields: CustomFields;
|
||||
projectData: ProjectData;
|
||||
settings: Settings;
|
||||
}
|
||||
@@ -17,13 +19,15 @@ export function useTimelineData(): ViewData<TimelineData> {
|
||||
const { data: rundownData, status: rundownStatus } = useFlatRundownWithMetadata();
|
||||
const { data: projectData, status: projectDataStatus } = useProjectData();
|
||||
const { data: settings, status: settingsStatus } = useSettings();
|
||||
const { data: customFields, status: customFieldsStatus } = useCustomFields();
|
||||
|
||||
return {
|
||||
data: {
|
||||
events: rundownData,
|
||||
customFields,
|
||||
projectData,
|
||||
settings,
|
||||
},
|
||||
status: aggregateQueryStatus([rundownStatus, projectDataStatus, settingsStatus]),
|
||||
status: aggregateQueryStatus([rundownStatus, projectDataStatus, settingsStatus, customFieldsStatus]),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user