mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-14 03:43:50 +00:00
feat: create group from entry selection
This commit is contained in:
committed by
Carlos Valente
parent
67f914bdc0
commit
7d5291e5e5
@@ -90,15 +90,15 @@ export async function requestApplyDelay(delayId: EntryId): Promise<AxiosResponse
|
||||
/**
|
||||
* HTTP request for dissolving of a block
|
||||
*/
|
||||
export async function requestDissolveBlock(blockId: EntryId): Promise<AxiosResponse<MessageResponse>> {
|
||||
export async function requestDissolveBlock(blockId: EntryId): Promise<AxiosResponse<Rundown>> {
|
||||
return axios.post(`${rundownPath}/dissolve/${blockId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request for grouping a list of entries into a block
|
||||
*/
|
||||
export async function requestGroupEntries(entryIds: EntryId[]): Promise<AxiosResponse<MessageResponse>> {
|
||||
return axios.post(`${rundownPath}/group`, { data: { ids: entryIds } });
|
||||
export async function requestGroupEntries(entryIds: EntryId[]): Promise<AxiosResponse<Rundown>> {
|
||||
return axios.post(`${rundownPath}/group`, { ids: entryIds });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
requestDeleteAll,
|
||||
requestDissolveBlock,
|
||||
requestEventSwap,
|
||||
requestGroupEntries,
|
||||
SwapEntry,
|
||||
} from '../api/rundown';
|
||||
import { logAxiosError } from '../api/utils';
|
||||
@@ -521,6 +522,19 @@ export const useEntryActions = () => {
|
||||
*/
|
||||
const _dissolveBlockMutation = useMutation({
|
||||
mutationFn: requestDissolveBlock,
|
||||
onSuccess: (response) => {
|
||||
if (!response.data) return;
|
||||
|
||||
const { id, title, order, flatOrder, entries, revision } = response.data;
|
||||
queryClient.setQueryData<Rundown>(RUNDOWN, {
|
||||
id,
|
||||
title,
|
||||
order,
|
||||
flatOrder,
|
||||
entries,
|
||||
revision,
|
||||
});
|
||||
},
|
||||
onSettled: () => queryClient.invalidateQueries({ queryKey: RUNDOWN }),
|
||||
});
|
||||
|
||||
@@ -537,6 +551,43 @@ export const useEntryActions = () => {
|
||||
},
|
||||
[_dissolveBlockMutation],
|
||||
);
|
||||
|
||||
/**
|
||||
* Calls mutation to create a block with a selection
|
||||
* @private
|
||||
*/
|
||||
const _groupEntriesMutation = useMutation({
|
||||
mutationFn: requestGroupEntries,
|
||||
onSuccess: (response) => {
|
||||
if (!response.data) return;
|
||||
|
||||
const { id, title, order, flatOrder, entries, revision } = response.data;
|
||||
queryClient.setQueryData<Rundown>(RUNDOWN, {
|
||||
id,
|
||||
title,
|
||||
order,
|
||||
flatOrder,
|
||||
entries,
|
||||
revision,
|
||||
});
|
||||
},
|
||||
onSettled: () => queryClient.invalidateQueries({ queryKey: RUNDOWN }),
|
||||
});
|
||||
|
||||
/**
|
||||
* Create a block with a selection
|
||||
*/
|
||||
const groupEntries = useCallback(
|
||||
async (entryIds: EntryId[]) => {
|
||||
try {
|
||||
await _groupEntriesMutation.mutateAsync(entryIds);
|
||||
} catch (error) {
|
||||
logAxiosError('Error grouping entries', error);
|
||||
}
|
||||
},
|
||||
[_groupEntriesMutation],
|
||||
);
|
||||
|
||||
/**
|
||||
* Calls mutation to reorder an entry
|
||||
* @private
|
||||
@@ -575,17 +626,17 @@ export const useEntryActions = () => {
|
||||
|
||||
// Mutation finished, we update the rundown with the response
|
||||
onSuccess: (response) => {
|
||||
if (response.data) {
|
||||
const { id, title, order, flatOrder, entries, revision } = response.data;
|
||||
queryClient.setQueryData<Rundown>(RUNDOWN, {
|
||||
id,
|
||||
title,
|
||||
order,
|
||||
flatOrder,
|
||||
entries,
|
||||
revision,
|
||||
});
|
||||
}
|
||||
if (!response.data) return;
|
||||
|
||||
const { id, title, order, flatOrder, entries, revision } = response.data;
|
||||
queryClient.setQueryData<Rundown>(RUNDOWN, {
|
||||
id,
|
||||
title,
|
||||
order,
|
||||
flatOrder,
|
||||
entries,
|
||||
revision,
|
||||
});
|
||||
},
|
||||
|
||||
// Mutation finished, failed or successful
|
||||
@@ -688,6 +739,7 @@ export const useEntryActions = () => {
|
||||
deleteAllEntries,
|
||||
dissolveBlock,
|
||||
getEntryById,
|
||||
groupEntries,
|
||||
reorderEntry,
|
||||
swapEvents,
|
||||
updateEntry,
|
||||
|
||||
@@ -19,18 +19,17 @@ import EventBlock from './event-block/EventBlock';
|
||||
import { useEventSelection } from './useEventSelection';
|
||||
|
||||
export type EventItemActions =
|
||||
| 'set-cursor'
|
||||
| 'event'
|
||||
| 'event-before'
|
||||
| 'delay'
|
||||
| 'delay-before'
|
||||
| 'block'
|
||||
| 'block-before'
|
||||
| 'swap'
|
||||
| 'delete'
|
||||
| 'clone'
|
||||
| 'update'
|
||||
| 'swap'
|
||||
| 'clear-report';
|
||||
| 'group'
|
||||
| 'update';
|
||||
|
||||
interface RundownEntryProps {
|
||||
type: SupportedEntry;
|
||||
@@ -66,7 +65,7 @@ export default function RundownEntry(props: RundownEntryProps) {
|
||||
isLinkedToLoaded,
|
||||
} = props;
|
||||
const { emitError } = useEmitLog();
|
||||
const { addEntry, updateEntry, batchUpdateEvents, deleteEntry, swapEvents } = useEntryActions();
|
||||
const { addEntry, updateEntry, batchUpdateEvents, deleteEntry, groupEntries, swapEvents } = useEntryActions();
|
||||
const { selectedEvents, unselect, clearSelectedEvents } = useEventSelection();
|
||||
|
||||
const removeOpenEvent = useCallback(() => {
|
||||
@@ -129,6 +128,13 @@ export default function RundownEntry(props: RundownEntryProps) {
|
||||
addEntry(newEvent, { after: data.id });
|
||||
break;
|
||||
}
|
||||
case 'group': {
|
||||
if (selectedEvents.size > 1) {
|
||||
clearMultiSelection();
|
||||
return groupEntries(Array.from(selectedEvents));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'update': {
|
||||
// Handles and filters update requests
|
||||
const { field, value } = payload as FieldValue;
|
||||
|
||||
@@ -2,6 +2,7 @@ import { MouseEvent, useEffect, useLayoutEffect, useRef, useState } from 'react'
|
||||
import {
|
||||
IoAdd,
|
||||
IoDuplicateOutline,
|
||||
IoFolder,
|
||||
IoLink,
|
||||
IoPeople,
|
||||
IoPeopleOutline,
|
||||
@@ -26,7 +27,7 @@ import RundownIndicators from './RundownIndicators';
|
||||
import style from './EventBlock.module.scss';
|
||||
|
||||
interface EventBlockProps {
|
||||
eventId: string;
|
||||
eventId: EntryId;
|
||||
cue: string;
|
||||
timeStart: number;
|
||||
timeEnd: number;
|
||||
@@ -144,6 +145,7 @@ export default function EventBlock(props: EventBlockProps) {
|
||||
value: false,
|
||||
}),
|
||||
},
|
||||
{ withDivider: true, label: 'Group', icon: IoFolder, onClick: () => actionHandler('group') },
|
||||
{ withDivider: true, label: 'Delete', icon: IoTrash, onClick: () => actionHandler('delete') },
|
||||
]
|
||||
: [
|
||||
|
||||
@@ -9,13 +9,13 @@ import { isMacOS } from '../../common/utils/deviceUtils';
|
||||
type SelectionMode = 'shift' | 'click' | 'ctrl';
|
||||
|
||||
interface EventSelectionStore {
|
||||
selectedEvents: Set<string>;
|
||||
selectedEvents: Set<EntryId>;
|
||||
anchoredIndex: MaybeNumber;
|
||||
cursor: MaybeString;
|
||||
setSelectedEvents: (selectionArgs: { id: string; index: number; selectMode: SelectionMode }) => void;
|
||||
setSelectedEvents: (selectionArgs: { id: EntryId; index: number; selectMode: SelectionMode }) => void;
|
||||
clearSelectedEvents: () => void;
|
||||
clearMultiSelect: () => void;
|
||||
unselect: (id: string) => void;
|
||||
unselect: (id: EntryId) => void;
|
||||
}
|
||||
|
||||
export const useEventSelection = create<EventSelectionStore>()((set, get) => ({
|
||||
|
||||
Reference in New Issue
Block a user