From 1ff27203e43c726b7dd44d8f29348af6d9eac8a1 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Sun, 15 Dec 2024 12:02:04 +0100 Subject: [PATCH] refactor: settings in params --- .../src/features/viewers/common/viewUtils.ts | 4 + apps/client/src/views/cuesheet/Cuesheet.tsx | 16 ++-- .../src/views/cuesheet/CuesheetPage.tsx | 15 ++- .../src/views/cuesheet/cuesheet.options.ts | 95 ++++++++++++++++--- .../src/views/cuesheet/cuesheetCols.tsx | 13 ++- .../cuesheet/store/cuesheetSettingsStore.tsx | 85 ----------------- 6 files changed, 113 insertions(+), 115 deletions(-) delete mode 100644 apps/client/src/views/cuesheet/store/cuesheetSettingsStore.tsx diff --git a/apps/client/src/features/viewers/common/viewUtils.ts b/apps/client/src/features/viewers/common/viewUtils.ts index 32158f01cb..bfc2e30465 100644 --- a/apps/client/src/features/viewers/common/viewUtils.ts +++ b/apps/client/src/features/viewers/common/viewUtils.ts @@ -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; diff --git a/apps/client/src/views/cuesheet/Cuesheet.tsx b/apps/client/src/views/cuesheet/Cuesheet.tsx index bd363f572a..99c8b20f43 100644 --- a/apps/client/src/views/cuesheet/Cuesheet.tsx +++ b/apps/client/src/views/cuesheet/Cuesheet.tsx @@ -11,7 +11,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'; @@ -25,7 +25,7 @@ interface CuesheetProps { } export default function Cuesheet({ data, columns, handleUpdate, selectedId, currentBlockId }: CuesheetProps) { - const { followSelected, showDelayBlock, showPrevious, showIndexColumn } = useCuesheetSettings(); + const { followSelected, hideDelays, hidePast, hideIndexColumn } = useCuesheetOptions(); const { columnVisibility, columnOrder, @@ -102,7 +102,7 @@ export default function Cuesheet({ data, columns, handleUpdate, selectedId, curr />
- + {rowModel.rows.map((row) => { const key = row.original.id; @@ -112,17 +112,17 @@ export default function Cuesheet({ data, columns, handleUpdate, selectedId, curr } if (isOntimeBlock(row.original)) { - if (isPast && !showPrevious && key !== currentBlockId) { + if (isPast && hidePast && key !== currentBlockId) { return null; } return ; } 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; } @@ -132,7 +132,7 @@ export default function Cuesheet({ data, columns, handleUpdate, selectedId, curr eventIndex++; const isSelected = key === selectedId; - if (isPast && !showPrevious) { + if (isPast && hidePast) { return null; } @@ -157,7 +157,7 @@ export default function Cuesheet({ data, columns, handleUpdate, selectedId, curr selectedRef={isSelected ? selectedRef : undefined} skip={row.original.skip} colour={row.original.colour} - showIndexColumn={showIndexColumn} + showIndexColumn={!hideIndexColumn} > {row.getVisibleCells().map((cell) => { return ( diff --git a/apps/client/src/views/cuesheet/CuesheetPage.tsx b/apps/client/src/views/cuesheet/CuesheetPage.tsx index df49c84990..8a08dcb332 100644 --- a/apps/client/src/views/cuesheet/CuesheetPage.tsx +++ b/apps/client/src/views/cuesheet/CuesheetPage.tsx @@ -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 } 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 } = 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 field * Currently, only custom fields can be updated from the cuesheet @@ -85,6 +93,7 @@ export default function CuesheetPage() { return (
+ } - onClick={() => toggleSettings()} + onClick={showEditFormDrawer} /> diff --git a/apps/client/src/views/cuesheet/cuesheet.options.ts b/apps/client/src/views/cuesheet/cuesheet.options.ts index c57bc6e2ad..82568c5d45 100644 --- a/apps/client/src/views/cuesheet/cuesheet.options.ts +++ b/apps/client/src/views/cuesheet/cuesheet.options.ts @@ -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; +}; + +/** + * Utility extract the view options from URL Params + * the names and fallbacks are manually matched with cuesheetOptions + */ +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')), + }; +} + /** - * @description set default hidden columns + * Hook exposes the cuesheet view options */ -export const defaultHiddenColumns: (keyof OntimeEvent)[] = []; +export function useCuesheetOptions(): CuesheetOptions { + const [searchParams] = useSearchParams(); + const options = useMemo(() => getOptionsFromParams(searchParams), [searchParams]); + return options; +} diff --git a/apps/client/src/views/cuesheet/cuesheetCols.tsx b/apps/client/src/views/cuesheet/cuesheetCols.tsx index 42b91ddc0d..ec0b5f86c5 100644 --- a/apps/client/src/views/cuesheet/cuesheetCols.tsx +++ b/apps/client/src/views/cuesheet/cuesheetCols.tsx @@ -7,7 +7,7 @@ import DelayIndicator from '../../common/components/delay-indicator/DelayIndicat import RunningTime from '../../features/viewers/common/running-time/RunningTime'; import EditableCell from './cuesheet-table-elements/EditableCell'; -import { useCuesheetSettings } from './store/cuesheetSettingsStore'; +import { useCuesheetOptions } from './cuesheet.options'; import style from './Cuesheet.module.scss'; @@ -17,27 +17,26 @@ function makePublic(row: CellContext) { } function MakeTimer({ getValue, row: { original } }: CellContext) { - 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 ( - + {delayValue !== 0 && showDelayedTimes && ( - + )} ); } function MakeDuration({ getValue }: CellContext) { - const hideSeconds = useCuesheetSettings((state) => state.hideSeconds); + const { hideTableSeconds } = useCuesheetOptions(); const cellValue = (getValue() as number | null) ?? 0; - return ; + return ; } function MakeCustomField({ row, column, table }: CellContext) { diff --git a/apps/client/src/views/cuesheet/store/cuesheetSettingsStore.tsx b/apps/client/src/views/cuesheet/store/cuesheetSettingsStore.tsx deleted file mode 100644 index f9eb5d0fbe..0000000000 --- a/apps/client/src/views/cuesheet/store/cuesheetSettingsStore.tsx +++ /dev/null @@ -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()((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 }; - }), -}));