mirror of
https://github.com/cpvalente/ontime.git
synced 2026-09-03 05:19:08 +00:00
Edit in cuesheet (#1372)
* pass on all event edits * MakePublic * trim value in cell * edit notes * title * add key check * don't log error Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com> * checkbox * refactor * remove log * fix test * use row number to test value --------- Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
d8f7d4bba6
commit
b048d0f88d
@@ -38,6 +38,16 @@ export const ontimeInputGhosted = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ontimeInputTransparent = {
|
||||||
|
field: {
|
||||||
|
...commonStyles,
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
_hover: {
|
||||||
|
backgroundColor: 'rgba(255, 255, 255, 0.10)', // $white-10
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const ontimeTextAreaFilled = {
|
export const ontimeTextAreaFilled = {
|
||||||
...commonStyles,
|
...commonStyles,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import { ontimeTab } from './ontimeTab';
|
|||||||
import {
|
import {
|
||||||
ontimeInputFilled,
|
ontimeInputFilled,
|
||||||
ontimeInputGhosted,
|
ontimeInputGhosted,
|
||||||
|
ontimeInputTransparent,
|
||||||
ontimeTextAreaFilled,
|
ontimeTextAreaFilled,
|
||||||
ontimeTextAreaTransparent,
|
ontimeTextAreaTransparent,
|
||||||
} from './ontimeTextInputs';
|
} from './ontimeTextInputs';
|
||||||
@@ -78,6 +79,7 @@ const theme = extendTheme({
|
|||||||
variants: {
|
variants: {
|
||||||
'ontime-filled': { ...ontimeInputFilled },
|
'ontime-filled': { ...ontimeInputFilled },
|
||||||
'ontime-ghosted': { ...ontimeInputGhosted },
|
'ontime-ghosted': { ...ontimeInputGhosted },
|
||||||
|
'ontime-transparent': { ...ontimeInputTransparent },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Kbd: {
|
Kbd: {
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
import { useCallback, useRef } from 'react';
|
import { useCallback, useRef } from 'react';
|
||||||
import { ColumnDef, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table';
|
import { ColumnDef, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table';
|
||||||
import Color from 'color';
|
import Color from 'color';
|
||||||
import { isOntimeBlock, isOntimeDelay, isOntimeEvent, OntimeRundown, OntimeRundownEntry } from 'ontime-types';
|
import {
|
||||||
|
CustomFieldLabel,
|
||||||
|
isOntimeBlock,
|
||||||
|
isOntimeDelay,
|
||||||
|
isOntimeEvent,
|
||||||
|
OntimeRundown,
|
||||||
|
OntimeRundownEntry,
|
||||||
|
} from 'ontime-types';
|
||||||
|
|
||||||
import useFollowComponent from '../../common/hooks/useFollowComponent';
|
import useFollowComponent from '../../common/hooks/useFollowComponent';
|
||||||
import { getAccessibleColour } from '../../common/utils/styleUtils';
|
import { getAccessibleColour } from '../../common/utils/styleUtils';
|
||||||
@@ -19,12 +26,20 @@ import style from './Cuesheet.module.scss';
|
|||||||
interface CuesheetProps {
|
interface CuesheetProps {
|
||||||
data: OntimeRundown;
|
data: OntimeRundown;
|
||||||
columns: ColumnDef<OntimeRundownEntry>[];
|
columns: ColumnDef<OntimeRundownEntry>[];
|
||||||
handleUpdate: (rowIndex: number, accessor: keyof OntimeRundownEntry, payload: unknown) => void;
|
handleUpdate: (rowIndex: number, accessor: keyof OntimeRundownEntry, payload: string) => void;
|
||||||
|
handleUpdateCustom: (rowIndex: number, accessor: CustomFieldLabel, payload: string) => void;
|
||||||
selectedId: string | null;
|
selectedId: string | null;
|
||||||
currentBlockId: string | null;
|
currentBlockId: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Cuesheet({ data, columns, handleUpdate, selectedId, currentBlockId }: CuesheetProps) {
|
export default function Cuesheet({
|
||||||
|
data,
|
||||||
|
columns,
|
||||||
|
handleUpdate,
|
||||||
|
handleUpdateCustom,
|
||||||
|
selectedId,
|
||||||
|
currentBlockId,
|
||||||
|
}: CuesheetProps) {
|
||||||
const { followSelected, showSettings, showDelayBlock, showPrevious, showIndexColumn } = useCuesheetSettings();
|
const { followSelected, showSettings, showDelayBlock, showPrevious, showIndexColumn } = useCuesheetSettings();
|
||||||
const {
|
const {
|
||||||
columnVisibility,
|
columnVisibility,
|
||||||
@@ -51,6 +66,7 @@ export default function Cuesheet({ data, columns, handleUpdate, selectedId, curr
|
|||||||
},
|
},
|
||||||
meta: {
|
meta: {
|
||||||
handleUpdate,
|
handleUpdate,
|
||||||
|
handleUpdateCustom,
|
||||||
},
|
},
|
||||||
onColumnVisibilityChange: setColumnVisibility,
|
onColumnVisibilityChange: setColumnVisibility,
|
||||||
onColumnSizingChange: setColumnSizing,
|
onColumnSizingChange: setColumnSizing,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useCallback, useMemo } from 'react';
|
|||||||
import { IconButton, useDisclosure } from '@chakra-ui/react';
|
import { IconButton, useDisclosure } from '@chakra-ui/react';
|
||||||
import { IoApps } from '@react-icons/all-files/io5/IoApps';
|
import { IoApps } from '@react-icons/all-files/io5/IoApps';
|
||||||
import { IoSettingsOutline } from '@react-icons/all-files/io5/IoSettingsOutline';
|
import { IoSettingsOutline } from '@react-icons/all-files/io5/IoSettingsOutline';
|
||||||
import { CustomFieldLabel, isOntimeEvent } from 'ontime-types';
|
import { CustomFieldLabel, isOntimeEvent, OntimeEvent } from 'ontime-types';
|
||||||
|
|
||||||
import ProductionNavigationMenu from '../../common/components/navigation-menu/ProductionNavigationMenu';
|
import ProductionNavigationMenu from '../../common/components/navigation-menu/ProductionNavigationMenu';
|
||||||
import EmptyPage from '../../common/components/state/EmptyPage';
|
import EmptyPage from '../../common/components/state/EmptyPage';
|
||||||
@@ -26,7 +26,7 @@ export default function CuesheetPage() {
|
|||||||
const { data: customFields } = useCustomFields();
|
const { data: customFields } = useCustomFields();
|
||||||
const { isOpen: isMenuOpen, onOpen, onClose } = useDisclosure();
|
const { isOpen: isMenuOpen, onOpen, onClose } = useDisclosure();
|
||||||
|
|
||||||
const { updateCustomField } = useEventAction();
|
const { updateCustomField, updateEvent } = useEventAction();
|
||||||
const featureData = useCuesheet();
|
const featureData = useCuesheet();
|
||||||
const columns = useMemo(() => makeCuesheetColumns(customFields), [customFields]);
|
const columns = useMemo(() => makeCuesheetColumns(customFields), [customFields]);
|
||||||
const toggleSettings = useCuesheetSettings((state) => state.toggleSettings);
|
const toggleSettings = useCuesheetSettings((state) => state.toggleSettings);
|
||||||
@@ -34,11 +34,10 @@ export default function CuesheetPage() {
|
|||||||
useWindowTitle('Cuesheet');
|
useWindowTitle('Cuesheet');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles updating a field
|
* Handles updating a custom field
|
||||||
* Currently, only custom fields can be updated from the cuesheet
|
|
||||||
*/
|
*/
|
||||||
const handleUpdate = useCallback(
|
const handleUpdateCustom = useCallback(
|
||||||
async (rowIndex: number, accessor: CustomFieldLabel, payload: unknown) => {
|
async (rowIndex: number, accessor: CustomFieldLabel, payload: string) => {
|
||||||
if (!flatRundown || rundownStatus !== 'success') {
|
if (!flatRundown || rundownStatus !== 'success') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -53,29 +52,44 @@ export default function CuesheetPage() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// skip if there is no value change
|
||||||
const previousValue = event.custom[accessor];
|
const previousValue = event.custom[accessor];
|
||||||
|
if (previousValue === payload) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateCustomField(event.id, accessor, payload);
|
||||||
|
},
|
||||||
|
[flatRundown, rundownStatus, updateCustomField],
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles updating all other string fields
|
||||||
|
*/
|
||||||
|
const handleUpdate = useCallback(
|
||||||
|
async (rowIndex: number, accessor: keyof OntimeEvent, payload: string) => {
|
||||||
|
if (!flatRundown || rundownStatus !== 'success') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rowIndex == null || accessor == null || payload == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if value is the same
|
||||||
|
const event = flatRundown[rowIndex];
|
||||||
|
if (!event || !isOntimeEvent(event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip if there is no value change
|
||||||
|
const previousValue = event[accessor];
|
||||||
if (previousValue === payload) {
|
if (previousValue === payload) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if value is valid
|
updateEvent({ id: event.id, [accessor]: payload });
|
||||||
// in anticipation to different types of event here
|
|
||||||
if (typeof payload !== 'string') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// cleanup
|
|
||||||
const cleanVal = payload.trim();
|
|
||||||
|
|
||||||
// submit
|
|
||||||
try {
|
|
||||||
await updateCustomField(event.id, accessor, cleanVal);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[flatRundown, rundownStatus, updateCustomField],
|
[flatRundown, rundownStatus, updateEvent],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!customFields || !flatRundown || rundownStatus !== 'success') {
|
if (!customFields || !flatRundown || rundownStatus !== 'success') {
|
||||||
@@ -106,6 +120,8 @@ export default function CuesheetPage() {
|
|||||||
data={flatRundown}
|
data={flatRundown}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
handleUpdate={handleUpdate}
|
handleUpdate={handleUpdate}
|
||||||
|
handleUpdateCustom={handleUpdateCustom}
|
||||||
|
//TODO: stabilizer selectedEventId and currentBlockId
|
||||||
selectedId={featureData.selectedEventId}
|
selectedId={featureData.selectedEventId}
|
||||||
currentBlockId={featureData.currentBlockId}
|
currentBlockId={featureData.currentBlockId}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
import { ChangeEvent, memo, useCallback, useEffect, useRef, useState } from 'react';
|
|
||||||
import { getHotkeyHandler } from '@mantine/hooks';
|
|
||||||
|
|
||||||
import { AutoTextArea } from '../../../common/components/input/auto-text-area/AutoTextArea';
|
|
||||||
|
|
||||||
interface EditableCellProps {
|
|
||||||
value: string;
|
|
||||||
handleUpdate: (newValue: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const EditableCell = (props: EditableCellProps) => {
|
|
||||||
const { value: initialValue, handleUpdate } = props;
|
|
||||||
|
|
||||||
// We need to keep and update the state of the cell normally
|
|
||||||
const [value, setValue] = useState(initialValue);
|
|
||||||
const ref = useRef<HTMLAreaElement>();
|
|
||||||
const onChange = useCallback((event: ChangeEvent<HTMLTextAreaElement>) => setValue(event.target.value), []);
|
|
||||||
|
|
||||||
// We'll only update the external data when the input is blurred
|
|
||||||
const onBlur = useCallback(() => handleUpdate(value), [handleUpdate, value]);
|
|
||||||
|
|
||||||
//TODO: maybe we can unify this with `useReactiveTextInput`
|
|
||||||
const onKeyDown = getHotkeyHandler([
|
|
||||||
['mod + Enter', () => ref.current?.blur()],
|
|
||||||
[
|
|
||||||
'Escape',
|
|
||||||
() => {
|
|
||||||
setValue(initialValue);
|
|
||||||
setTimeout(() => ref.current?.blur());
|
|
||||||
},
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
// If the initialValue is changed external, sync it up with our state
|
|
||||||
useEffect(() => {
|
|
||||||
setValue(initialValue);
|
|
||||||
}, [initialValue]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<AutoTextArea
|
|
||||||
size='sm'
|
|
||||||
value={value}
|
|
||||||
inputref={ref}
|
|
||||||
onChange={onChange}
|
|
||||||
onBlur={onBlur}
|
|
||||||
rows={1}
|
|
||||||
onKeyDown={onKeyDown}
|
|
||||||
transition='none'
|
|
||||||
spellCheck={false}
|
|
||||||
style={{ padding: 0 }}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(EditableCell);
|
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { memo, useCallback, useRef } from 'react';
|
||||||
|
|
||||||
|
import { AutoTextArea } from '../../../common/components/input/auto-text-area/AutoTextArea';
|
||||||
|
import useReactiveTextInput from '../../../common/components/input/text-input/useReactiveTextInput';
|
||||||
|
|
||||||
|
interface MultiLineCellProps {
|
||||||
|
initialValue: string;
|
||||||
|
handleUpdate: (newValue: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MultiLineCell = (props: MultiLineCellProps) => {
|
||||||
|
const { initialValue, handleUpdate } = props;
|
||||||
|
const ref = useRef<HTMLInputElement | null>(null);
|
||||||
|
const submitCallback = useCallback((newValue: string) => handleUpdate(newValue), [handleUpdate]);
|
||||||
|
|
||||||
|
const { value, onChange, onBlur, onKeyDown } = useReactiveTextInput(initialValue, submitCallback, ref, {
|
||||||
|
submitOnCtrlEnter: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AutoTextArea
|
||||||
|
inputref={ref}
|
||||||
|
rows={1}
|
||||||
|
size='sm'
|
||||||
|
style={{ padding: 0 }}
|
||||||
|
transition='none'
|
||||||
|
variant='ontime-transparent'
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
onBlur={onBlur}
|
||||||
|
onKeyDown={onKeyDown}
|
||||||
|
spellCheck={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(MultiLineCell);
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { memo, useCallback, useRef } from 'react';
|
||||||
|
import { Input } from '@chakra-ui/react';
|
||||||
|
|
||||||
|
import useReactiveTextInput from '../../../common/components/input/text-input/useReactiveTextInput';
|
||||||
|
|
||||||
|
interface SingleLineCellProps {
|
||||||
|
initialValue: string;
|
||||||
|
handleUpdate: (newValue: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SingleLineCell = (props: SingleLineCellProps) => {
|
||||||
|
const { initialValue, handleUpdate } = props;
|
||||||
|
const ref = useRef<HTMLInputElement | null>(null);
|
||||||
|
const submitCallback = useCallback((newValue: string) => handleUpdate(newValue), [handleUpdate]);
|
||||||
|
|
||||||
|
const { value, onChange, onBlur, onKeyDown } = useReactiveTextInput(initialValue, submitCallback, ref, {
|
||||||
|
submitOnCtrlEnter: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
ref={ref}
|
||||||
|
size='sx'
|
||||||
|
variant='ontime-transparent'
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
onBlur={onBlur}
|
||||||
|
onKeyDown={onKeyDown}
|
||||||
|
spellCheck={false}
|
||||||
|
autoComplete='off'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(SingleLineCell);
|
||||||
@@ -1,19 +1,37 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { IoCheckmark } from '@react-icons/all-files/io5/IoCheckmark';
|
import { Checkbox } from '@chakra-ui/react';
|
||||||
import { CellContext, ColumnDef } from '@tanstack/react-table';
|
import { CellContext, ColumnDef } from '@tanstack/react-table';
|
||||||
import { CustomFields, isOntimeEvent, OntimeEvent, OntimeRundownEntry } from 'ontime-types';
|
import { CustomFields, isOntimeEvent, OntimeEvent, OntimeRundownEntry } from 'ontime-types';
|
||||||
|
|
||||||
import DelayIndicator from '../../common/components/delay-indicator/DelayIndicator';
|
import DelayIndicator from '../../common/components/delay-indicator/DelayIndicator';
|
||||||
import RunningTime from '../../features/viewers/common/running-time/RunningTime';
|
import RunningTime from '../../features/viewers/common/running-time/RunningTime';
|
||||||
|
|
||||||
import EditableCell from './cuesheet-table-elements/EditableCell';
|
import MultiLineCell from './cuesheet-table-elements/MultiLineCell';
|
||||||
|
import SingleLineCell from './cuesheet-table-elements/SingleLineCell';
|
||||||
import { useCuesheetSettings } from './store/cuesheetSettingsStore';
|
import { useCuesheetSettings } from './store/cuesheetSettingsStore';
|
||||||
|
|
||||||
import style from './Cuesheet.module.scss';
|
import style from './Cuesheet.module.scss';
|
||||||
|
|
||||||
function makePublic(row: CellContext<OntimeRundownEntry, unknown>) {
|
function MakePublic({ row, column, table }: CellContext<OntimeRundownEntry, unknown>) {
|
||||||
const cellValue = row.getValue();
|
const update = useCallback(
|
||||||
return cellValue ? <IoCheckmark className={style.check} /> : '';
|
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
// @ts-expect-error -- we inject this into react-table
|
||||||
|
table.options.meta?.handleUpdate(row.index, column.id, event.target.checked);
|
||||||
|
},
|
||||||
|
// 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 isChecked = event.isPublic;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Checkbox variant='ontime-ondark' onChange={update} isChecked={isChecked} style={{ verticalAlign: 'middle' }} />
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function MakeTimer({ getValue, row: { original } }: CellContext<OntimeRundownEntry, unknown>) {
|
function MakeTimer({ getValue, row: { original } }: CellContext<OntimeRundownEntry, unknown>) {
|
||||||
@@ -40,7 +58,7 @@ function MakeDuration({ getValue }: CellContext<OntimeRundownEntry, unknown>) {
|
|||||||
return <RunningTime value={cellValue} hideSeconds={hideSeconds} />;
|
return <RunningTime value={cellValue} hideSeconds={hideSeconds} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function MakeCustomField({ row, column, table }: CellContext<OntimeRundownEntry, unknown>) {
|
function MakeMultiLineField({ row, column, table }: CellContext<OntimeRundownEntry, unknown>) {
|
||||||
const update = useCallback(
|
const update = useCallback(
|
||||||
(newValue: string) => {
|
(newValue: string) => {
|
||||||
// @ts-expect-error -- we inject this into react-table
|
// @ts-expect-error -- we inject this into react-table
|
||||||
@@ -55,10 +73,49 @@ function MakeCustomField({ row, column, table }: CellContext<OntimeRundownEntry,
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// events dont necessarily contain all custom fields
|
const initialValue = event[column.id as keyof OntimeRundownEntry] ?? '';
|
||||||
|
|
||||||
|
return <MultiLineCell initialValue={initialValue} handleUpdate={update} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
function MakeSingleLineField({ row, column, table }: CellContext<OntimeRundownEntry, unknown>) {
|
||||||
|
const update = useCallback(
|
||||||
|
(newValue: string) => {
|
||||||
|
// @ts-expect-error -- we inject this into react-table
|
||||||
|
table.options.meta?.handleUpdate(row.index, column.id, newValue);
|
||||||
|
},
|
||||||
|
// 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 OntimeRundownEntry] ?? '';
|
||||||
|
|
||||||
|
return <SingleLineCell initialValue={initialValue} handleUpdate={update} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
function MakeCustomField({ row, column, table }: CellContext<OntimeRundownEntry, unknown>) {
|
||||||
|
const update = useCallback(
|
||||||
|
(newValue: string) => {
|
||||||
|
// @ts-expect-error -- we inject this into react-table
|
||||||
|
table.options.meta?.handleUpdateCustom(row.index, column.id, newValue);
|
||||||
|
},
|
||||||
|
// 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] ?? '';
|
const initialValue = event.custom[column.id] ?? '';
|
||||||
|
|
||||||
return <EditableCell value={initialValue} handleUpdate={update} />;
|
return <MultiLineCell initialValue={initialValue} handleUpdate={update} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeCuesheetColumns(customFields: CustomFields): ColumnDef<OntimeRundownEntry>[] {
|
export function makeCuesheetColumns(customFields: CustomFields): ColumnDef<OntimeRundownEntry>[] {
|
||||||
@@ -83,7 +140,7 @@ export function makeCuesheetColumns(customFields: CustomFields): ColumnDef<Ontim
|
|||||||
accessorKey: 'isPublic',
|
accessorKey: 'isPublic',
|
||||||
id: 'isPublic',
|
id: 'isPublic',
|
||||||
header: 'Public',
|
header: 'Public',
|
||||||
cell: makePublic,
|
cell: MakePublic,
|
||||||
size: 45,
|
size: 45,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -111,14 +168,14 @@ export function makeCuesheetColumns(customFields: CustomFields): ColumnDef<Ontim
|
|||||||
accessorKey: 'title',
|
accessorKey: 'title',
|
||||||
id: 'title',
|
id: 'title',
|
||||||
header: 'Title',
|
header: 'Title',
|
||||||
cell: (row) => row.getValue(),
|
cell: MakeSingleLineField,
|
||||||
size: 250,
|
size: 250,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'note',
|
accessorKey: 'note',
|
||||||
id: 'note',
|
id: 'note',
|
||||||
header: 'Note',
|
header: 'Note',
|
||||||
cell: (row) => row.getValue(),
|
cell: MakeMultiLineField,
|
||||||
size: 250,
|
size: 250,
|
||||||
},
|
},
|
||||||
...dynamicCustomFields,
|
...dynamicCustomFields,
|
||||||
|
|||||||
@@ -1,11 +1,18 @@
|
|||||||
import { test } from '@playwright/test';
|
import { expect, test } from '@playwright/test';
|
||||||
|
|
||||||
test('cuesheet displays events and exports csv', async ({ page }) => {
|
test('cuesheet displays events', async ({ page }) => {
|
||||||
// same elements in cuesheet
|
// same elements in cuesheet
|
||||||
await page.goto('http://localhost:4001/cuesheet');
|
await page.goto('http://localhost:4001/cuesheet');
|
||||||
await page.getByText('Eurovision Song Contest').click();
|
await expect(page.getByText('Eurovision Song Contest')).toBeVisible();
|
||||||
await page.getByRole('cell', { name: 'Lunch break' }).click();
|
await expect(page.getByRole('row', { name: 'Lunch break' })).toBeVisible();
|
||||||
await page.getByRole('cell', { name: 'Albania' }).click();
|
|
||||||
await page.getByRole('cell', { name: 'Latvia' }).click();
|
await expect(page.locator('tr:nth-child(1) > td:nth-child(7)').first().getByRole('textbox').first()).toHaveValue(
|
||||||
await page.getByRole('cell', { name: 'Lithuania' }).click();
|
'Albania',
|
||||||
|
);
|
||||||
|
await expect(page.locator('tr:nth-child(2) > td:nth-child(7)').first().getByRole('textbox').first()).toHaveValue(
|
||||||
|
'Latvia',
|
||||||
|
);
|
||||||
|
await expect(page.locator('tr:nth-child(3) > td:nth-child(7)').first().getByRole('textbox').first()).toHaveValue(
|
||||||
|
'Lithuania',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user