diff --git a/apps/client/src/common/components/input/text-input/useReactiveTextInput.tsx b/apps/client/src/common/components/input/text-input/useReactiveTextInput.tsx index 3185e40d5..c3e5d74ac 100644 --- a/apps/client/src/common/components/input/text-input/useReactiveTextInput.tsx +++ b/apps/client/src/common/components/input/text-input/useReactiveTextInput.tsx @@ -25,12 +25,15 @@ export default function useReactiveTextInput( const isKeyboardSubmitting = useRef(false); useEffect(() => { + const isFocused = document.activeElement === ref.current; + if (isFocused) return; + if (typeof initialText === 'undefined') { setText(''); } else { setText(initialText); } - }, [initialText]); + }, [initialText, ref]); /** * @description Handles Input value change diff --git a/apps/client/src/views/cuesheet/cuesheet-table/CuesheetTable.tsx b/apps/client/src/views/cuesheet/cuesheet-table/CuesheetTable.tsx index 63b17c547..c9f4f9c3d 100644 --- a/apps/client/src/views/cuesheet/cuesheet-table/CuesheetTable.tsx +++ b/apps/client/src/views/cuesheet/cuesheet-table/CuesheetTable.tsx @@ -1,8 +1,8 @@ -import { useCallback, useEffect, useMemo, useRef } from 'react'; +import { memo, useCallback, useEffect, useMemo, useRef } from 'react'; import { TableVirtuoso, TableVirtuosoHandle } from 'react-virtuoso'; import { useTableNav } from '@table-nav/react'; -import { ColumnDef, getCoreRowModel, useReactTable } from '@tanstack/react-table'; -import { isOntimeDelay, isOntimeGroup, isOntimeMilestone, OntimeEntry, TimeField } from 'ontime-types'; +import { ColumnDef, getCoreRowModel, Row, Table, useReactTable } from '@tanstack/react-table'; +import { EntryId, isOntimeDelay, isOntimeGroup, isOntimeMilestone, OntimeEntry, TimeField } from 'ontime-types'; import EmptyPage from '../../../common/components/state/EmptyPage'; import EmptyTableBody from '../../../common/components/state/EmptyTableBody'; @@ -27,6 +27,115 @@ import { useColumnOrder, useColumnSizes, useColumnVisibility } from './useColumn import style from './CuesheetTable.module.scss'; +interface VirtuosoContext { + table: Table; + rows: Row[]; + cursor: EntryId | null; + columnSizeVars: Record; + listeners: object; +} + +const VirtuosoTable = memo(({ style: injectedStyles, context, ...virtuosoProps }: any) => { + const { columnSizeVars, listeners } = context as VirtuosoContext; + return ( + + ); +}); +VirtuosoTable.displayName = 'VirtuosoTable'; + +const VirtuosoTableRow = memo(({ item: _item, context, ...virtuosoProps }: any) => { + const { table, rows, cursor } = context as VirtuosoContext; + const rowIndex = virtuosoProps['data-index']; + const row = rows[rowIndex]; + if (!row) return null; + + const key = row.original.id; + const entry = row.original; + const hasCursor = entry.id === cursor; + + if (isOntimeGroup(entry)) { + return ( + + ); + } + + if (isOntimeDelay(entry)) { + return ( + + ); + } + + if (isOntimeMilestone(entry)) { + return ( + + ); + } + + return ( + + ); +}); +VirtuosoTableRow.displayName = 'VirtuosoTableRow'; + +const VirtuosoTableHead = memo((props: any) => ); +VirtuosoTableHead.displayName = 'VirtuosoTableHead'; + +const VirtuosoEmptyPlaceholder = memo(() => ); +VirtuosoEmptyPlaceholder.displayName = 'VirtuosoEmptyPlaceholder'; + interface CuesheetTableProps { columns: ColumnDef[]; cuesheetMode: AppMode; @@ -49,11 +158,14 @@ export default function CuesheetTable({ columns, cuesheetMode, tableRoot = 'cues const virtuosoRef = useRef(null); const { listeners } = useTableNav(); + const dataRef = useRef(data); + dataRef.current = data; + const meta = useMemo( () => ({ handleUpdate: (rowIndex: number, accessor: string, payload: string, isCustom = false) => { // check if value is the same - const event = data[rowIndex]; + const event = dataRef.current[rowIndex]; if (!event) { return; @@ -84,7 +196,7 @@ export default function CuesheetTable({ columns, cuesheetMode, tableRoot = 'cues hideIndexColumn, }, }), - [cuesheetMode, data, hideIndexColumn, hideTableSeconds, showDelayedTimes, updateEntry, updateTimer], + [cuesheetMode, hideIndexColumn, hideTableSeconds, showDelayedTimes, updateEntry, updateTimer], ); const { columnOrder, resetColumnOrder } = useColumnOrder(columns, tableRoot); @@ -171,6 +283,17 @@ export default function CuesheetTable({ columns, cuesheetMode, tableRoot = 'cues const allLeafColumns = table.getAllLeafColumns(); const { rows } = table.getRowModel(); + const virtuosoContext = useMemo( + () => ({ + table, + rows, + cursor, + columnSizeVars, + listeners, + }), + [columnSizeVars, cursor, listeners, rows, table], + ); + const isLoading = !data || status === 'pending'; if (isLoading) { @@ -191,99 +314,14 @@ export default function CuesheetTable({ columns, cuesheetMode, tableRoot = 'cues , - Table: ({ style: injectedStyles, ...virtuosoProps }) => { - return ( -
- ); - }, - TableRow: ({ item: _item, style: injectedStyles, ...virtuosoProps }) => { - // eslint-disable-next-line react/destructuring-assignment - const rowIndex = virtuosoProps['data-index']; - const row = rows[rowIndex]; - const key = row.original.id; - const entry = row.original; - const hasCursor = entry.id === cursor; - - if (isOntimeGroup(entry)) { - return ( - - ); - } - - if (isOntimeDelay(entry)) { - return ( - - ); - } - - if (isOntimeMilestone(entry)) { - return ( - - ); - } - - return ( - - ); - }, - TableHead: (virtuosoProps) => , + EmptyPlaceholder: VirtuosoEmptyPlaceholder, + Table: VirtuosoTable, + TableRow: VirtuosoTableRow, + TableHead: VirtuosoTableHead, }} fixedHeaderContent={() => { return table.getHeaderGroups().map((headerGroup) => { diff --git a/dev_output.log b/dev_output.log new file mode 100644 index 000000000..3e8713ffb --- /dev/null +++ b/dev_output.log @@ -0,0 +1,94 @@ + +> ontime@4.3.1 dev /app +> turbo run dev + + +Attention: +Turborepo now collects completely anonymous telemetry regarding usage. +This information is used to shape the Turborepo roadmap and prioritize features. +You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL: +https://turborepo.com/docs/telemetry + +turbo 2.5.8 + +• Packages in scope: @getontime/cli, @getontime/resolver, ontime-electron, ontime-server, ontime-types, ontime-ui, ontime-utils +• Running dev in 7 packages +• Remote caching disabled +ontime-server:dev: cache bypass, force executing 736e67d68a6b5681 +ontime-ui:dev: cache bypass, force executing 9eacdb30152cd80e +ontime-ui:dev: +ontime-ui:dev: > ontime-ui@4.3.1 dev /app/apps/client +ontime-ui:dev: > cross-env BROWSER=none vite +ontime-ui:dev: +ontime-server:dev: +ontime-server:dev: > ontime-server@4.3.1 dev /app/apps/server +ontime-server:dev: > cross-env NODE_ENV=development tsx watch ./src/index.ts +ontime-server:dev: +ontime-ui:dev: +ontime-ui:dev: VITE v6.3.1 ready in 748 ms +ontime-ui:dev: +ontime-ui:dev: ➜ Local: http://localhost:3000/ +ontime-ui:dev: ➜ Network: use --host to expose +ontime-server:dev: +ontime-server:dev: +ontime-server:dev: Starting Ontime version 4.3.1 +ontime-server:dev: Ontime running in development environment +ontime-server:dev: Ontime source directory at /app/apps/server/src/ +ontime-server:dev: Ontime public directory at /home/jules/.Ontime +ontime-server:dev: +ontime-server:dev: +ontime-server:dev: Request: Initialise assets... +ontime-server:dev: [INFO] SERVER Loaded project demo project.json +ontime-server:dev: [INFO] SERVER Switch to rundown: default +ontime-server:dev: [INFO] SERVER Initialised Ontime with demo project.json +ontime-server:dev: +ontime-server:dev: +ontime-server:dev: Request: Start server... +ontime-server:dev: [INFO] SERVER Runtime service started +ontime-server:dev: Local: http://localhost:4001/editor +ontime-server:dev: Network: http://192.168.0.2:4001/editor +ontime-server:dev: [INFO] SERVER Ontime is listening on port 4001 +ontime-server:dev: +ontime-server:dev: +ontime-server:dev: Request: Start integrations... +ontime-server:dev: [INFO] SERVER Skipping OSC integration +ontime-ui:dev: Browserslist: browsers data (caniuse-lite) is 9 months old. Please run: +ontime-ui:dev: npx update-browserslist-db@latest +ontime-ui:dev: Why you should do it regularly: https://github.com/browserslist/update-db#readme +ontime-ui:dev: Browserslist: caniuse-lite is outdated. Please run: +ontime-ui:dev: npx update-browserslist-db@latest +ontime-ui:dev: Why you should do it regularly: https://github.com/browserslist/update-db#readme +ontime-server:dev: [INFO] CLIENT 1 Connections with new: low-fi instrument +ontime-ui:dev: Proxy: GET /data/settings +ontime-ui:dev: Proxy: GET /user/translations/translations.json +ontime-ui:dev: Proxy: GET /data/report +ontime-ui:dev: Proxy: GET /data/view-settings +ontime-ui:dev: Proxy: GET /data/rundowns/current +ontime-ui:dev: Proxy: GET /data/project +ontime-ui:dev: Proxy: GET /data/db/all +ontime-ui:dev: Proxy: GET /data/rundowns/current +ontime-ui:dev: Proxy: GET /data/project +ontime-ui:dev: Proxy: GET /data/db/all +ontime-server:dev: [INFO] CLIENT 0 Connections with disconnected: low-fi instrument +ontime-server:dev: [INFO] CLIENT 1 Connections with new: mellow uplight +ontime-ui:dev: Proxy: GET /data/settings +ontime-ui:dev: Proxy: GET /user/translations/translations.json +ontime-ui:dev: Proxy: GET /data/report +ontime-ui:dev: Proxy: GET /data/view-settings +ontime-ui:dev: Proxy: GET /data/rundowns/current +ontime-ui:dev: Proxy: GET /data/project +ontime-ui:dev: Proxy: GET /data/rundowns/current +ontime-ui:dev: Proxy: GET /data/project +ontime-server:dev: [INFO] CLIENT 0 Connections with disconnected: mellow uplight +ontime-server:dev: [INFO] CLIENT 1 Connections with new: nostalgic mix +ontime-ui:dev: Proxy: GET /data/settings +ontime-ui:dev: Proxy: GET /user/translations/translations.json +ontime-ui:dev: Proxy: GET /data/report +ontime-ui:dev: Proxy: GET /data/view-settings +ontime-ui:dev: Proxy: GET /data/rundowns/current +ontime-ui:dev: Proxy: GET /data/project +ontime-ui:dev: Proxy: GET /data/rundowns/current +ontime-ui:dev: Proxy: GET /data/project +ontime-ui:dev: Proxy: GET /data/custom-fields +ontime-ui:dev: Proxy: GET /data/rundowns/current +ontime-server:dev: [INFO] CLIENT 0 Connections with disconnected: nostalgic mix