mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-06 07:53:54 +00:00
fix: keyboard shortcuts in rundown
This commit is contained in:
committed by
Carlos Valente
parent
ad2ef3b53f
commit
abe9012f20
@@ -89,25 +89,17 @@ export const useEntryActions = () => {
|
||||
|
||||
// ************* CHECK OPTIONS specific to events
|
||||
if (isOntimeEvent(newEntry)) {
|
||||
// merge creation time options with event settings
|
||||
const applicationOptions = {
|
||||
after: options?.after,
|
||||
before: options?.before,
|
||||
lastEventId: options?.lastEventId,
|
||||
linkPrevious: options?.linkPrevious ?? linkPrevious,
|
||||
};
|
||||
|
||||
if (applicationOptions?.lastEventId) {
|
||||
if (options?.lastEventId) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- we know this is a value
|
||||
const rundownData = queryClient.getQueryData<Rundown>(RUNDOWN)!;
|
||||
const previousEvent = rundownData.entries[applicationOptions.lastEventId];
|
||||
const previousEvent = rundownData.entries[options?.lastEventId];
|
||||
if (isOntimeEvent(previousEvent)) {
|
||||
newEntry.timeStart = previousEvent.timeEnd;
|
||||
}
|
||||
}
|
||||
|
||||
// Override event with options from editor settings
|
||||
newEntry.linkStart = applicationOptions.linkPrevious;
|
||||
newEntry.linkStart = options?.linkPrevious ?? linkPrevious;
|
||||
|
||||
if (newEntry.duration === undefined && newEntry.timeEnd === undefined) {
|
||||
newEntry.duration = parseUserTime(defaultDuration);
|
||||
|
||||
@@ -33,7 +33,7 @@ import {
|
||||
reorderArray,
|
||||
} from 'ontime-utils';
|
||||
|
||||
import { type EventOptions, useEntryActions } from '../../common/hooks/useEntryAction';
|
||||
import { useEntryActions } from '../../common/hooks/useEntryAction';
|
||||
import useFollowComponent from '../../common/hooks/useFollowComponent';
|
||||
import { useRundownEditor } from '../../common/hooks/useSocket';
|
||||
import { useEntryCopy } from '../../common/stores/entryCopyStore';
|
||||
@@ -114,20 +114,16 @@ export default function Rundown({ data }: RundownProps) {
|
||||
[addEntry, order, entries],
|
||||
);
|
||||
|
||||
/**
|
||||
* Add a new item referring to an existing one
|
||||
*/
|
||||
const insertAtId = useCallback(
|
||||
(patch: Partial<OntimeEntry> & { type: SupportedEntry }, id: MaybeString, above = false) => {
|
||||
const options: EventOptions =
|
||||
id === null
|
||||
? {}
|
||||
: {
|
||||
after: above ? undefined : id,
|
||||
before: above ? id : undefined,
|
||||
};
|
||||
|
||||
if (!above && id) {
|
||||
options.lastEventId = id;
|
||||
}
|
||||
addEntry(patch, options);
|
||||
addEntry(patch, {
|
||||
after: id && !above ? id : undefined,
|
||||
before: id && above ? id : undefined,
|
||||
lastEventId: !above && id ? id : undefined,
|
||||
});
|
||||
},
|
||||
[addEntry],
|
||||
);
|
||||
@@ -239,52 +235,72 @@ export default function Rundown({ data }: RundownProps) {
|
||||
|
||||
// shortcuts
|
||||
useHotkeys([
|
||||
['alt + ArrowDown', () => selectEntry(cursor, 'down'), { preventDefault: true }],
|
||||
['alt + ArrowUp', () => selectEntry(cursor, 'up'), { preventDefault: true }],
|
||||
['alt + ArrowDown', () => selectEntry(cursor, 'down'), { preventDefault: true, usePhysicalKeys: true }],
|
||||
['alt + ArrowUp', () => selectEntry(cursor, 'up'), { preventDefault: true, usePhysicalKeys: true }],
|
||||
|
||||
['alt + shift + ArrowDown', () => selectBlock(cursor, 'down'), { preventDefault: true }],
|
||||
['alt + shift + ArrowUp', () => selectBlock(cursor, 'up'), { preventDefault: true }],
|
||||
['alt + shift + ArrowDown', () => selectBlock(cursor, 'down'), { preventDefault: true, usePhysicalKeys: true }],
|
||||
['alt + shift + ArrowUp', () => selectBlock(cursor, 'up'), { preventDefault: true, usePhysicalKeys: true }],
|
||||
|
||||
['alt + mod + ArrowDown', () => moveEntry(cursor, 'down'), { preventDefault: true }],
|
||||
['alt + mod + ArrowUp', () => moveEntry(cursor, 'up'), { preventDefault: true }],
|
||||
['alt + mod + ArrowDown', () => moveEntry(cursor, 'down'), { preventDefault: true, usePhysicalKeys: true }],
|
||||
['alt + mod + ArrowUp', () => moveEntry(cursor, 'up'), { preventDefault: true, usePhysicalKeys: true }],
|
||||
|
||||
['Escape', () => clearSelectedEvents(), { preventDefault: true }],
|
||||
['Escape', () => clearSelectedEvents(), { preventDefault: true, usePhysicalKeys: true }],
|
||||
|
||||
['mod + Backspace', () => deleteAtCursor(cursor), { preventDefault: true }],
|
||||
['mod + Backspace', () => deleteAtCursor(cursor), { preventDefault: true, usePhysicalKeys: true }],
|
||||
|
||||
[
|
||||
'alt + E',
|
||||
() => insertAtId({ type: SupportedEntry.Event }, cursor),
|
||||
{ preventDefault: true, usePhysicalKeys: true },
|
||||
],
|
||||
['alt + shift + E', () => insertAtId({ type: SupportedEntry.Event }, cursor, true), { preventDefault: true }],
|
||||
[
|
||||
'alt + shift + E',
|
||||
() => insertAtId({ type: SupportedEntry.Event }, cursor, true),
|
||||
{ preventDefault: true, usePhysicalKeys: true },
|
||||
],
|
||||
|
||||
[
|
||||
'alt + G',
|
||||
() => insertAtId({ type: SupportedEntry.Block }, cursor),
|
||||
{ preventDefault: true, usePhysicalKeys: true },
|
||||
],
|
||||
['alt + shift + G', () => insertAtId({ type: SupportedEntry.Block }, cursor, true), { preventDefault: true }],
|
||||
[
|
||||
'alt + shift + G',
|
||||
() => insertAtId({ type: SupportedEntry.Block }, cursor, true),
|
||||
{ preventDefault: true, usePhysicalKeys: true },
|
||||
],
|
||||
|
||||
[
|
||||
'alt + D',
|
||||
() => insertAtId({ type: SupportedEntry.Delay }, cursor),
|
||||
{ preventDefault: true, usePhysicalKeys: true },
|
||||
],
|
||||
['alt + shift + D', () => insertAtId({ type: SupportedEntry.Delay }, cursor, true), { preventDefault: true }],
|
||||
[
|
||||
'alt + shift + D',
|
||||
() => insertAtId({ type: SupportedEntry.Delay }, cursor, true),
|
||||
{ preventDefault: true, usePhysicalKeys: true },
|
||||
],
|
||||
|
||||
[
|
||||
'alt + M',
|
||||
() => insertAtId({ type: SupportedEntry.Milestone }, cursor),
|
||||
{ preventDefault: true, usePhysicalKeys: true },
|
||||
],
|
||||
['alt + shift + M', () => insertAtId({ type: SupportedEntry.Milestone }, cursor, true), { preventDefault: true }],
|
||||
[
|
||||
'alt + shift + M',
|
||||
() => insertAtId({ type: SupportedEntry.Milestone }, cursor, true),
|
||||
{ preventDefault: true, usePhysicalKeys: true },
|
||||
],
|
||||
|
||||
['mod + C', () => setEntryCopyId(cursor)],
|
||||
['mod + V', () => insertCopyAtId(cursor, entryCopyId)],
|
||||
['mod + shift + V', () => insertCopyAtId(cursor, entryCopyId, true), { preventDefault: true }],
|
||||
[
|
||||
'mod + shift + V',
|
||||
() => insertCopyAtId(cursor, entryCopyId, true),
|
||||
{ preventDefault: true, usePhysicalKeys: true },
|
||||
],
|
||||
|
||||
['alt + backspace', () => deleteAtCursor(cursor), { preventDefault: true }],
|
||||
['alt + backspace', () => deleteAtCursor(cursor), { preventDefault: true, usePhysicalKeys: true }],
|
||||
]);
|
||||
|
||||
// we copy the state from the store here
|
||||
|
||||
@@ -35,14 +35,30 @@ export async function addEntry(eventData: EventPostPayload): Promise<OntimeEntry
|
||||
throw new Error(`Event with ID ${eventData.id} already exists`);
|
||||
}
|
||||
|
||||
// if the user provides a parent (inside a group), we make sure it exists and it is a group
|
||||
// the parent can be provided or inferred from position
|
||||
let parent: OntimeBlock | null = null;
|
||||
|
||||
console.log('Adding entry with data:', eventData);
|
||||
|
||||
if ('parent' in eventData && eventData.parent != null) {
|
||||
// if the user provides a parent (inside a group), we make sure it exists and it is a group
|
||||
const maybeParent = rundown.entries[eventData.parent];
|
||||
if (!maybeParent || !isOntimeBlock(maybeParent)) {
|
||||
throw new Error(`Invalid parent event with ID ${eventData.parent}`);
|
||||
}
|
||||
parent = maybeParent;
|
||||
} else {
|
||||
// otherwise, we may infer the parent from relative positioning (after/before)
|
||||
const referenceId = eventData?.after ?? eventData?.before;
|
||||
if (referenceId) {
|
||||
const maybeSibling = rundown.entries[referenceId];
|
||||
if (maybeSibling && 'parent' in maybeSibling && maybeSibling.parent) {
|
||||
const maybeParent = rundown.entries[maybeSibling.parent];
|
||||
if (maybeParent && isOntimeBlock(maybeParent)) {
|
||||
parent = maybeParent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// normalise the position of the event in the rundown order
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import type { OntimeEntry } from '../../definitions/core/OntimeEntry.js';
|
||||
import type { EntryId, OntimeEntry } from '../../definitions/core/OntimeEntry.js';
|
||||
|
||||
export type PatchWithId<T extends OntimeEntry = OntimeEntry> = Partial<T> & { id: string };
|
||||
export type PatchWithId<T extends OntimeEntry = OntimeEntry> = Partial<T> & { id: EntryId };
|
||||
|
||||
export type EventPostPayload = Partial<OntimeEntry> & {
|
||||
after?: string;
|
||||
before?: string;
|
||||
after?: EntryId;
|
||||
before?: EntryId;
|
||||
};
|
||||
|
||||
export type TransientEventPayload = Partial<OntimeEntry> & {
|
||||
after?: string;
|
||||
before?: string;
|
||||
after?: EntryId;
|
||||
before?: EntryId;
|
||||
};
|
||||
|
||||
export type ProjectRundown = {
|
||||
|
||||
Reference in New Issue
Block a user