mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-19 22:24:11 +00:00
227 lines
6.9 KiB
TypeScript
227 lines
6.9 KiB
TypeScript
import { useCallback } from 'react';
|
|
import { CellContext, ColumnDef } from '@tanstack/react-table';
|
|
import { CustomFields, isOntimeEvent, OntimeEntry, OntimeEvent, TimeStrategy } from 'ontime-types';
|
|
import { millisToString, removeSeconds } from 'ontime-utils';
|
|
|
|
import DelayIndicator from '../../../../common/components/delay-indicator/DelayIndicator';
|
|
import { formatDuration } from '../../../../common/utils/time';
|
|
|
|
import EditableImage from './EditableImage';
|
|
import MultiLineCell from './MultiLineCell';
|
|
import SingleLineCell from './SingleLineCell';
|
|
import TimeInput from './TimeInput';
|
|
|
|
function MakeStart({ getValue, row, table }: CellContext<OntimeEntry, unknown>) {
|
|
if (!table.options.meta) {
|
|
return null;
|
|
}
|
|
|
|
const { handleUpdateTimer } = table.options.meta;
|
|
const { showDelayedTimes, hideTableSeconds } = table.options.meta.options;
|
|
|
|
const update = (newValue: string) => handleUpdateTimer(row.original.id, 'timeStart', newValue);
|
|
|
|
const startTime = getValue() as number;
|
|
const isStartLocked = (row.original as OntimeEvent).linkStart === null;
|
|
const delayValue = (row.original as OntimeEvent)?.delay ?? 0;
|
|
|
|
const displayTime = showDelayedTimes ? startTime + delayValue : startTime;
|
|
let formattedTime = millisToString(displayTime);
|
|
if (hideTableSeconds) {
|
|
formattedTime = removeSeconds(formattedTime);
|
|
}
|
|
|
|
return (
|
|
<TimeInput initialValue={startTime} onSubmit={update} lockedValue={isStartLocked} delayed={delayValue !== 0}>
|
|
{formattedTime}
|
|
<DelayIndicator delayValue={delayValue} tooltipPrefix={millisToString(startTime)} />
|
|
</TimeInput>
|
|
);
|
|
}
|
|
|
|
function MakeEnd({ getValue, row, table }: CellContext<OntimeEntry, unknown>) {
|
|
if (!table.options.meta) {
|
|
return null;
|
|
}
|
|
|
|
const { handleUpdateTimer } = table.options.meta;
|
|
const { showDelayedTimes, hideTableSeconds } = table.options.meta.options;
|
|
|
|
const update = (newValue: string) => handleUpdateTimer(row.original.id, 'timeEnd', newValue);
|
|
|
|
const endTime = getValue() as number;
|
|
const isEndLocked = (row.original as OntimeEvent).timeStrategy === TimeStrategy.LockEnd;
|
|
const delayValue = (row.original as OntimeEvent)?.delay ?? 0;
|
|
|
|
const displayTime = showDelayedTimes ? endTime + delayValue : endTime;
|
|
let formattedTime = millisToString(displayTime);
|
|
if (hideTableSeconds) {
|
|
formattedTime = removeSeconds(formattedTime);
|
|
}
|
|
|
|
return (
|
|
<TimeInput initialValue={endTime} onSubmit={update} lockedValue={isEndLocked} delayed={delayValue !== 0}>
|
|
{formattedTime}
|
|
<DelayIndicator delayValue={delayValue} tooltipPrefix={millisToString(endTime)} />
|
|
</TimeInput>
|
|
);
|
|
}
|
|
|
|
function MakeDuration({ getValue, row, table }: CellContext<OntimeEntry, unknown>) {
|
|
if (!table.options.meta) {
|
|
return null;
|
|
}
|
|
|
|
const { handleUpdateTimer } = table.options.meta;
|
|
|
|
const update = (newValue: string) => handleUpdateTimer(row.original.id, 'duration', newValue);
|
|
|
|
const duration = getValue() as number;
|
|
const isDurationLocked = (row.original as OntimeEvent).timeStrategy === TimeStrategy.LockDuration;
|
|
const formattedDuration = formatDuration(duration, false);
|
|
|
|
return (
|
|
<TimeInput initialValue={duration} onSubmit={update} lockedValue={isDurationLocked}>
|
|
{formattedDuration}
|
|
</TimeInput>
|
|
);
|
|
}
|
|
|
|
function MakeMultiLineField({ row, column, table }: CellContext<OntimeEntry, unknown>) {
|
|
const update = useCallback(
|
|
(newValue: string) => {
|
|
table.options.meta?.handleUpdate(row.index, column.id, newValue, false);
|
|
},
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- we skip table.options.meta since the reference seems unstable
|
|
[column.id, row.index],
|
|
);
|
|
|
|
const event = row.original;
|
|
if (!isOntimeEvent(event)) {
|
|
return null;
|
|
}
|
|
|
|
const initialValue = event[column.id as keyof OntimeEntry] ?? '';
|
|
|
|
return <MultiLineCell initialValue={initialValue as string} handleUpdate={update} />;
|
|
}
|
|
|
|
function LazyImage({ row, column, table }: CellContext<OntimeEntry, unknown>) {
|
|
const update = useCallback(
|
|
(newValue: string) => {
|
|
table.options.meta?.handleUpdate(row.index, column.id, newValue, true);
|
|
},
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- we skip table.options.meta since the reference seems unstable
|
|
[column.id, row.index],
|
|
);
|
|
|
|
const event = row.original;
|
|
if (!isOntimeEvent(event)) {
|
|
return null;
|
|
}
|
|
|
|
const initialValue = event.custom[column.id];
|
|
return <EditableImage initialValue={initialValue} updateValue={update} />;
|
|
}
|
|
|
|
function MakeSingleLineField({ row, column, table }: CellContext<OntimeEntry, unknown>) {
|
|
const update = useCallback(
|
|
(newValue: string) => {
|
|
table.options.meta?.handleUpdate(row.index, column.id, newValue, false);
|
|
},
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- we skip table.options.meta since the reference seems unstable
|
|
[column.id, row.index],
|
|
);
|
|
|
|
const event = row.original;
|
|
if (!isOntimeEvent(event)) {
|
|
return null;
|
|
}
|
|
|
|
const initialValue = event[column.id as keyof OntimeEntry] ?? '';
|
|
|
|
return <SingleLineCell initialValue={initialValue as string} handleUpdate={update} />;
|
|
}
|
|
|
|
function MakeCustomField({ row, column, table }: CellContext<OntimeEntry, unknown>) {
|
|
const update = useCallback(
|
|
(newValue: string) => {
|
|
table.options.meta?.handleUpdate(row.index, column.id, newValue, true);
|
|
},
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- we skip table.options.meta since the reference seems unstable
|
|
[column.id, row.index],
|
|
);
|
|
|
|
const event = row.original;
|
|
if (!isOntimeEvent(event)) {
|
|
return null;
|
|
}
|
|
|
|
const initialValue = event.custom[column.id] ?? '';
|
|
return <MultiLineCell initialValue={initialValue} handleUpdate={update} />;
|
|
}
|
|
|
|
export function makeCuesheetColumns(customFields: CustomFields): ColumnDef<OntimeEntry>[] {
|
|
const dynamicCustomFields = Object.keys(customFields).map((key) => ({
|
|
accessorKey: key,
|
|
id: key,
|
|
header: customFields[key].label,
|
|
meta: { colour: customFields[key].colour, type: customFields[key].type },
|
|
cell: customFields[key].type === 'string' ? MakeCustomField : LazyImage,
|
|
size: 250,
|
|
minSize: 75,
|
|
}));
|
|
|
|
return [
|
|
{
|
|
accessorKey: 'cue',
|
|
id: 'cue',
|
|
header: 'Cue',
|
|
cell: MakeSingleLineField,
|
|
size: 75,
|
|
minSize: 40,
|
|
},
|
|
{
|
|
accessorKey: 'timeStart',
|
|
id: 'timeStart',
|
|
header: 'Start',
|
|
cell: MakeStart,
|
|
size: 75,
|
|
minSize: 75,
|
|
},
|
|
{
|
|
accessorKey: 'timeEnd',
|
|
id: 'timeEnd',
|
|
header: 'End',
|
|
cell: MakeEnd,
|
|
size: 75,
|
|
minSize: 75,
|
|
},
|
|
{
|
|
accessorKey: 'duration',
|
|
id: 'duration',
|
|
header: 'Duration',
|
|
cell: MakeDuration,
|
|
size: 75,
|
|
minSize: 75,
|
|
},
|
|
{
|
|
accessorKey: 'title',
|
|
id: 'title',
|
|
header: 'Title',
|
|
cell: MakeSingleLineField,
|
|
size: 250,
|
|
minSize: 75,
|
|
},
|
|
{
|
|
accessorKey: 'note',
|
|
id: 'note',
|
|
header: 'Note',
|
|
cell: MakeMultiLineField,
|
|
size: 250,
|
|
minSize: 75,
|
|
},
|
|
...dynamicCustomFields,
|
|
];
|
|
}
|