mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-08 00:43:54 +00:00
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:
@@ -25,7 +25,7 @@ import { forgivingStringToMillis } from '../utils/dateConfig';
|
||||
*/
|
||||
export const useEventAction = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const { defaultPublic, linkPrevious, defaultDuration } = useEditorSettings((state) => state.eventSettings);
|
||||
const { defaultPublic, linkPrevious, defaultDuration, defaultWarnTime, defaultDangerTime } = useEditorSettings();
|
||||
|
||||
/**
|
||||
* Calls mutation to add new event
|
||||
@@ -48,6 +48,8 @@ export const useEventAction = () => {
|
||||
defaultPublic: boolean;
|
||||
linkPrevious: boolean;
|
||||
lastEventId: string;
|
||||
defaultWarnTime: number;
|
||||
defaultDangerTime: number;
|
||||
}>;
|
||||
|
||||
/**
|
||||
@@ -64,6 +66,8 @@ export const useEventAction = () => {
|
||||
defaultPublic: options?.defaultPublic ?? defaultPublic,
|
||||
lastEventId: options?.lastEventId,
|
||||
linkPrevious: options?.linkPrevious ?? linkPrevious,
|
||||
defaultWarnTime,
|
||||
defaultDangerTime,
|
||||
};
|
||||
|
||||
if (applicationOptions.linkPrevious && applicationOptions?.lastEventId) {
|
||||
@@ -85,6 +89,14 @@ export const useEventAction = () => {
|
||||
if (newEvent.duration === undefined && newEvent.timeEnd === undefined) {
|
||||
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
|
||||
@@ -98,7 +110,7 @@ export const useEventAction = () => {
|
||||
logAxiosError('Failed adding event', error);
|
||||
}
|
||||
},
|
||||
[_addEventMutation, defaultDuration, defaultPublic, linkPrevious],
|
||||
[_addEventMutation, defaultDangerTime, defaultDuration, defaultPublic, defaultWarnTime, linkPrevious, queryClient],
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,55 +2,68 @@ import { create } from 'zustand';
|
||||
|
||||
import { booleanFromLocalStorage } from '../utils/localStorage';
|
||||
|
||||
type EditorSettings = {
|
||||
linkPrevious: boolean;
|
||||
defaultPublic: boolean;
|
||||
type EditorSettingsStore = {
|
||||
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 = {
|
||||
eventSettings: EditorSettings;
|
||||
setLocalEventSettings: (newState: EditorSettings) => void;
|
||||
setLinkPrevious: (linkPrevious: boolean) => void;
|
||||
setDefaultPublic: (defaultPublic: boolean) => void;
|
||||
setDefaultDuration: (defaultDuration: string) => void;
|
||||
export const editorSettingsDefaults = {
|
||||
duration: '00:10:00',
|
||||
linkPrevious: true,
|
||||
warnTime: '00:02:00', // 120000 same as backend
|
||||
dangerTime: '00:01:00', // 60000 same as backend
|
||||
isPublic: true,
|
||||
};
|
||||
|
||||
enum EditorSettingsKeys {
|
||||
LinkPrevious = 'ontime-link-previous',
|
||||
DefaultPublic = 'ontime-default-public',
|
||||
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) => ({
|
||||
eventSettings: {
|
||||
linkPrevious: booleanFromLocalStorage(EditorSettingsKeys.LinkPrevious, true),
|
||||
defaultPublic: booleanFromLocalStorage(EditorSettingsKeys.DefaultPublic, true),
|
||||
defaultDuration: localStorage.getItem(EditorSettingsKeys.DefaultDuration) ?? '00:10:00',
|
||||
},
|
||||
export const useEditorSettings = create<EditorSettingsStore>((set) => {
|
||||
return {
|
||||
defaultDuration: localStorage.getItem(EditorSettingsKeys.DefaultDuration) ?? editorSettingsDefaults.duration,
|
||||
linkPrevious: booleanFromLocalStorage(EditorSettingsKeys.LinkPrevious, editorSettingsDefaults.linkPrevious),
|
||||
defaultWarnTime: localStorage.getItem(EditorSettingsKeys.DefaultWarnTime) ?? editorSettingsDefaults.warnTime,
|
||||
defaultDangerTime: localStorage.getItem(EditorSettingsKeys.DefaultDangerTime) ?? editorSettingsDefaults.dangerTime,
|
||||
defaultPublic: booleanFromLocalStorage(EditorSettingsKeys.DefaultPublic, editorSettingsDefaults.isPublic),
|
||||
|
||||
setLocalEventSettings: (value) =>
|
||||
set(() => {
|
||||
localStorage.setItem(EditorSettingsKeys.LinkPrevious, String(value.linkPrevious));
|
||||
localStorage.setItem(EditorSettingsKeys.DefaultPublic, String(value.defaultPublic));
|
||||
return { eventSettings: value };
|
||||
}),
|
||||
setDefaultDuration: (defaultDuration) =>
|
||||
set(() => {
|
||||
localStorage.setItem(EditorSettingsKeys.DefaultDuration, String(defaultDuration));
|
||||
return { defaultDuration };
|
||||
}),
|
||||
|
||||
setLinkPrevious: (linkPrevious) =>
|
||||
set((state) => {
|
||||
localStorage.setItem(EditorSettingsKeys.LinkPrevious, String(linkPrevious));
|
||||
return { eventSettings: { ...state.eventSettings, linkPrevious } };
|
||||
}),
|
||||
|
||||
setDefaultPublic: (defaultPublic) =>
|
||||
set((state) => {
|
||||
localStorage.setItem(EditorSettingsKeys.DefaultPublic, String(defaultPublic));
|
||||
return { eventSettings: { ...state.eventSettings, defaultPublic } };
|
||||
}),
|
||||
|
||||
setDefaultDuration: (defaultDuration) =>
|
||||
set((state) => {
|
||||
localStorage.setItem(EditorSettingsKeys.DefaultDuration, String(defaultDuration));
|
||||
return { eventSettings: { ...state.eventSettings, defaultDuration } };
|
||||
}),
|
||||
}));
|
||||
setLinkPrevious: (linkPrevious) =>
|
||||
set(() => {
|
||||
localStorage.setItem(EditorSettingsKeys.LinkPrevious, String(linkPrevious));
|
||||
return { linkPrevious };
|
||||
}),
|
||||
setWarnTime: (defaultWarnTime) =>
|
||||
set(() => {
|
||||
localStorage.setItem(EditorSettingsKeys.DefaultWarnTime, String(defaultWarnTime));
|
||||
return { defaultWarnTime };
|
||||
}),
|
||||
setDangerTime: (defaultDangerTime) =>
|
||||
set(() => {
|
||||
localStorage.setItem(EditorSettingsKeys.DefaultDangerTime, String(defaultDangerTime));
|
||||
return { defaultDangerTime };
|
||||
}),
|
||||
setDefaultPublic: (defaultPublic) =>
|
||||
set(() => {
|
||||
localStorage.setItem(EditorSettingsKeys.DefaultPublic, String(defaultPublic));
|
||||
return { defaultPublic };
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
gap: 0.25rem;
|
||||
|
||||
overflow: hidden;
|
||||
background-color: black;
|
||||
background-color: $ui-black;
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ export default function ViewSettingsForm() {
|
||||
<Panel.ListItem>
|
||||
<Panel.Field
|
||||
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
|
||||
control={control}
|
||||
|
||||
+56
-13
@@ -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 { useEditorSettings } from '../../../../common/stores/editorSettings';
|
||||
import { editorSettingsDefaults, useEditorSettings } from '../../../../common/stores/editorSettings';
|
||||
import { forgivingStringToMillis } from '../../../../common/utils/dateConfig';
|
||||
import * as Panel from '../PanelUtils';
|
||||
|
||||
export default function EditorSettingsForm() {
|
||||
const eventSettings = useEditorSettings((state) => state.eventSettings);
|
||||
const setLinkPrevious = useEditorSettings((state) => state.setLinkPrevious);
|
||||
const setDefaultPublic = useEditorSettings((state) => state.setDefaultPublic);
|
||||
const setDefaultDuration = useEditorSettings((state) => state.setDefaultDuration);
|
||||
const eventSettings = useEditorSettings((state) => state);
|
||||
|
||||
const setDefaultDuration = eventSettings.setDefaultDuration;
|
||||
const setLinkPrevious = eventSettings.setLinkPrevious;
|
||||
const setWarnTime = eventSettings.setWarnTime;
|
||||
const setDangerTime = eventSettings.setDangerTime;
|
||||
const setDefaultPublic = eventSettings.setDefaultPublic;
|
||||
|
||||
const durationInMs = forgivingStringToMillis(eventSettings.defaultDuration);
|
||||
const warnTimeInMs = forgivingStringToMillis(eventSettings.defaultWarnTime);
|
||||
const dangerTimeInMs = forgivingStringToMillis(eventSettings.defaultDangerTime);
|
||||
|
||||
return (
|
||||
<Panel.Section>
|
||||
@@ -19,24 +25,21 @@ export default function EditorSettingsForm() {
|
||||
<Panel.SubHeader>Editor settings</Panel.SubHeader>
|
||||
<Panel.Divider />
|
||||
<Panel.Section>
|
||||
<Panel.Title>Rundown options</Panel.Title>
|
||||
<Panel.Title>Rundown defaults for new events</Panel.Title>
|
||||
<Panel.ListGroup>
|
||||
<Panel.ListItem>
|
||||
<Panel.Field
|
||||
title='Default duration'
|
||||
description='When creating a new event, what is the default duration'
|
||||
/>
|
||||
<Panel.Field title='Default duration' description='Default duration for new events' />
|
||||
<TimeInput<'defaultDuration'>
|
||||
name='defaultDuration'
|
||||
submitHandler={(_field, value) => setDefaultDuration(value)}
|
||||
time={durationInMs}
|
||||
placeholder='00:10:00'
|
||||
placeholder={editorSettingsDefaults.duration}
|
||||
/>
|
||||
</Panel.ListItem>
|
||||
<Panel.ListItem>
|
||||
<Panel.Field
|
||||
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
|
||||
variant='ontime'
|
||||
@@ -45,6 +48,46 @@ export default function EditorSettingsForm() {
|
||||
onChange={(event) => setLinkPrevious(event.target.checked)}
|
||||
/>
|
||||
</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.Field title='Default public' description='New events will be public' />
|
||||
<Switch
|
||||
|
||||
@@ -8,7 +8,6 @@ import { useEventAction } from '../../common/hooks/useEventAction';
|
||||
import useFollowComponent from '../../common/hooks/useFollowComponent';
|
||||
import { useRundownEditor } from '../../common/hooks/useSocket';
|
||||
import { AppMode, useAppMode } from '../../common/stores/appModeStore';
|
||||
import { useEditorSettings } from '../../common/stores/editorSettings';
|
||||
import { cloneEvent } from '../../common/utils/eventsManager';
|
||||
|
||||
import QuickAddBlock from './quick-add-block/QuickAddBlock';
|
||||
@@ -28,9 +27,6 @@ export default function Rundown({ data }: RundownProps) {
|
||||
|
||||
const featureData = useRundownEditor();
|
||||
const { addEvent, reorderEvent } = useEventAction();
|
||||
const eventSettings = useEditorSettings((state) => state.eventSettings);
|
||||
const defaultPublic = eventSettings.defaultPublic;
|
||||
const linkPrevious = eventSettings.linkPrevious;
|
||||
|
||||
// cursor
|
||||
const { cursor, mode: appMode, setCursor } = useAppMode();
|
||||
@@ -65,16 +61,14 @@ export default function Rundown({ data }: RundownProps) {
|
||||
};
|
||||
const options = {
|
||||
after: cursor,
|
||||
defaultPublic,
|
||||
lastEventId: cursor,
|
||||
linkPrevious,
|
||||
};
|
||||
addEvent(newEvent, options);
|
||||
} else {
|
||||
addEvent({ type }, { after: cursor });
|
||||
}
|
||||
},
|
||||
[addEvent, rundown, defaultPublic, linkPrevious],
|
||||
[addEvent, rundown],
|
||||
);
|
||||
|
||||
// Handle keyboard shortcuts
|
||||
|
||||
@@ -4,7 +4,6 @@ import { MaybeNumber, OntimeEvent, OntimeRundownEntry, Playback, SupportedEvent
|
||||
import { useEventAction } from '../../common/hooks/useEventAction';
|
||||
import useMemoisedFn from '../../common/hooks/useMemoisedFn';
|
||||
import { useAppMode } from '../../common/stores/appModeStore';
|
||||
import { useEditorSettings } from '../../common/stores/editorSettings';
|
||||
import { useEmitLog } from '../../common/stores/logger';
|
||||
import { cloneEvent } from '../../common/utils/eventsManager';
|
||||
|
||||
@@ -61,10 +60,6 @@ export default function RundownEntry(props: RundownEntryProps) {
|
||||
const setCursor = useAppMode((state) => state.setCursor);
|
||||
const { selectedEvents, clearSelectedEvents } = useEventSelection();
|
||||
|
||||
const eventSettings = useEditorSettings((state) => state.eventSettings);
|
||||
const defaultPublic = eventSettings.defaultPublic;
|
||||
const linkPrevious = eventSettings.linkPrevious;
|
||||
|
||||
const removeOpenEvent = useCallback(() => {
|
||||
if (selectedEvents.has(data.id)) {
|
||||
clearSelectedEvents();
|
||||
@@ -88,9 +83,7 @@ export default function RundownEntry(props: RundownEntryProps) {
|
||||
const newEvent = { type: SupportedEvent.Event };
|
||||
const options = {
|
||||
after: data.id,
|
||||
defaultPublic,
|
||||
lastEventId: previousEventId,
|
||||
linkPrevious,
|
||||
};
|
||||
return addEvent(newEvent, options);
|
||||
}
|
||||
@@ -98,8 +91,6 @@ export default function RundownEntry(props: RundownEntryProps) {
|
||||
const newEvent = { type: SupportedEvent.Event };
|
||||
const options = {
|
||||
after: previousEventId,
|
||||
defaultPublic,
|
||||
linkPrevious,
|
||||
};
|
||||
return addEvent(newEvent, options);
|
||||
}
|
||||
|
||||
@@ -18,10 +18,10 @@ $block-cursor-color: $orange-400;
|
||||
|
||||
@mixin block-styling() {
|
||||
box-sizing: content-box;
|
||||
border: 1px solid $white-10;
|
||||
font-family: $ontime-font-family;
|
||||
border: 1px solid $white-7;
|
||||
border-radius: $block-border-radius;
|
||||
margin: 0.25rem 0.125rem;
|
||||
margin-block: 0.25rem;
|
||||
margin-right: 0.125rem;
|
||||
position: relative;
|
||||
color: $block-text-color;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
.block {
|
||||
@include block-spacing;
|
||||
@include block-styling;
|
||||
margin-left: 0.5rem;
|
||||
|
||||
background-color: $block-bg2;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
.delay {
|
||||
@include block-spacing;
|
||||
@include block-styling;
|
||||
margin-left: 0.5rem;
|
||||
|
||||
background-color: $block-bg2;
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ export const ontimeInputGhosted = {
|
||||
backgroundColor: 'transparent',
|
||||
color: '#f6f6f6', // $gray-50
|
||||
_hover: {
|
||||
backgroundColor: 'transparent', // $gray-1100
|
||||
backgroundColor: 'transparent',
|
||||
border: '1px solid #2B5ABC', // $blue-500
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user