Event defaults (#910)

* chore: cleanup outdated comment

* style: align blocks

* style: use ui-black background

* chore: clarify docs

* feat: event defaults

* chore: cleanup
This commit is contained in:
Carlos Valente
2024-04-24 20:13:51 +02:00
committed by GitHub
parent c4f51192de
commit 817ebcdd26
11 changed files with 133 additions and 78 deletions
+14 -2
View File
@@ -25,7 +25,7 @@ import { forgivingStringToMillis } from '../utils/dateConfig';
*/ */
export const useEventAction = () => { export const useEventAction = () => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const { defaultPublic, linkPrevious, defaultDuration } = useEditorSettings((state) => state.eventSettings); const { defaultPublic, linkPrevious, defaultDuration, defaultWarnTime, defaultDangerTime } = useEditorSettings();
/** /**
* Calls mutation to add new event * Calls mutation to add new event
@@ -48,6 +48,8 @@ export const useEventAction = () => {
defaultPublic: boolean; defaultPublic: boolean;
linkPrevious: boolean; linkPrevious: boolean;
lastEventId: string; lastEventId: string;
defaultWarnTime: number;
defaultDangerTime: number;
}>; }>;
/** /**
@@ -64,6 +66,8 @@ export const useEventAction = () => {
defaultPublic: options?.defaultPublic ?? defaultPublic, defaultPublic: options?.defaultPublic ?? defaultPublic,
lastEventId: options?.lastEventId, lastEventId: options?.lastEventId,
linkPrevious: options?.linkPrevious ?? linkPrevious, linkPrevious: options?.linkPrevious ?? linkPrevious,
defaultWarnTime,
defaultDangerTime,
}; };
if (applicationOptions.linkPrevious && applicationOptions?.lastEventId) { if (applicationOptions.linkPrevious && applicationOptions?.lastEventId) {
@@ -85,6 +89,14 @@ export const useEventAction = () => {
if (newEvent.duration === undefined && newEvent.timeEnd === undefined) { if (newEvent.duration === undefined && newEvent.timeEnd === undefined) {
newEvent.duration = forgivingStringToMillis(defaultDuration); newEvent.duration = forgivingStringToMillis(defaultDuration);
} }
if (newEvent.timeDanger === undefined) {
newEvent.timeDanger = forgivingStringToMillis(defaultDangerTime);
}
if (newEvent.timeWarning === undefined) {
newEvent.timeWarning = forgivingStringToMillis(defaultWarnTime);
}
} }
// handle adding options that concern all event type // handle adding options that concern all event type
@@ -98,7 +110,7 @@ export const useEventAction = () => {
logAxiosError('Failed adding event', error); logAxiosError('Failed adding event', error);
} }
}, },
[_addEventMutation, defaultDuration, defaultPublic, linkPrevious], [_addEventMutation, defaultDangerTime, defaultDuration, defaultPublic, defaultWarnTime, linkPrevious, queryClient],
); );
/** /**
+54 -41
View File
@@ -2,55 +2,68 @@ import { create } from 'zustand';
import { booleanFromLocalStorage } from '../utils/localStorage'; import { booleanFromLocalStorage } from '../utils/localStorage';
type EditorSettings = { type EditorSettingsStore = {
linkPrevious: boolean;
defaultPublic: boolean;
defaultDuration: string; defaultDuration: string;
linkPrevious: boolean;
defaultWarnTime: string;
defaultDangerTime: string;
defaultPublic: boolean;
setDefaultDuration: (defaultDuration: string) => void;
setLinkPrevious: (linkPrevious: boolean) => void;
setWarnTime: (warnTime: string) => void;
setDangerTime: (dangerTime: string) => void;
setDefaultPublic: (defaultPublic: boolean) => void;
}; };
type EditorSettingsStore = { export const editorSettingsDefaults = {
eventSettings: EditorSettings; duration: '00:10:00',
setLocalEventSettings: (newState: EditorSettings) => void; linkPrevious: true,
setLinkPrevious: (linkPrevious: boolean) => void; warnTime: '00:02:00', // 120000 same as backend
setDefaultPublic: (defaultPublic: boolean) => void; dangerTime: '00:01:00', // 60000 same as backend
setDefaultDuration: (defaultDuration: string) => void; isPublic: true,
}; };
enum EditorSettingsKeys { enum EditorSettingsKeys {
LinkPrevious = 'ontime-link-previous',
DefaultPublic = 'ontime-default-public',
DefaultDuration = 'ontime-default-duration', DefaultDuration = 'ontime-default-duration',
LinkPrevious = 'ontime-link-previous',
DefaultWarnTime = 'ontime-default-warn-time',
DefaultDangerTime = 'ontime-default-danger-time',
DefaultPublic = 'ontime-default-public',
} }
export const useEditorSettings = create<EditorSettingsStore>((set) => ({ export const useEditorSettings = create<EditorSettingsStore>((set) => {
eventSettings: { return {
linkPrevious: booleanFromLocalStorage(EditorSettingsKeys.LinkPrevious, true), defaultDuration: localStorage.getItem(EditorSettingsKeys.DefaultDuration) ?? editorSettingsDefaults.duration,
defaultPublic: booleanFromLocalStorage(EditorSettingsKeys.DefaultPublic, true), linkPrevious: booleanFromLocalStorage(EditorSettingsKeys.LinkPrevious, editorSettingsDefaults.linkPrevious),
defaultDuration: localStorage.getItem(EditorSettingsKeys.DefaultDuration) ?? '00:10:00', defaultWarnTime: localStorage.getItem(EditorSettingsKeys.DefaultWarnTime) ?? editorSettingsDefaults.warnTime,
}, defaultDangerTime: localStorage.getItem(EditorSettingsKeys.DefaultDangerTime) ?? editorSettingsDefaults.dangerTime,
defaultPublic: booleanFromLocalStorage(EditorSettingsKeys.DefaultPublic, editorSettingsDefaults.isPublic),
setLocalEventSettings: (value) => setDefaultDuration: (defaultDuration) =>
set(() => { set(() => {
localStorage.setItem(EditorSettingsKeys.LinkPrevious, String(value.linkPrevious)); localStorage.setItem(EditorSettingsKeys.DefaultDuration, String(defaultDuration));
localStorage.setItem(EditorSettingsKeys.DefaultPublic, String(value.defaultPublic)); return { defaultDuration };
return { eventSettings: value }; }),
}),
setLinkPrevious: (linkPrevious) => setLinkPrevious: (linkPrevious) =>
set((state) => { set(() => {
localStorage.setItem(EditorSettingsKeys.LinkPrevious, String(linkPrevious)); localStorage.setItem(EditorSettingsKeys.LinkPrevious, String(linkPrevious));
return { eventSettings: { ...state.eventSettings, linkPrevious } }; return { linkPrevious };
}), }),
setWarnTime: (defaultWarnTime) =>
setDefaultPublic: (defaultPublic) => set(() => {
set((state) => { localStorage.setItem(EditorSettingsKeys.DefaultWarnTime, String(defaultWarnTime));
localStorage.setItem(EditorSettingsKeys.DefaultPublic, String(defaultPublic)); return { defaultWarnTime };
return { eventSettings: { ...state.eventSettings, defaultPublic } }; }),
}), setDangerTime: (defaultDangerTime) =>
set(() => {
setDefaultDuration: (defaultDuration) => localStorage.setItem(EditorSettingsKeys.DefaultDangerTime, String(defaultDangerTime));
set((state) => { return { defaultDangerTime };
localStorage.setItem(EditorSettingsKeys.DefaultDuration, String(defaultDuration)); }),
return { eventSettings: { ...state.eventSettings, defaultDuration } }; setDefaultPublic: (defaultPublic) =>
}), set(() => {
})); localStorage.setItem(EditorSettingsKeys.DefaultPublic, String(defaultPublic));
return { defaultPublic };
}),
};
});
@@ -7,5 +7,5 @@
gap: 0.25rem; gap: 0.25rem;
overflow: hidden; overflow: hidden;
background-color: black; background-color: $ui-black;
} }
@@ -126,7 +126,7 @@ export default function ViewSettingsForm() {
<Panel.ListItem> <Panel.ListItem>
<Panel.Field <Panel.Field
title='Freeze timer on end' title='Freeze timer on end'
description='Timer in views will stop from going negative after reaching' description='Timer in views will stop from going negative and instead stop at 00:00:00'
/> />
<Controller <Controller
control={control} control={control}
@@ -1,17 +1,23 @@
import { Switch } from '@chakra-ui/react'; import { Select, Switch } from '@chakra-ui/react';
import { EndAction, TimerType } from 'ontime-types';
import TimeInput from '../../../../common/components/input/time-input/TimeInput'; import TimeInput from '../../../../common/components/input/time-input/TimeInput';
import { useEditorSettings } from '../../../../common/stores/editorSettings'; import { editorSettingsDefaults, useEditorSettings } from '../../../../common/stores/editorSettings';
import { forgivingStringToMillis } from '../../../../common/utils/dateConfig'; import { forgivingStringToMillis } from '../../../../common/utils/dateConfig';
import * as Panel from '../PanelUtils'; import * as Panel from '../PanelUtils';
export default function EditorSettingsForm() { export default function EditorSettingsForm() {
const eventSettings = useEditorSettings((state) => state.eventSettings); const eventSettings = useEditorSettings((state) => state);
const setLinkPrevious = useEditorSettings((state) => state.setLinkPrevious);
const setDefaultPublic = useEditorSettings((state) => state.setDefaultPublic); const setDefaultDuration = eventSettings.setDefaultDuration;
const setDefaultDuration = useEditorSettings((state) => state.setDefaultDuration); const setLinkPrevious = eventSettings.setLinkPrevious;
const setWarnTime = eventSettings.setWarnTime;
const setDangerTime = eventSettings.setDangerTime;
const setDefaultPublic = eventSettings.setDefaultPublic;
const durationInMs = forgivingStringToMillis(eventSettings.defaultDuration); const durationInMs = forgivingStringToMillis(eventSettings.defaultDuration);
const warnTimeInMs = forgivingStringToMillis(eventSettings.defaultWarnTime);
const dangerTimeInMs = forgivingStringToMillis(eventSettings.defaultDangerTime);
return ( return (
<Panel.Section> <Panel.Section>
@@ -19,24 +25,21 @@ export default function EditorSettingsForm() {
<Panel.SubHeader>Editor settings</Panel.SubHeader> <Panel.SubHeader>Editor settings</Panel.SubHeader>
<Panel.Divider /> <Panel.Divider />
<Panel.Section> <Panel.Section>
<Panel.Title>Rundown options</Panel.Title> <Panel.Title>Rundown defaults for new events</Panel.Title>
<Panel.ListGroup> <Panel.ListGroup>
<Panel.ListItem> <Panel.ListItem>
<Panel.Field <Panel.Field title='Default duration' description='Default duration for new events' />
title='Default duration'
description='When creating a new event, what is the default duration'
/>
<TimeInput<'defaultDuration'> <TimeInput<'defaultDuration'>
name='defaultDuration' name='defaultDuration'
submitHandler={(_field, value) => setDefaultDuration(value)} submitHandler={(_field, value) => setDefaultDuration(value)}
time={durationInMs} time={durationInMs}
placeholder='00:10:00' placeholder={editorSettingsDefaults.duration}
/> />
</Panel.ListItem> </Panel.ListItem>
<Panel.ListItem> <Panel.ListItem>
<Panel.Field <Panel.Field
title='Link previous' title='Link previous'
description='New events start time will be linked to the previous event' description='Whether the start time of new events should be linked to the previous event end time'
/> />
<Switch <Switch
variant='ontime' variant='ontime'
@@ -45,6 +48,46 @@ export default function EditorSettingsForm() {
onChange={(event) => setLinkPrevious(event.target.checked)} onChange={(event) => setLinkPrevious(event.target.checked)}
/> />
</Panel.ListItem> </Panel.ListItem>
<Panel.ListItem>
<Panel.Field title='Timer type' description='Default type of timer for new events' />
<Select variant='ontime' size='sm' width='auto' isDisabled>
<option value={TimerType.CountDown}>Count down</option>
<option value={TimerType.CountUp}>Count up</option>
<option value={TimerType.TimeToEnd}>Time to end</option>
<option value={TimerType.Clock}>Clock</option>
</Select>
</Panel.ListItem>
<Panel.ListItem>
<Panel.Field title='End Action' description='Default end action for new events' />
<Select variant='ontime' size='sm' width='auto' isDisabled>
<option value={EndAction.None}>None</option>
<option value={EndAction.Stop}>Stop</option>
<option value={EndAction.LoadNext}>Load next</option>
<option value={EndAction.PlayNext}>Play next</option>
</Select>
</Panel.ListItem>
</Panel.ListGroup>
<Panel.ListGroup>
<Panel.ListItem>
<Panel.Field title='Warning time' description='Default threshold for warning time in an event' />
<TimeInput<'warnTime'>
name='warnTime'
submitHandler={(_field, value) => setWarnTime(value)}
time={warnTimeInMs}
placeholder={editorSettingsDefaults.warnTime}
/>
</Panel.ListItem>
<Panel.ListItem>
<Panel.Field title='Danger time' description='Default threshold for danger time in an event' />
<TimeInput<'dangerTime'>
name='dangerTime'
submitHandler={(_field, value) => setDangerTime(value)}
time={dangerTimeInMs}
placeholder={editorSettingsDefaults.dangerTime}
/>
</Panel.ListItem>
</Panel.ListGroup>
<Panel.ListGroup>
<Panel.ListItem> <Panel.ListItem>
<Panel.Field title='Default public' description='New events will be public' /> <Panel.Field title='Default public' description='New events will be public' />
<Switch <Switch
+1 -7
View File
@@ -8,7 +8,6 @@ import { useEventAction } from '../../common/hooks/useEventAction';
import useFollowComponent from '../../common/hooks/useFollowComponent'; import useFollowComponent from '../../common/hooks/useFollowComponent';
import { useRundownEditor } from '../../common/hooks/useSocket'; import { useRundownEditor } from '../../common/hooks/useSocket';
import { AppMode, useAppMode } from '../../common/stores/appModeStore'; import { AppMode, useAppMode } from '../../common/stores/appModeStore';
import { useEditorSettings } from '../../common/stores/editorSettings';
import { cloneEvent } from '../../common/utils/eventsManager'; import { cloneEvent } from '../../common/utils/eventsManager';
import QuickAddBlock from './quick-add-block/QuickAddBlock'; import QuickAddBlock from './quick-add-block/QuickAddBlock';
@@ -28,9 +27,6 @@ export default function Rundown({ data }: RundownProps) {
const featureData = useRundownEditor(); const featureData = useRundownEditor();
const { addEvent, reorderEvent } = useEventAction(); const { addEvent, reorderEvent } = useEventAction();
const eventSettings = useEditorSettings((state) => state.eventSettings);
const defaultPublic = eventSettings.defaultPublic;
const linkPrevious = eventSettings.linkPrevious;
// cursor // cursor
const { cursor, mode: appMode, setCursor } = useAppMode(); const { cursor, mode: appMode, setCursor } = useAppMode();
@@ -65,16 +61,14 @@ export default function Rundown({ data }: RundownProps) {
}; };
const options = { const options = {
after: cursor, after: cursor,
defaultPublic,
lastEventId: cursor, lastEventId: cursor,
linkPrevious,
}; };
addEvent(newEvent, options); addEvent(newEvent, options);
} else { } else {
addEvent({ type }, { after: cursor }); addEvent({ type }, { after: cursor });
} }
}, },
[addEvent, rundown, defaultPublic, linkPrevious], [addEvent, rundown],
); );
// Handle keyboard shortcuts // Handle keyboard shortcuts
@@ -4,7 +4,6 @@ import { MaybeNumber, OntimeEvent, OntimeRundownEntry, Playback, SupportedEvent
import { useEventAction } from '../../common/hooks/useEventAction'; import { useEventAction } from '../../common/hooks/useEventAction';
import useMemoisedFn from '../../common/hooks/useMemoisedFn'; import useMemoisedFn from '../../common/hooks/useMemoisedFn';
import { useAppMode } from '../../common/stores/appModeStore'; import { useAppMode } from '../../common/stores/appModeStore';
import { useEditorSettings } from '../../common/stores/editorSettings';
import { useEmitLog } from '../../common/stores/logger'; import { useEmitLog } from '../../common/stores/logger';
import { cloneEvent } from '../../common/utils/eventsManager'; import { cloneEvent } from '../../common/utils/eventsManager';
@@ -61,10 +60,6 @@ export default function RundownEntry(props: RundownEntryProps) {
const setCursor = useAppMode((state) => state.setCursor); const setCursor = useAppMode((state) => state.setCursor);
const { selectedEvents, clearSelectedEvents } = useEventSelection(); const { selectedEvents, clearSelectedEvents } = useEventSelection();
const eventSettings = useEditorSettings((state) => state.eventSettings);
const defaultPublic = eventSettings.defaultPublic;
const linkPrevious = eventSettings.linkPrevious;
const removeOpenEvent = useCallback(() => { const removeOpenEvent = useCallback(() => {
if (selectedEvents.has(data.id)) { if (selectedEvents.has(data.id)) {
clearSelectedEvents(); clearSelectedEvents();
@@ -88,9 +83,7 @@ export default function RundownEntry(props: RundownEntryProps) {
const newEvent = { type: SupportedEvent.Event }; const newEvent = { type: SupportedEvent.Event };
const options = { const options = {
after: data.id, after: data.id,
defaultPublic,
lastEventId: previousEventId, lastEventId: previousEventId,
linkPrevious,
}; };
return addEvent(newEvent, options); return addEvent(newEvent, options);
} }
@@ -98,8 +91,6 @@ export default function RundownEntry(props: RundownEntryProps) {
const newEvent = { type: SupportedEvent.Event }; const newEvent = { type: SupportedEvent.Event };
const options = { const options = {
after: previousEventId, after: previousEventId,
defaultPublic,
linkPrevious,
}; };
return addEvent(newEvent, options); return addEvent(newEvent, options);
} }
@@ -18,10 +18,10 @@ $block-cursor-color: $orange-400;
@mixin block-styling() { @mixin block-styling() {
box-sizing: content-box; box-sizing: content-box;
border: 1px solid $white-10; border: 1px solid $white-7;
font-family: $ontime-font-family;
border-radius: $block-border-radius; border-radius: $block-border-radius;
margin: 0.25rem 0.125rem; margin-block: 0.25rem;
margin-right: 0.125rem;
position: relative; position: relative;
color: $block-text-color; color: $block-text-color;
@@ -3,6 +3,7 @@
.block { .block {
@include block-spacing; @include block-spacing;
@include block-styling; @include block-styling;
margin-left: 0.5rem;
background-color: $block-bg2; background-color: $block-bg2;
@@ -3,6 +3,7 @@
.delay { .delay {
@include block-spacing; @include block-spacing;
@include block-styling; @include block-styling;
margin-left: 0.5rem;
background-color: $block-bg2; background-color: $block-bg2;
+1 -1
View File
@@ -32,7 +32,7 @@ export const ontimeInputGhosted = {
backgroundColor: 'transparent', backgroundColor: 'transparent',
color: '#f6f6f6', // $gray-50 color: '#f6f6f6', // $gray-50
_hover: { _hover: {
backgroundColor: 'transparent', // $gray-1100 backgroundColor: 'transparent',
border: '1px solid #2B5ABC', // $blue-500 border: '1px solid #2B5ABC', // $blue-500
}, },
}, },