refactor: settings in params

This commit is contained in:
Carlos Valente
2024-12-15 12:02:04 +01:00
committed by Carlos Valente
parent e91d5f5cd9
commit 41fe213ebb
6 changed files with 113 additions and 115 deletions
@@ -32,6 +32,10 @@ export function getTimerByType(freezeEnd: boolean, timerObject?: TimerTypeParams
}
}
/**
* Parses a string to semantically verify if it represents a true value
* Used in the context of parsing search params and local storage items which can be strings or null
*/
export function isStringBoolean(text: string | null) {
if (text === null) {
return false;
+8 -8
View File
@@ -18,7 +18,7 @@ import CuesheetHeader from './cuesheet-table-elements/CuesheetHeader';
import DelayRow from './cuesheet-table-elements/DelayRow';
import EventRow from './cuesheet-table-elements/EventRow';
import CuesheetTableSettings from './cuesheet-table-settings/CuesheetTableSettings';
import { useCuesheetSettings } from './store/cuesheetSettingsStore';
import { useCuesheetOptions } from './cuesheet.options';
import useColumnManager from './useColumnManager';
import style from './Cuesheet.module.scss';
@@ -40,7 +40,7 @@ export default function Cuesheet({
selectedId,
currentBlockId,
}: CuesheetProps) {
const { followSelected, showDelayBlock, showPrevious, showIndexColumn } = useCuesheetSettings();
const { followSelected, hideDelays, hidePast, hideIndexColumn } = useCuesheetOptions();
const {
columnVisibility,
columnOrder,
@@ -118,7 +118,7 @@ export default function Cuesheet({
/>
<div ref={tableContainerRef} className={style.cuesheetContainer}>
<table className={style.cuesheet}>
<CuesheetHeader headerGroups={headerGroups} saveColumnOrder={reorder} showIndexColumn={showIndexColumn} />
<CuesheetHeader headerGroups={headerGroups} saveColumnOrder={reorder} showIndexColumn={!hideIndexColumn} />
<tbody>
{rowModel.rows.map((row) => {
const key = row.original.id;
@@ -128,17 +128,17 @@ export default function Cuesheet({
}
if (isOntimeBlock(row.original)) {
if (isPast && !showPrevious && key !== currentBlockId) {
if (isPast && hidePast && key !== currentBlockId) {
return null;
}
return <BlockRow key={key} title={row.original.title} />;
}
if (isOntimeDelay(row.original)) {
if (isPast && !showPrevious) {
if (isPast && hidePast) {
return null;
}
const delayVal = row.original.duration;
if (!showDelayBlock || delayVal === 0) {
if (hideDelays || delayVal === 0) {
return null;
}
@@ -148,7 +148,7 @@ export default function Cuesheet({
eventIndex++;
const isSelected = key === selectedId;
if (isPast && !showPrevious) {
if (isPast && hidePast) {
return null;
}
@@ -173,7 +173,7 @@ export default function Cuesheet({
selectedRef={isSelected ? selectedRef : undefined}
skip={row.original.skip}
colour={row.original.colour}
showIndexColumn={showIndexColumn}
showIndexColumn={!hideIndexColumn}
>
{row.getVisibleCells().map((cell) => {
return (
@@ -1,4 +1,5 @@
import { useCallback, useMemo } from 'react';
import { useSearchParams } from 'react-router-dom';
import { IconButton, useDisclosure } from '@chakra-ui/react';
import { IoApps } from '@react-icons/all-files/io5/IoApps';
import { IoSettingsOutline } from '@react-icons/all-files/io5/IoSettingsOutline';
@@ -6,6 +7,7 @@ import { CustomFieldLabel, isOntimeEvent, OntimeEvent } from 'ontime-types';
import ProductionNavigationMenu from '../../common/components/navigation-menu/ProductionNavigationMenu';
import EmptyPage from '../../common/components/state/EmptyPage';
import ViewParamsEditor from '../../common/components/view-params-editor/ViewParamsEditor';
import { useEventAction } from '../../common/hooks/useEventAction';
import { useCuesheet } from '../../common/hooks/useSocket';
import { useWindowTitle } from '../../common/hooks/useWindowTitle';
@@ -14,8 +16,8 @@ import { useFlatRundown } from '../../common/hooks-query/useRundown';
import { CuesheetOverview } from '../../features/overview/Overview';
import CuesheetProgress from './cuesheet-progress/CuesheetProgress';
import { useCuesheetSettings } from './store/cuesheetSettingsStore';
import Cuesheet from './Cuesheet';
import { cuesheetOptions } from './cuesheet.options';
import { makeCuesheetColumns } from './cuesheetCols';
import styles from './CuesheetPage.module.scss';
@@ -24,15 +26,21 @@ export default function CuesheetPage() {
// TODO: can we use the normalised rundown for the table?
const { data: flatRundown, status: rundownStatus } = useFlatRundown();
const { data: customFields } = useCustomFields();
const [searchParams, setSearchParams] = useSearchParams();
const { isOpen: isMenuOpen, onOpen, onClose } = useDisclosure();
const { updateCustomField, updateEvent } = useEventAction();
const featureData = useCuesheet();
const columns = useMemo(() => makeCuesheetColumns(customFields), [customFields]);
const toggleSettings = useCuesheetSettings((state) => state.toggleSettings);
useWindowTitle('Cuesheet');
/** Handles showing the view params edit drawer */
const showEditFormDrawer = useCallback(() => {
searchParams.set('edit', 'true');
setSearchParams(searchParams);
}, [searchParams, setSearchParams]);
/**
* Handles updating a custom field
*/
@@ -99,6 +107,7 @@ export default function CuesheetPage() {
return (
<div className={styles.tableWrapper} data-testid='cuesheet'>
<ProductionNavigationMenu isMenuOpen={isMenuOpen} onMenuClose={onClose} />
<ViewParamsEditor viewOptions={cuesheetOptions} />
<CuesheetOverview>
<IconButton
aria-label='Toggle navigation'
@@ -112,7 +121,7 @@ export default function CuesheetPage() {
variant='ontime-subtle-white'
size='lg'
icon={<IoSettingsOutline />}
onClick={() => toggleSettings()}
onClick={showEditFormDrawer}
/>
</CuesheetOverview>
<CuesheetProgress />
@@ -1,19 +1,90 @@
import { OntimeEntryCommonKeys, OntimeEvent } from 'ontime-types';
import { useMemo } from 'react';
import { useSearchParams } from 'react-router-dom';
import { ViewOption } from '../../common/components/view-params-editor/types';
import { isStringBoolean } from '../../features/viewers/common/viewUtils';
/**
* @description set default column order
* In the specific case of the cuesheet options
* we save the user preferences in the local storage
*/
export const defaultColumnOrder: OntimeEntryCommonKeys[] = [
'isPublic',
'cue',
'timeStart',
'timeEnd',
'duration',
'title',
'note',
export const cuesheetOptions: ViewOption[] = [
{ section: 'Table options' },
{
id: 'hideTableSeconds',
title: 'Hide seconds in table',
description: 'Whether to hide seconds in the time fields displayed in the table',
type: 'boolean',
defaultValue: false,
},
{
id: 'followSelected',
title: 'Follow selected event',
description: 'Whether the view should automatically scroll to the selected event',
type: 'boolean',
defaultValue: false,
},
{
id: 'hidePast',
title: 'Hide Past Events',
description: 'Whether to hide events that have passed',
type: 'boolean',
defaultValue: false,
},
{
id: 'hideIndexColumn',
title: 'Hide index column',
description: 'Whether the hide the event indexes in the table',
type: 'boolean',
defaultValue: false,
},
{ section: 'Delay flow' },
{
id: 'showDelayedTimes',
title: 'Show delayed times',
description: 'Whether the time fields should include delays',
type: 'boolean',
defaultValue: false,
},
{
id: 'hideDelays',
title: 'Hide delays',
description: 'Whether to hide the rows containing scheduled delays',
type: 'boolean',
defaultValue: false,
},
];
type CuesheetOptions = {
hideTableSeconds: boolean;
followSelected: boolean;
hidePast: boolean;
hideIndexColumn: boolean;
showDelayedTimes: boolean;
hideDelays: boolean;
};
/**
* @description set default hidden columns
* Utility extract the view options from URL Params
* the names and fallbacks are manually matched with cuesheetOptions
*/
export const defaultHiddenColumns: (keyof OntimeEvent)[] = [];
export function getOptionsFromParams(searchParams: URLSearchParams): CuesheetOptions {
// we manually make an object that matches the key above
return {
hideTableSeconds: isStringBoolean(searchParams.get('hideTableSeconds')),
followSelected: isStringBoolean(searchParams.get('followSelected')),
hidePast: isStringBoolean(searchParams.get('hidePast')),
hideIndexColumn: isStringBoolean(searchParams.get('hideIndexColumn')),
showDelayedTimes: isStringBoolean(searchParams.get('showDelayedTimes')),
hideDelays: isStringBoolean(searchParams.get('hideDelays')),
};
}
/**
* Hook exposes the cuesheet view options
*/
export function useCuesheetOptions(): CuesheetOptions {
const [searchParams] = useSearchParams();
const options = useMemo(() => getOptionsFromParams(searchParams), [searchParams]);
return options;
}
@@ -8,7 +8,7 @@ import RunningTime from '../../features/viewers/common/running-time/RunningTime'
import MultiLineCell from './cuesheet-table-elements/MultiLineCell';
import SingleLineCell from './cuesheet-table-elements/SingleLineCell';
import { useCuesheetSettings } from './store/cuesheetSettingsStore';
import { useCuesheetOptions } from './cuesheet.options';
import style from './Cuesheet.module.scss';
@@ -35,27 +35,26 @@ function MakePublic({ row, column, table }: CellContext<OntimeRundownEntry, unkn
}
function MakeTimer({ getValue, row: { original } }: CellContext<OntimeRundownEntry, unknown>) {
const showDelayedTimes = useCuesheetSettings((state) => state.showDelayedTimes);
const hideSeconds = useCuesheetSettings((state) => state.hideSeconds);
const { showDelayedTimes, hideTableSeconds } = useCuesheetOptions();
const cellValue = (getValue() as number | null) ?? 0;
const delayValue = (original as OntimeEvent)?.delay ?? 0;
return (
<span className={style.time}>
<DelayIndicator delayValue={delayValue} />
<RunningTime value={cellValue} hideSeconds={hideSeconds} />
<RunningTime value={cellValue} hideSeconds={hideTableSeconds} />
{delayValue !== 0 && showDelayedTimes && (
<RunningTime className={style.delayedTime} value={cellValue + delayValue} hideSeconds={hideSeconds} />
<RunningTime className={style.delayedTime} value={cellValue + delayValue} hideSeconds={hideTableSeconds} />
)}
</span>
);
}
function MakeDuration({ getValue }: CellContext<OntimeRundownEntry, unknown>) {
const hideSeconds = useCuesheetSettings((state) => state.hideSeconds);
const { hideTableSeconds } = useCuesheetOptions();
const cellValue = (getValue() as number | null) ?? 0;
return <RunningTime value={cellValue} hideSeconds={hideSeconds} />;
return <RunningTime value={cellValue} hideSeconds={hideTableSeconds} />;
}
function MakeMultiLineField({ row, column, table }: CellContext<OntimeRundownEntry, unknown>) {
@@ -1,85 +0,0 @@
import { create } from 'zustand';
import { booleanFromLocalStorage } from '../../../common/utils/localStorage';
interface CuesheetSettingsStore {
showSettings: boolean;
showIndexColumn: boolean;
followSelected: boolean;
showPrevious: boolean;
showDelayBlock: boolean;
showDelayedTimes: boolean;
hideSeconds: boolean;
toggleSettings: (newValue?: boolean) => void;
toggleFollow: (newValue?: boolean) => void;
togglePreviousVisibility: (newValue?: boolean) => void;
toggleIndexColumn: (newValue?: boolean) => void;
toggleDelayVisibility: (newValue?: boolean) => void;
toggleDelayedTimes: (newValue?: boolean) => void;
toggleSecondsVisibility: (newValue?: boolean) => void;
}
function toggle(oldValue: boolean, value?: boolean) {
if (typeof value === 'undefined') {
return !oldValue;
}
return value;
}
enum CuesheetKeys {
Follow = 'ontime-cuesheet-follow-selected',
DelayVisibility = 'ontime-cuesheet-show-delay',
PreviousVisibility = 'ontime-cuesheet-show-previous',
ColumnIndex = 'ontime-cuesheet-show-index-column',
DelayedTimes = 'ontime-cuesheet-show-delayed',
Seconds = 'ontime-cuesheet-hide-sceconds',
}
export const useCuesheetSettings = create<CuesheetSettingsStore>()((set) => ({
showSettings: false,
showIndexColumn: booleanFromLocalStorage(CuesheetKeys.ColumnIndex, true),
followSelected: booleanFromLocalStorage(CuesheetKeys.Follow, false),
showPrevious: booleanFromLocalStorage(CuesheetKeys.PreviousVisibility, true),
showDelayBlock: booleanFromLocalStorage(CuesheetKeys.DelayVisibility, true),
showDelayedTimes: booleanFromLocalStorage(CuesheetKeys.DelayedTimes, false),
hideSeconds: booleanFromLocalStorage(CuesheetKeys.Seconds, false),
toggleSettings: (newValue?: boolean) => set((state) => ({ showSettings: toggle(state.showSettings, newValue) })),
toggleFollow: (newValue?: boolean) =>
set((state) => {
const followSelected = toggle(state.followSelected, newValue);
localStorage.setItem(CuesheetKeys.Follow, String(followSelected));
return { followSelected };
}),
toggleIndexColumn: (newValue?: boolean) =>
set((state) => {
const showIndexColumn = toggle(state.showIndexColumn, newValue);
localStorage.setItem(CuesheetKeys.ColumnIndex, String(showIndexColumn));
return { showIndexColumn };
}),
togglePreviousVisibility: (newValue?: boolean) =>
set((state) => {
const showPrevious = toggle(state.showPrevious, newValue);
localStorage.setItem(CuesheetKeys.PreviousVisibility, String(showPrevious));
return { showPrevious };
}),
toggleDelayVisibility: (newValue?: boolean) =>
set((state) => {
const showDelayBlock = toggle(state.showDelayBlock, newValue);
localStorage.setItem(CuesheetKeys.DelayVisibility, String(showDelayBlock));
return { showDelayBlock };
}),
toggleDelayedTimes: (newValue?: boolean) =>
set((state) => {
const showDelayedTimes = toggle(state.showDelayedTimes, newValue);
localStorage.setItem(CuesheetKeys.DelayedTimes, String(showDelayedTimes));
return { showDelayedTimes };
}),
toggleSecondsVisibility: (newValue?: boolean) =>
set((state) => {
const hideSeconds = toggle(state.hideSeconds, newValue);
localStorage.setItem(CuesheetKeys.Seconds, String(hideSeconds));
return { hideSeconds };
}),
}));