mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-26 09:29:10 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fbbbaa5922 |
@@ -25,12 +25,15 @@ export default function useReactiveTextInput(
|
|||||||
const isKeyboardSubmitting = useRef(false);
|
const isKeyboardSubmitting = useRef(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const isFocused = document.activeElement === ref.current;
|
||||||
|
if (isFocused) return;
|
||||||
|
|
||||||
if (typeof initialText === 'undefined') {
|
if (typeof initialText === 'undefined') {
|
||||||
setText('');
|
setText('');
|
||||||
} else {
|
} else {
|
||||||
setText(initialText);
|
setText(initialText);
|
||||||
}
|
}
|
||||||
}, [initialText]);
|
}, [initialText, ref]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Handles Input value change
|
* @description Handles Input value change
|
||||||
|
|||||||
@@ -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 { TableVirtuoso, TableVirtuosoHandle } from 'react-virtuoso';
|
||||||
import { useTableNav } from '@table-nav/react';
|
import { useTableNav } from '@table-nav/react';
|
||||||
import { ColumnDef, getCoreRowModel, useReactTable } from '@tanstack/react-table';
|
import { ColumnDef, getCoreRowModel, Row, Table, useReactTable } from '@tanstack/react-table';
|
||||||
import { isOntimeDelay, isOntimeGroup, isOntimeMilestone, OntimeEntry, TimeField } from 'ontime-types';
|
import { EntryId, isOntimeDelay, isOntimeGroup, isOntimeMilestone, OntimeEntry, TimeField } from 'ontime-types';
|
||||||
|
|
||||||
import EmptyPage from '../../../common/components/state/EmptyPage';
|
import EmptyPage from '../../../common/components/state/EmptyPage';
|
||||||
import EmptyTableBody from '../../../common/components/state/EmptyTableBody';
|
import EmptyTableBody from '../../../common/components/state/EmptyTableBody';
|
||||||
@@ -27,6 +27,115 @@ import { useColumnOrder, useColumnSizes, useColumnVisibility } from './useColumn
|
|||||||
|
|
||||||
import style from './CuesheetTable.module.scss';
|
import style from './CuesheetTable.module.scss';
|
||||||
|
|
||||||
|
interface VirtuosoContext {
|
||||||
|
table: Table<ExtendedEntry>;
|
||||||
|
rows: Row<ExtendedEntry>[];
|
||||||
|
cursor: EntryId | null;
|
||||||
|
columnSizeVars: Record<string, number | string>;
|
||||||
|
listeners: object;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VirtuosoTable = memo(({ style: injectedStyles, context, ...virtuosoProps }: any) => {
|
||||||
|
const { columnSizeVars, listeners } = context as VirtuosoContext;
|
||||||
|
return (
|
||||||
|
<table
|
||||||
|
className={style.cuesheet}
|
||||||
|
id="cuesheet"
|
||||||
|
style={{ ...injectedStyles, ...columnSizeVars }}
|
||||||
|
{...listeners}
|
||||||
|
{...virtuosoProps}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
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 (
|
||||||
|
<GroupRow
|
||||||
|
key={key}
|
||||||
|
groupId={entry.id}
|
||||||
|
colour={entry.colour}
|
||||||
|
rowId={row.id}
|
||||||
|
rowIndex={row.index}
|
||||||
|
table={table}
|
||||||
|
injectedStyles={virtuosoProps.style}
|
||||||
|
hasCursor={hasCursor}
|
||||||
|
{...virtuosoProps}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isOntimeDelay(entry)) {
|
||||||
|
return (
|
||||||
|
<DelayRow
|
||||||
|
key={key}
|
||||||
|
duration={entry.duration}
|
||||||
|
injectedStyles={virtuosoProps.style}
|
||||||
|
hasCursor={hasCursor}
|
||||||
|
{...virtuosoProps}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isOntimeMilestone(entry)) {
|
||||||
|
return (
|
||||||
|
<MilestoneRow
|
||||||
|
key={key}
|
||||||
|
entryId={entry.id}
|
||||||
|
isPast={entry.isPast}
|
||||||
|
parentBgColour={entry.groupColour}
|
||||||
|
parentId={entry.parent}
|
||||||
|
colour={entry.colour}
|
||||||
|
rowId={row.id}
|
||||||
|
rowIndex={rowIndex}
|
||||||
|
table={table}
|
||||||
|
injectedStyles={virtuosoProps.style}
|
||||||
|
hasCursor={hasCursor}
|
||||||
|
{...virtuosoProps}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<EventRow
|
||||||
|
key={row.id}
|
||||||
|
id={entry.id}
|
||||||
|
eventIndex={entry.eventIndex}
|
||||||
|
colour={entry.colour}
|
||||||
|
isFirstAfterGroup={entry.isFirstAfterGroup}
|
||||||
|
isLoaded={entry.isLoaded}
|
||||||
|
isPast={entry.isPast}
|
||||||
|
groupColour={entry.groupColour}
|
||||||
|
flag={entry.flag}
|
||||||
|
skip={entry.skip}
|
||||||
|
parent={entry.parent}
|
||||||
|
rowId={row.id}
|
||||||
|
rowIndex={rowIndex}
|
||||||
|
table={table}
|
||||||
|
injectedStyles={virtuosoProps.style}
|
||||||
|
hasCursor={hasCursor}
|
||||||
|
{...virtuosoProps}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
VirtuosoTableRow.displayName = 'VirtuosoTableRow';
|
||||||
|
|
||||||
|
const VirtuosoTableHead = memo((props: any) => <thead className={style.tableHeader} {...props} />);
|
||||||
|
VirtuosoTableHead.displayName = 'VirtuosoTableHead';
|
||||||
|
|
||||||
|
const VirtuosoEmptyPlaceholder = memo(() => <EmptyTableBody text="No data in rundown" />);
|
||||||
|
VirtuosoEmptyPlaceholder.displayName = 'VirtuosoEmptyPlaceholder';
|
||||||
|
|
||||||
interface CuesheetTableProps {
|
interface CuesheetTableProps {
|
||||||
columns: ColumnDef<ExtendedEntry>[];
|
columns: ColumnDef<ExtendedEntry>[];
|
||||||
cuesheetMode: AppMode;
|
cuesheetMode: AppMode;
|
||||||
@@ -49,11 +158,14 @@ export default function CuesheetTable({ columns, cuesheetMode, tableRoot = 'cues
|
|||||||
const virtuosoRef = useRef<TableVirtuosoHandle | null>(null);
|
const virtuosoRef = useRef<TableVirtuosoHandle | null>(null);
|
||||||
const { listeners } = useTableNav();
|
const { listeners } = useTableNav();
|
||||||
|
|
||||||
|
const dataRef = useRef(data);
|
||||||
|
dataRef.current = data;
|
||||||
|
|
||||||
const meta = useMemo(
|
const meta = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
handleUpdate: (rowIndex: number, accessor: string, payload: string, isCustom = false) => {
|
handleUpdate: (rowIndex: number, accessor: string, payload: string, isCustom = false) => {
|
||||||
// check if value is the same
|
// check if value is the same
|
||||||
const event = data[rowIndex];
|
const event = dataRef.current[rowIndex];
|
||||||
|
|
||||||
if (!event) {
|
if (!event) {
|
||||||
return;
|
return;
|
||||||
@@ -84,7 +196,7 @@ export default function CuesheetTable({ columns, cuesheetMode, tableRoot = 'cues
|
|||||||
hideIndexColumn,
|
hideIndexColumn,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[cuesheetMode, data, hideIndexColumn, hideTableSeconds, showDelayedTimes, updateEntry, updateTimer],
|
[cuesheetMode, hideIndexColumn, hideTableSeconds, showDelayedTimes, updateEntry, updateTimer],
|
||||||
);
|
);
|
||||||
|
|
||||||
const { columnOrder, resetColumnOrder } = useColumnOrder(columns, tableRoot);
|
const { columnOrder, resetColumnOrder } = useColumnOrder(columns, tableRoot);
|
||||||
@@ -171,6 +283,17 @@ export default function CuesheetTable({ columns, cuesheetMode, tableRoot = 'cues
|
|||||||
const allLeafColumns = table.getAllLeafColumns();
|
const allLeafColumns = table.getAllLeafColumns();
|
||||||
const { rows } = table.getRowModel();
|
const { rows } = table.getRowModel();
|
||||||
|
|
||||||
|
const virtuosoContext = useMemo(
|
||||||
|
() => ({
|
||||||
|
table,
|
||||||
|
rows,
|
||||||
|
cursor,
|
||||||
|
columnSizeVars,
|
||||||
|
listeners,
|
||||||
|
}),
|
||||||
|
[columnSizeVars, cursor, listeners, rows, table],
|
||||||
|
);
|
||||||
|
|
||||||
const isLoading = !data || status === 'pending';
|
const isLoading = !data || status === 'pending';
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
@@ -191,99 +314,14 @@ export default function CuesheetTable({ columns, cuesheetMode, tableRoot = 'cues
|
|||||||
<TableVirtuoso
|
<TableVirtuoso
|
||||||
ref={virtuosoRef}
|
ref={virtuosoRef}
|
||||||
data={data}
|
data={data}
|
||||||
|
context={virtuosoContext}
|
||||||
style={tableRoot === 'editor' ? { paddingLeft: '1rem' } : undefined}
|
style={tableRoot === 'editor' ? { paddingLeft: '1rem' } : undefined}
|
||||||
increaseViewportBy={{ top: 100, bottom: 200 }}
|
increaseViewportBy={{ top: 100, bottom: 200 }}
|
||||||
components={{
|
components={{
|
||||||
EmptyPlaceholder: () => <EmptyTableBody text='No data in rundown' />,
|
EmptyPlaceholder: VirtuosoEmptyPlaceholder,
|
||||||
Table: ({ style: injectedStyles, ...virtuosoProps }) => {
|
Table: VirtuosoTable,
|
||||||
return (
|
TableRow: VirtuosoTableRow,
|
||||||
<table
|
TableHead: VirtuosoTableHead,
|
||||||
className={style.cuesheet}
|
|
||||||
id='cuesheet'
|
|
||||||
style={{ ...injectedStyles, ...columnSizeVars }}
|
|
||||||
{...listeners}
|
|
||||||
{...virtuosoProps}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
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 (
|
|
||||||
<GroupRow
|
|
||||||
key={key}
|
|
||||||
groupId={entry.id}
|
|
||||||
colour={entry.colour}
|
|
||||||
rowId={row.id}
|
|
||||||
rowIndex={row.index}
|
|
||||||
table={table}
|
|
||||||
injectedStyles={injectedStyles}
|
|
||||||
hasCursor={hasCursor}
|
|
||||||
{...virtuosoProps}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isOntimeDelay(entry)) {
|
|
||||||
return (
|
|
||||||
<DelayRow
|
|
||||||
key={key}
|
|
||||||
duration={entry.duration}
|
|
||||||
injectedStyles={injectedStyles}
|
|
||||||
hasCursor={hasCursor}
|
|
||||||
{...virtuosoProps}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isOntimeMilestone(entry)) {
|
|
||||||
return (
|
|
||||||
<MilestoneRow
|
|
||||||
key={key}
|
|
||||||
entryId={entry.id}
|
|
||||||
isPast={entry.isPast}
|
|
||||||
parentBgColour={entry.groupColour}
|
|
||||||
parentId={entry.parent}
|
|
||||||
colour={entry.colour}
|
|
||||||
rowId={row.id}
|
|
||||||
rowIndex={rowIndex}
|
|
||||||
table={table}
|
|
||||||
injectedStyles={injectedStyles}
|
|
||||||
hasCursor={hasCursor}
|
|
||||||
{...virtuosoProps}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<EventRow
|
|
||||||
key={row.id}
|
|
||||||
id={entry.id}
|
|
||||||
eventIndex={entry.eventIndex}
|
|
||||||
colour={entry.colour}
|
|
||||||
isFirstAfterGroup={entry.isFirstAfterGroup}
|
|
||||||
isLoaded={entry.isLoaded}
|
|
||||||
isPast={entry.isPast}
|
|
||||||
groupColour={entry.groupColour}
|
|
||||||
flag={entry.flag}
|
|
||||||
skip={entry.skip}
|
|
||||||
parent={entry.parent}
|
|
||||||
rowId={row.id}
|
|
||||||
rowIndex={rowIndex}
|
|
||||||
table={table}
|
|
||||||
injectedStyles={injectedStyles}
|
|
||||||
hasCursor={hasCursor}
|
|
||||||
{...virtuosoProps}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
TableHead: (virtuosoProps) => <thead className={style.tableHeader} {...virtuosoProps} />,
|
|
||||||
}}
|
}}
|
||||||
fixedHeaderContent={() => {
|
fixedHeaderContent={() => {
|
||||||
return table.getHeaderGroups().map((headerGroup) => {
|
return table.getHeaderGroups().map((headerGroup) => {
|
||||||
|
|||||||
@@ -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: [96mStarting Ontime version 4.3.1[0m
|
||||||
|
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: [96mRequest: Initialise assets...[0m
|
||||||
|
ontime-server:dev: [2m[INFO] SERVER Loaded project demo project.json[0m
|
||||||
|
ontime-server:dev: [2m[INFO] SERVER Switch to rundown: default[0m
|
||||||
|
ontime-server:dev: [2m[INFO] SERVER Initialised Ontime with demo project.json[0m
|
||||||
|
ontime-server:dev:
|
||||||
|
ontime-server:dev:
|
||||||
|
ontime-server:dev: [96mRequest: Start server...[0m
|
||||||
|
ontime-server:dev: [2m[INFO] SERVER Runtime service started[0m
|
||||||
|
ontime-server:dev: [32mLocal: http://localhost:4001/editor[0m
|
||||||
|
ontime-server:dev: [32mNetwork: http://192.168.0.2:4001/editor[0m
|
||||||
|
ontime-server:dev: [2m[INFO] SERVER Ontime is listening on port 4001[0m
|
||||||
|
ontime-server:dev:
|
||||||
|
ontime-server:dev:
|
||||||
|
ontime-server:dev: [96mRequest: Start integrations...[0m
|
||||||
|
ontime-server:dev: [2m[INFO] SERVER Skipping OSC integration[0m
|
||||||
|
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: [2m[INFO] CLIENT 1 Connections with new: low-fi instrument[0m
|
||||||
|
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: [2m[INFO] CLIENT 0 Connections with disconnected: low-fi instrument[0m
|
||||||
|
ontime-server:dev: [2m[INFO] CLIENT 1 Connections with new: mellow uplight[0m
|
||||||
|
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: [2m[INFO] CLIENT 0 Connections with disconnected: mellow uplight[0m
|
||||||
|
ontime-server:dev: [2m[INFO] CLIENT 1 Connections with new: nostalgic mix[0m
|
||||||
|
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: [2m[INFO] CLIENT 0 Connections with disconnected: nostalgic mix[0m
|
||||||
Reference in New Issue
Block a user