Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@

# Ignore build folders
node_modules
dist
**/node_modules
**/dist

# Ignore default volumes created by running docker compose up
ontime-db
Expand Down
13 changes: 13 additions & 0 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,16 @@ Other useful commands

- __List running processes__ by running `docker ps`
- __Kill running process__ by running `docker kill <process-id>`

## CONTRIBUTION GUIDELINES

If you want to propose changes to the codebase, please reach out before opening a Pull Request.

For new PRs, please follow the following checklist:
* [ ] You have updated and ran unit locally and they are passing. Unit tests are generally created for all utility functions and business logic
* [ ] You have ran code formatting and linting in all your changes
* [ ] The branch is clean and the commits are meaningfully separated and contain descriptive messages
* [ ] The PR body contains description and motivation for the changes

After this checklist is complete, you can request a review from one of the maintainers to get feedback and approval on the changes. \
We will review as soon as possible
2 changes: 1 addition & 1 deletion apps/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@getontime/cli",
"version": "4.0.0-beta.2",
"version": "4.0.0-beta.3",
"author": "Carlos Valente",
"description": "Time keeping for live events",
"repository": "https://github.com/cpvalente/ontime",
Expand Down
2 changes: 1 addition & 1 deletion apps/client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ontime-ui",
"version": "4.0.0-beta.2",
"version": "4.0.0-beta.3",
"private": true,
"type": "module",
"dependencies": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
}

.pin {
margin-top: 0.5rem;
display: flex;
align-items: center;
justify-content: center;
gap: 4px;

input {
font-size: 4rem;
Expand Down
75 changes: 16 additions & 59 deletions apps/client/src/common/hooks/useFollowComponent.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { RefObject, useCallback, useEffect, useRef } from 'react';

import { useSelectedEventId } from './useSocket';
import { RefObject, useCallback, useEffect } from 'react';
import { MaybeString } from 'ontime-types';

function scrollToComponent<ComponentRef extends HTMLElement, ScrollRef extends HTMLElement>(
componentRef: RefObject<ComponentRef>,
Expand All @@ -18,37 +17,26 @@ function scrollToComponent<ComponentRef extends HTMLElement, ScrollRef extends H
scrollRef.current.scrollTo({ top, behavior: 'smooth' });
}

function snapToComponent<ComponentRef extends HTMLElement, ScrollRef extends HTMLElement>(
componentRef: RefObject<ComponentRef>,
scrollRef: RefObject<ScrollRef>,
topOffset: number,
) {
if (!componentRef.current || !scrollRef.current) {
return;
}

const componentRect = componentRef.current.getBoundingClientRect();
const scrollRect = scrollRef.current.getBoundingClientRect();
const top = componentRect.top - scrollRect.top + scrollRef.current.scrollTop - topOffset;

// maintain current x scroll position
scrollRef.current.scrollTo(scrollRef.current.scrollLeft, top);
}

interface UseFollowComponentProps {
followRef: RefObject<HTMLElement | null>;
scrollRef: RefObject<HTMLElement | null>;
doFollow: boolean;
topOffset?: number;
setScrollFlag?: (newValue: boolean) => void;
followTrigger?: MaybeString; // this would be an entry id or null
}

export default function useFollowComponent(props: UseFollowComponentProps) {
const { followRef, scrollRef, doFollow, topOffset = 100, setScrollFlag } = props;

// when cursor moves, view should follow
export default function useFollowComponent({
followRef,
scrollRef,
doFollow,
topOffset = 100,
setScrollFlag,
followTrigger,
}: UseFollowComponentProps) {
// when trigger moves, view should follow
useEffect(() => {
if (!doFollow) {
if (!doFollow || !followTrigger) {
return;
}

Expand All @@ -60,49 +48,18 @@ export default function useFollowComponent(props: UseFollowComponentProps) {
setScrollFlag?.(false);
});
}

// eslint-disable-next-line -- the prompt seems incorrect
}, [followRef?.current, scrollRef?.current]);
}, [followTrigger, doFollow, followRef, scrollRef, setScrollFlag, topOffset]);

const scrollToRefComponent = useCallback(
(componentRef = followRef, containerRef = scrollRef, offset = topOffset) => {
if (componentRef.current && containerRef.current) {
if (componentRef && containerRef) {
// @ts-expect-error -- we know this are not null
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
scrollToComponent(componentRef!, scrollRef!, offset);
scrollToComponent(componentRef!, containerRef!, offset);
}
},
[followRef, scrollRef, topOffset],
);

return scrollToRefComponent;
}

export function useFollowSelected(doFollow: boolean, topOffset = 100) {
const selectedEvenId = useSelectedEventId();

const selectedRef = useRef<HTMLTableRowElement>(null);
const scrollRef = useRef<HTMLDivElement>(null);

useEffect(() => {
if (!doFollow) {
return;
}

if (selectedEvenId && selectedRef.current && scrollRef.current) {
// Use requestAnimationFrame to ensure the component is fully loaded
window.requestAnimationFrame(() => {
snapToComponent(
{ current: selectedRef.current } as RefObject<HTMLElement>,
{ current: scrollRef.current } as RefObject<HTMLElement>,
topOffset,
);
});
}
}, [doFollow, selectedEvenId, topOffset]);

return {
selectedRef,
scrollRef,
};
}
1 change: 0 additions & 1 deletion apps/client/src/common/hooks/useSocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ const createSelector =
export const setClientRemote = {
setIdentify: (payload: { target: string; identify: boolean }) => sendSocket('client', payload),
setRedirect: (payload: { target: string; redirect: string }) => {
console.log('--- got', payload);
sendSocket('client', payload);
},
setClientName: (payload: { target: string; rename: string }) => sendSocket('client', payload),
Expand Down
19 changes: 0 additions & 19 deletions apps/client/src/common/models/View.types.ts

This file was deleted.

3 changes: 2 additions & 1 deletion apps/client/src/features/operator/Operator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export default function Operator() {
scrollRef,
doFollow: !lockAutoScroll,
topOffset: selectedOffset,
followTrigger: selectedEventId,
});

useWindowTitle('Operator');
Expand Down Expand Up @@ -181,7 +182,7 @@ export default function Operator() {
const { isPast, isSelected, isLinkedToLoaded, totalGap } = process(nestedEntry);

// hide past events (if setting) and skipped events
if (hidePast && isPast) {
if ((hidePast && isPast) || nestedEntry.skip) {
return null;
}

Expand Down
9 changes: 7 additions & 2 deletions apps/client/src/features/rundown/Rundown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,12 @@ export default function Rundown({ data, rundownMetadata }: RundownProps) {

const cursorRef = useRef<HTMLDivElement | null>(null);
const scrollRef = useRef<HTMLDivElement | null>(null);
useFollowComponent({ followRef: cursorRef, scrollRef, doFollow: editorMode === AppMode.Run });
useFollowComponent({
followRef: cursorRef,
scrollRef,
doFollow: true,
followTrigger: editorMode === AppMode.Edit ? cursor : featureData?.selectedEventId,
});

// DND KIT
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 10 } }));
Expand Down Expand Up @@ -312,7 +317,7 @@ export default function Rundown({ data, rundownMetadata }: RundownProps) {
setMetadata(rundownMetadata);
}, [order, entries, rundownMetadata]);

