feat: event description (#481)

* feat: enable configuration of <Info> panel

* feat: add description field to event data
This commit is contained in:
Carlos Valente
2023-08-11 10:55:02 +02:00
committed by GitHub
parent c361ff4b3f
commit af1241bec7
23 changed files with 162 additions and 82 deletions
@@ -13,14 +13,14 @@ import {
requestPutEvent,
requestReorderEvent,
} from '../api/eventsApi';
import { useLocalEvent } from '../stores/localEvent';
import { useEditorSettings } from '../stores/editorSettings';
/**
* @description Set of utilities for events
*/
export const useEventAction = () => {
const queryClient = useQueryClient();
const eventSettings = useLocalEvent((state) => state.eventSettings);
const eventSettings = useEditorSettings((state) => state.eventSettings);
const defaultPublic = eventSettings.defaultPublic;
const startTimeIsLastEnd = eventSettings.startTimeIsLastEnd;
@@ -2,6 +2,7 @@ import { EventData } from 'ontime-types';
export const eventDataPlaceholder: EventData = {
title: '',
description: '',
publicUrl: '',
publicInfo: '',
backstageUrl: '',
@@ -0,0 +1,67 @@
import { create } from 'zustand';
import { booleanFromLocalStorage } from '../utils/localStorage';
type EditorSettings = {
showQuickEntry: boolean;
startTimeIsLastEnd: boolean;
defaultPublic: boolean;
showNif: boolean;
};
type EditorSettingsStore = {
eventSettings: EditorSettings;
setLocalEventSettings: (newState: EditorSettings) => void;
setShowQuickEntry: (showQuickEntry: boolean) => void;
setStartTimeIsLastEnd: (startTimeIsLastEnd: boolean) => void;
setDefaultPublic: (defaultPublic: boolean) => void;
setShowNif: (showNif: boolean) => void;
};
enum EditorSettingsKeys {
ShowQuickEntry = 'ontime-show-quick-entry',
StartTimeIsLastEnd = 'ontime-start-is-last-end',
DefaultPublic = 'ontime-default-public',
ShowNif = 'ontime-show-nif',
}
export const useEditorSettings = create<EditorSettingsStore>((set) => ({
eventSettings: {
showQuickEntry: booleanFromLocalStorage(EditorSettingsKeys.ShowQuickEntry, false),
startTimeIsLastEnd: booleanFromLocalStorage(EditorSettingsKeys.ShowQuickEntry, true),
defaultPublic: booleanFromLocalStorage(EditorSettingsKeys.ShowQuickEntry, true),
showNif: booleanFromLocalStorage(EditorSettingsKeys.ShowNif, true),
},
setLocalEventSettings: (value) =>
set(() => {
localStorage.setItem(EditorSettingsKeys.ShowQuickEntry, String(value.showQuickEntry));
localStorage.setItem(EditorSettingsKeys.StartTimeIsLastEnd, String(value.startTimeIsLastEnd));
localStorage.setItem(EditorSettingsKeys.DefaultPublic, String(value.defaultPublic));
return { eventSettings: value };
}),
setShowQuickEntry: (showQuickEntry) =>
set((state) => {
localStorage.setItem(EditorSettingsKeys.ShowQuickEntry, String(showQuickEntry));
return { eventSettings: { ...state.eventSettings, showQuickEntry } };
}),
setStartTimeIsLastEnd: (startTimeIsLastEnd) =>
set((state) => {
localStorage.setItem(EditorSettingsKeys.StartTimeIsLastEnd, String(startTimeIsLastEnd));
return { eventSettings: { ...state.eventSettings, startTimeIsLastEnd } };
}),
setDefaultPublic: (defaultPublic) =>
set((state) => {
localStorage.setItem(EditorSettingsKeys.DefaultPublic, String(defaultPublic));
return { eventSettings: { ...state.eventSettings, defaultPublic } };
}),
setShowNif: (showNif) =>
set((state) => {
localStorage.setItem(EditorSettingsKeys.ShowNif, String(showNif));
return { eventSettings: { ...state.eventSettings, showNif } };
}),
}));
@@ -1,57 +0,0 @@
import { create } from 'zustand';
import { booleanFromLocalStorage } from '../utils/localStorage';
type EventSettings = {
showQuickEntry: boolean;
startTimeIsLastEnd: boolean;
defaultPublic: boolean;
};
type LocalEventStore = {
eventSettings: EventSettings;
setLocalEventSettings: (newState: EventSettings) => void;
setShowQuickEntry: (showQuickEntry: boolean) => void;
setStartTimeIsLastEnd: (startTimeIsLastEnd: boolean) => void;
setDefaultPublic: (defaultPublic: boolean) => void;
};
enum LocalEventKeys {
ShowQuickEntry = 'ontime-show-quick-entry',
StartTimeIsLastEnd = 'ontime-start-is-last-end',
DefaultPublic = 'ontime-default-public',
}
export const useLocalEvent = create<LocalEventStore>((set) => ({
eventSettings: {
showQuickEntry: booleanFromLocalStorage(LocalEventKeys.ShowQuickEntry, false),
startTimeIsLastEnd: booleanFromLocalStorage(LocalEventKeys.ShowQuickEntry, true),
defaultPublic: booleanFromLocalStorage(LocalEventKeys.ShowQuickEntry, true),
},
setLocalEventSettings: (value) =>
set(() => {
localStorage.setItem(LocalEventKeys.ShowQuickEntry, String(value.showQuickEntry));
localStorage.setItem(LocalEventKeys.StartTimeIsLastEnd, String(value.startTimeIsLastEnd));
localStorage.setItem(LocalEventKeys.DefaultPublic, String(value.defaultPublic));
return { eventSettings: value };
}),
setShowQuickEntry: (showQuickEntry) =>
set((state) => {
localStorage.setItem(LocalEventKeys.ShowQuickEntry, String(showQuickEntry));
return { eventSettings: { ...state.eventSettings, showQuickEntry } };
}),
setStartTimeIsLastEnd: (startTimeIsLastEnd) =>
set((state) => {
localStorage.setItem(LocalEventKeys.StartTimeIsLastEnd, String(startTimeIsLastEnd));
return { eventSettings: { ...state.eventSettings, startTimeIsLastEnd } };
}),
setDefaultPublic: (defaultPublic) =>
set((state) => {
localStorage.setItem(LocalEventKeys.DefaultPublic, String(defaultPublic));
return { eventSettings: { ...state.eventSettings, defaultPublic } };
}),
}));
@@ -19,6 +19,13 @@
}
}
.description {
color: $label-gray;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.labels {
font-size: $inner-section-text-size;
display: flex;
+7 -3
View File
@@ -1,4 +1,5 @@
import { useInfoPanel } from '../../common/hooks/useSocket';
import { useEditorSettings } from '../../common/stores/editorSettings';
import InfoHeader from './info-header/InfoHeader';
import CollapsableInfo from './CollapsableInfo';
@@ -8,6 +9,7 @@ import InfoTitles from './InfoTitles';
export default function Info() {
const data = useInfoPanel();
const showNif = useEditorSettings((state) => state.eventSettings.showNif);
const titlesNow = {
title: data.titles.titleNow || '',
@@ -32,9 +34,11 @@ export default function Info() {
return (
<>
<InfoHeader selected={selected} />
<CollapsableInfo title='Network Info'>
<InfoNif />
</CollapsableInfo>
{showNif && (
<CollapsableInfo title='Network Info'>
<InfoNif />
</CollapsableInfo>
)}
<CollapsableInfo title='Playing Now'>
<InfoTitles data={titlesNow} />
</CollapsableInfo>
@@ -6,9 +6,12 @@ export default function InfoHeader({ selected }: { selected: string }) {
const { data } = useEventData();
return (
<div className={style.panelHeader}>
<span className={style.title}>{data?.title || ''}</span>
<span className={style.selected}>{selected}</span>
</div>
<>
<div className={style.panelHeader}>
<span className={style.title}>{data?.title || ''}</span>
<span className={style.selected}>{selected}</span>
</div>
<div className={style.description}>{data?.description || ''}</div>
</>
);
}
@@ -102,6 +102,18 @@ export default function QuickStart({ onClose, isOpen }: QuickStartProps) {
/>
</label>
</div>
<div className={styles.entryRow}>
<label className={styles.sectionTitle}>
Event description
<Input
variant='ontime-filled-on-light'
size='sm'
maxLength={100}
placeholder='Euro Love, Malmö 2024'
{...register('description')}
/>
</label>
</div>
<div className={styles.entryRow}>
<label className={styles.sectionTitle}>
Public Info
@@ -1,15 +1,16 @@
import { Switch } from '@chakra-ui/react';
import { useLocalEvent } from '../../../common/stores/localEvent';
import { useEditorSettings } from '../../../common/stores/editorSettings';
import ModalSplitInput from '../ModalSplitInput';
import style from './SettingsModal.module.scss';
export default function EditorSettings() {
const eventSettings = useLocalEvent((state) => state.eventSettings);
const setShowQuickEntry = useLocalEvent((state) => state.setShowQuickEntry);
const setStartTimeIsLastEnd = useLocalEvent((state) => state.setStartTimeIsLastEnd);
const setDefaultPublic = useLocalEvent((state) => state.setDefaultPublic);
const eventSettings = useEditorSettings((state) => state.eventSettings);
const setShowQuickEntry = useEditorSettings((state) => state.setShowQuickEntry);
const setStartTimeIsLastEnd = useEditorSettings((state) => state.setStartTimeIsLastEnd);
const setDefaultPublic = useEditorSettings((state) => state.setDefaultPublic);
const setShowNif = useEditorSettings((state) => state.setShowNif);
return (
<div className={style.sectionContainer}>
@@ -39,6 +40,18 @@ export default function EditorSettings() {
onChange={(event) => setDefaultPublic(event.target.checked)}
/>
</ModalSplitInput>
<span className={style.title}>Info settings</span>
<ModalSplitInput
field=''
title='Show network'
description='Whether to available show network interfaces in the panel'
>
<Switch
variant='ontime-on-light'
defaultChecked={eventSettings.showQuickEntry}
onChange={(event) => setShowNif(event.target.checked)}
/>
</ModalSplitInput>
</div>
);
}
@@ -71,6 +71,21 @@ export default function EventDataForm() {
{...register('title')}
/>
</ModalInput>
<ModalInput
field='description'
title='Event description'
description='Free field, shown in editor'
error={errors.description?.message}
>
<Input
{...inputProps}
variant='ontime-filled-on-light'
maxLength={100}
placeholder='Euro Love, Malmö 2024'
isDisabled={disableInputs}
{...register('description')}
/>
</ModalInput>
<div style={{ height: '16px' }} />
<ModalInput field='publicInfo' title='Public Info' description='Information shown in public screens'>
<Textarea
+2 -2
View File
@@ -6,7 +6,7 @@ import { OntimeRundown, Playback, SupportedEvent } from 'ontime-types';
import { useEventAction } from '../../common/hooks/useEventAction';
import { useRundownEditor } from '../../common/hooks/useSocket';
import { AppMode, useAppMode } from '../../common/stores/appModeStore';
import { useLocalEvent } from '../../common/stores/localEvent';
import { useEditorSettings } from '../../common/stores/editorSettings';
import { cloneEvent, getFirstEvent, getNextEvent, getPreviousEvent } from '../../common/utils/eventsManager';
import QuickAddBlock from './quick-add-block/QuickAddBlock';
@@ -26,7 +26,7 @@ export default function Rundown(props: RundownProps) {
const featureData = useRundownEditor();
const { addEvent, reorderEvent } = useEventAction();
const eventSettings = useLocalEvent((state) => state.eventSettings);
const eventSettings = useEditorSettings((state) => state.eventSettings);
const defaultPublic = eventSettings.defaultPublic;
const startTimeIsLastEnd = eventSettings.startTimeIsLastEnd;
const showQuickEntry = eventSettings.showQuickEntry;
@@ -3,7 +3,7 @@ import { OntimeEvent, OntimeRundownEntry, Playback, SupportedEvent } from 'ontim
import { useEventAction } from '../../common/hooks/useEventAction';
import { useAppMode } from '../../common/stores/appModeStore';
import { useLocalEvent } from '../../common/stores/localEvent';
import { useEditorSettings } from '../../common/stores/editorSettings';
import { useEmitLog } from '../../common/stores/logger';
import { cloneEvent } from '../../common/utils/eventsManager';
import { calculateDuration } from '../../common/utils/timesManager';
@@ -61,7 +61,7 @@ export default function RundownEntry(props: RundownEntryProps) {
}
}, [cursor, data.id, openId, setCursor, setEditId]);
const eventSettings = useLocalEvent((state) => state.eventSettings);
const eventSettings = useEditorSettings((state) => state.eventSettings);
const defaultPublic = eventSettings.defaultPublic;
const startTimeIsLastEnd = eventSettings.startTimeIsLastEnd;
@@ -3,7 +3,7 @@ import { Button, Checkbox, Tooltip } from '@chakra-ui/react';
import { SupportedEvent } from 'ontime-types';
import { useEventAction } from '../../../common/hooks/useEventAction';
import { useLocalEvent } from '../../../common/stores/localEvent';
import { useEditorSettings } from '../../../common/stores/editorSettings';
import { useEmitLog } from '../../../common/stores/logger';
import { tooltipDelayMid } from '../../../ontimeConfig';
@@ -25,7 +25,7 @@ const QuickAddBlock = (props: QuickAddBlockProps) => {
const doStartTime = useRef<HTMLInputElement | null>(null);
const doPublic = useRef<HTMLInputElement | null>(null);
const eventSettings = useLocalEvent((state) => state.eventSettings);
const eventSettings = useEditorSettings((state) => state.eventSettings);
const defaultPublic = eventSettings.defaultPublic;
const startTimeIsLastEnd = eventSettings.startTimeIsLastEnd;
@@ -1,21 +1,26 @@
import { RequestHandler } from 'express';
import { EventData } from 'ontime-types';
import { removeUndefined } from '../utils/parserUtils.js';
import { failEmptyObjects } from '../utils/routerUtils.js';
import { DataProvider } from '../classes/data-provider/DataProvider.js';
// Create controller for GET request to 'event'
export const getEventData = async (req, res) => {
export const getEventData: RequestHandler = async (req, res) => {
res.json(DataProvider.getEventData());
};
// Create controller for POST request to 'event'
export const postEventData = async (req, res) => {
export const postEventData: RequestHandler = async (req, res) => {
if (failEmptyObjects(req.body, res)) {
return;
}
try {
const newEvent = removeUndefined({
const newEvent: Partial<EventData> = removeUndefined({
title: req.body?.title,
description: req.body?.description,
publicUrl: req.body?.publicUrl,
publicInfo: req.body?.publicInfo,
backstageUrl: req.body?.backstageUrl,
@@ -2,6 +2,7 @@ import { body, validationResult } from 'express-validator';
export const eventDataSanitizer = [
body('title').optional().isString().trim(),
body('description').optional().isString().trim(),
body('publicUrl').optional().isString().trim(),
body('publicInfo').optional().isString().trim(),
body('backstageUrl').optional().isString().trim(),
@@ -1,5 +1,6 @@
import { Alias, EventData, LogOrigin } from 'ontime-types';
import { RequestHandler } from 'express';
import fs from 'fs';
import { networkInterfaces } from 'os';
@@ -325,10 +326,11 @@ export const dbUpload = async (req, res) => {
};
// Create controller for POST request to '/ontime/new'
export const postNew = async (req, res) => {
export const postNew: RequestHandler = async (req, res) => {
try {
const newEventData: Omit<EventData, 'endMessage'> = {
const newEventData: EventData = {
title: req.body?.title ?? '',
description: req.body?.description ?? '',
publicUrl: req.body?.publicUrl ?? '',
publicInfo: req.body?.publicInfo ?? '',
backstageUrl: req.body?.backstageUrl ?? '',
+1
View File
@@ -4,6 +4,7 @@ export const dbModel: DatabaseModel = {
rundown: [],
eventData: {
title: '',
description: '',
publicUrl: '',
publicInfo: '',
backstageUrl: '',
+1
View File
@@ -96,6 +96,7 @@ export const parseEventData = (data, enforce): EventData => {
newEventData = {
...dbModel.eventData,
title: e.title || dbModel.eventData.title,
description: e.description || dbModel.eventData.description,
publicUrl: e.publicUrl || dbModel.eventData.publicUrl,
publicInfo: e.publicInfo || dbModel.eventData.publicInfo,
backstageUrl: e.backstageUrl || dbModel.eventData.backstageUrl,
+1
View File
@@ -229,6 +229,7 @@
],
"eventData": {
"title": "All about Carlos demo event",
"description": "Demo event for Ontime",
"publicUrl": "www.getontime.no",
"publicInfo": "WiFi: demoproject \nPassword: ontimeproject",
"backstageUrl": "www.getontime.no",
+1
View File
@@ -95,6 +95,7 @@
],
"eventData": {
"title": "All about Carlos demo event",
"description": "Demo event for Ontime",
"publicUrl": "www.getontime.no",
"publicInfo": "WiFi: demoproject \nPassword: ontimeproject",
"backstageUrl": "www.getontime.no",
+1
View File
@@ -30,6 +30,7 @@
],
"eventData": {
"title": "Ontime demo event",
"description": "Demo event for Ontime",
"publicUrl": "www.getontime.no",
"publicInfo": "WiFi: demoproject \nPassword: ontimeproject",
"backstageUrl": "www.getontime.no",
+1
View File
@@ -95,6 +95,7 @@
],
"eventData": {
"title": "All about Carlos demo event",
"description": "Demo event for Ontime",
"publicUrl": "www.getontime.no",
"publicInfo": "WiFi: demoproject \nPassword: ontimeproject",
"backstageUrl": "www.getontime.no",
@@ -1,5 +1,6 @@
export type EventData = {
title: string;
description: string;
publicUrl: string;
publicInfo: string;
backstageUrl: string;