// in run mode, we follow selection
// in run mode, we follow the playback selection and open groups as needed
useEffect(() => {
if (editorMode !== AppMode.Run || !featureData?.selectedEventId) {
return;
Expand Down
12 changes: 7 additions & 5 deletions apps/client/src/features/rundown/RundownExport.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,22 @@
padding-inline: 0;
box-shadow: $box-shadow-right;

flex: 1 2 auto; /* flex-grow: 1, flex-shrink: 2, flex-basis: auto */
flex: 1 1 0; /* flex-grow: 1, flex-shrink: 1, flex-basis: 0 */
min-width: 38rem;
max-width: 60rem;
max-width: none;
width: 0;
}

.side {
max-height: 100%;
max-width: 45rem;
margin: 0.5rem 0;
padding: 1rem;
padding-right: 0;
background-color: $gray-1325;
border-radius: 0 8px 8px 0;

flex: 1 1 auto; /* flex-grow: 1, flex-shrink: 1, flex-basis: auto */
max-width: 45rem;
flex: 1 1 0; /* flex-grow: 1, flex-shrink: 1, flex-basis: 0 */
// width is locked to swatch picker elements
min-width: calc(15 * 2rem + 13 * 0.5rem);
width: 0;
}
4 changes: 2 additions & 2 deletions apps/client/src/features/rundown/rundown.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ export function canDrop(
order?: 'after' | 'before',
isTargetCollapsed?: boolean,
): boolean {
// this would mean inserting a group inside another
// inserting before would mean adding a group inside another
if (targetType === 'end-group') {
return false;
return order === 'after';
}

// this means swapping places with another group
Expand Down
8 changes: 5 additions & 3 deletions apps/client/src/views/countdown/Countdown.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useMemo, useState } from 'react';
import { IoAdd } from 'react-icons/io5';
import { EntryId, isOntimeEvent, isPlayableEvent, OntimeEvent, OntimeView } from 'ontime-types';
import { isOntimeEvent, isPlayableEvent, OntimeEvent, OntimeView } from 'ontime-types';

import Button from '../../common/components/buttons/Button';
import Empty from '../../common/components/state/Empty';
Expand All @@ -16,7 +16,7 @@ import { useTranslation } from '../../translation/TranslationProvider';
import Loader from '../common/loader/Loader';

import { getCountdownOptions, useCountdownOptions } from './countdown.options';
import { getOrderedSubscriptions } from './countdown.utils';
import { CountdownSubscription, getOrderedSubscriptions } from './countdown.utils';
import CountdownSelect from './CountdownSelect';
import CountdownSubscriptions from './CountdownSubscriptions';
import SingleEventCountdown from './SingleEventCountdown';
Expand Down Expand Up @@ -59,6 +59,8 @@ function Countdown({ customFields, rundownData, projectData, isMirrored, setting
[defaultFormat, customFields, subscriptions],
);

console.log(subscriptions)

return (
<div className={`countdown ${isMirrored ? 'mirror' : ''}`} data-testid='countdown-view'>
<ViewParamsEditor target={OntimeView.Countdown} viewOptions={countdownOptions} />
Expand Down Expand Up @@ -87,7 +89,7 @@ function Countdown({ customFields, rundownData, projectData, isMirrored, setting

interface CountdownContentsProps {
playableEvents: ExtendedEntry<OntimeEvent>[];
subscriptions: EntryId[];
subscriptions: CountdownSubscription;
goToEditMode: () => void;
}

Expand Down
25 changes: 21 additions & 4 deletions apps/client/src/views/countdown/CountdownSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import { useState } from 'react';

Check failure on line 1 in apps/client/src/views/countdown/CountdownSelect.tsx

View workflow job for this annotation

GitHub Actions / unit-test

Run autofix to sort these imports!
import { IoArrowBack, IoClose, IoSaveOutline } from 'react-icons/io5';
import { IoArrowBack, IoClose, IoSaveOutline, IoAlbumsOutline } from 'react-icons/io5';
import { useNavigate } from 'react-router';
import { EntryId, OntimeEvent } from 'ontime-types';

import Button from '../../common/components/buttons/Button';
import { cx } from '../../common/utils/styleUtils';
import ClockTime from '../../features/viewers/common/clock-time/ClockTime';

import { makeSubscriptionsUrl } from './countdown.utils';
import { CountdownSubscription, makeSubscriptionsUrl } from './countdown.utils';

import './Countdown.scss';

interface CountdownSelectProps {
events: OntimeEvent[];
subscriptions: EntryId[];
subscriptions: CountdownSubscription;
disableEdit: () => void;
}

export default function CountdownSelect({ events, subscriptions, disableEdit }: CountdownSelectProps) {
const [selected, setSelected] = useState<EntryId[]>(subscriptions);
const maybeAllSubscriptions: EntryId[] = subscriptions === 'all' ? events.map((event) => event.id) : subscriptions;
const [selected, setSelected] = useState<EntryId[]>(maybeAllSubscriptions);
const navigate = useNavigate();

/**
Expand Down Expand Up @@ -47,6 +48,18 @@
navigate(url.search.toString());
};

/**
* Creates a URL with all
* and navigates to it
*/
const applyAll = () => {
// we remove events that no longer exist to avoid stale subscriptions
const url = makeSubscriptionsUrl(window.location.href, 'all');
disableEdit();
setSelected([]);
navigate(url.search.toString());
};

// make a copy of the selected array for quick lookup
const selectedIds = new Set(selected);

Expand Down Expand Up @@ -86,6 +99,10 @@
<Button variant='subtle' size='xlarge' onClick={disableEdit}>
<IoArrowBack /> Go back
</Button>
<Button variant='subtle' size='xlarge' onClick={applyAll}>
{/* TODO: icon ??? */}
<IoAlbumsOutline /> Use All
</Button>
<Button variant='subtle' size='xlarge' onClick={() => setSelected([])} disabled={selected.length === 0}>
<IoClose /> Clear
</Button>
Expand Down
1 change: 1 addition & 0 deletions apps/client/src/views/countdown/CountdownSubscriptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export default function CountdownSubscriptions({ subscribedEvents, goToEditMode
scrollRef,
doFollow: !lockAutoScroll,
topOffset: 0,
followTrigger: selectedEventId,
});

// reset scroll if nothing is selected
Expand Down
Loading
Loading