mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-11 18:33:53 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fa7ec623f1 | |||
| bfb9b51073 | |||
| 8bc3f5a56c | |||
| acf1afb5e9 |
@@ -39,6 +39,7 @@ dist/
|
|||||||
# docker utils
|
# docker utils
|
||||||
ontime-db
|
ontime-db
|
||||||
ontime-external/
|
ontime-external/
|
||||||
|
ontime-data/
|
||||||
|
|
||||||
# versioning file
|
# versioning file
|
||||||
**/ONTIME_VERSION.js
|
**/ONTIME_VERSION.js
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@getontime/cli",
|
"name": "@getontime/cli",
|
||||||
"version": "3.9.2",
|
"version": "3.9.4",
|
||||||
"author": "Carlos Valente",
|
"author": "Carlos Valente",
|
||||||
"description": "Time keeping for live events",
|
"description": "Time keeping for live events",
|
||||||
"repository": "https://github.com/cpvalente/ontime",
|
"repository": "https://github.com/cpvalente/ontime",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ontime-ui",
|
"name": "ontime-ui",
|
||||||
"version": "3.9.2",
|
"version": "3.9.4",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"build:local": "cross-env NODE_ENV=local vite build",
|
"build:local": "cross-env NODE_ENV=local vite build",
|
||||||
"build:electron": "cross-env NODE_ENV=local vite build",
|
"build:electron": "cross-env NODE_ENV=local vite build",
|
||||||
"build:docker": "cross-env VITE_IS_CLOUD=true vite build",
|
"build:docker": "cross-env VITE_IS_DOCKER=true vite build",
|
||||||
"build:localdocker": "cross-env NODE_ENV=local vite build",
|
"build:localdocker": "cross-env NODE_ENV=local vite build",
|
||||||
"lint": "eslint . --quiet",
|
"lint": "eslint . --quiet",
|
||||||
"test": "vitest",
|
"test": "vitest",
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { IoExpand } from '@react-icons/all-files/io5/IoExpand';
|
|||||||
import { IoLockClosedOutline } from '@react-icons/all-files/io5/IoLockClosedOutline';
|
import { IoLockClosedOutline } from '@react-icons/all-files/io5/IoLockClosedOutline';
|
||||||
import { IoSwapVertical } from '@react-icons/all-files/io5/IoSwapVertical';
|
import { IoSwapVertical } from '@react-icons/all-files/io5/IoSwapVertical';
|
||||||
|
|
||||||
import { isLocalhost, serverPort } from '../../../externals';
|
import { isLocalhost } from '../../../externals';
|
||||||
import { navigatorConstants } from '../../../viewerConfig';
|
import { navigatorConstants } from '../../../viewerConfig';
|
||||||
import useClickOutside from '../../hooks/useClickOutside';
|
import useClickOutside from '../../hooks/useClickOutside';
|
||||||
import { useElectronEvent } from '../../hooks/useElectronEvent';
|
import { useElectronEvent } from '../../hooks/useElectronEvent';
|
||||||
@@ -25,7 +25,7 @@ import useInfo from '../../hooks-query/useInfo';
|
|||||||
import { useClientStore } from '../../stores/clientStore';
|
import { useClientStore } from '../../stores/clientStore';
|
||||||
import { useViewOptionsStore } from '../../stores/viewOptions';
|
import { useViewOptionsStore } from '../../stores/viewOptions';
|
||||||
import { isKeyEnter } from '../../utils/keyEvent';
|
import { isKeyEnter } from '../../utils/keyEvent';
|
||||||
import { handleLinks, openLink } from '../../utils/linkUtils';
|
import { handleLinks, linkToOtherHost, openLink } from '../../utils/linkUtils';
|
||||||
import { cx } from '../../utils/styleUtils';
|
import { cx } from '../../utils/styleUtils';
|
||||||
import { RenameClientModal } from '../client-modal/RenameClientModal';
|
import { RenameClientModal } from '../client-modal/RenameClientModal';
|
||||||
import CopyTag from '../copy-tag/CopyTag';
|
import CopyTag from '../copy-tag/CopyTag';
|
||||||
@@ -154,7 +154,8 @@ function OtherAddresses(props: OtherAddressesProps) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const address = `http://${nif.address}:${serverPort}${currentLocation}`;
|
const address = linkToOtherHost(nif.address, currentLocation);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CopyTag
|
<CopyTag
|
||||||
key={nif.name}
|
key={nif.name}
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
/**
|
|
||||||
* Returns hostname
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
export const host = window?.location?.host;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open an external URLs: specifically for a electron / browser case
|
|
||||||
* If electron: ask main process to call a new browser window
|
|
||||||
* If browser: open in new tab
|
|
||||||
* @param url
|
|
||||||
*/
|
|
||||||
export function openLink(url) {
|
|
||||||
if (window.process?.type === 'renderer') {
|
|
||||||
window.ipcRenderer.send('send-to-link', url);
|
|
||||||
} else {
|
|
||||||
window.open(url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles opening external links
|
|
||||||
* @param event
|
|
||||||
* @param location
|
|
||||||
*/
|
|
||||||
export function handleLinks(event, location) {
|
|
||||||
// we handle the link manually
|
|
||||||
event.preventDefault();
|
|
||||||
openLink(`http://${host}/${location}`);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import type { MouseEvent } from 'react';
|
||||||
|
|
||||||
|
import { baseURI, serverURL } from '../../externals';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open an external URLs: specifically for a electron / browser case
|
||||||
|
* If electron: ask main process to call a new browser window
|
||||||
|
* If browser: open in new tab
|
||||||
|
* @param url
|
||||||
|
*/
|
||||||
|
export function openLink(url: string) {
|
||||||
|
if (window.process?.type === 'renderer') {
|
||||||
|
window.ipcRenderer.send('send-to-link', url);
|
||||||
|
} else {
|
||||||
|
window.open(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles opening external links
|
||||||
|
* @param event
|
||||||
|
* @param location
|
||||||
|
*/
|
||||||
|
export function handleLinks(event: MouseEvent, location: string) {
|
||||||
|
// we handle the link manually
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const destination = new URL(serverURL);
|
||||||
|
destination.pathname = baseURI ? `${baseURI}/${location}` : location;
|
||||||
|
openLink(destination.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
export function linkToOtherHost(host: string, path?: string) {
|
||||||
|
const destination = new URL(serverURL);
|
||||||
|
destination.hostname = host;
|
||||||
|
if (path) {
|
||||||
|
destination.pathname = baseURI ? `${baseURI}/${path}` : path;
|
||||||
|
}
|
||||||
|
return destination.toString();
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
import { version } from '../../../package.json';
|
|
||||||
/**
|
/**
|
||||||
* This file contains a list of constants that may need to be resolved at runtime
|
* This file contains a list of constants that may need to be resolved at runtime
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { version } from '../../../package.json';
|
||||||
|
|
||||||
export const githubUrl = 'https://www.github.com/cpvalente/ontime';
|
export const githubUrl = 'https://www.github.com/cpvalente/ontime';
|
||||||
export const apiRepoLatest = 'https://api.github.com/repos/cpvalente/ontime/releases/latest';
|
export const apiRepoLatest = 'https://api.github.com/repos/cpvalente/ontime/releases/latest';
|
||||||
export const websiteUrl = 'https://www.getontime.no';
|
export const websiteUrl = 'https://www.getontime.no';
|
||||||
@@ -16,31 +17,59 @@ export const appVersion = version;
|
|||||||
export const isProduction = import.meta.env.MODE === 'production';
|
export const isProduction = import.meta.env.MODE === 'production';
|
||||||
export const isDev = !isProduction;
|
export const isDev = !isProduction;
|
||||||
export const isLocalhost = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';
|
export const isLocalhost = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';
|
||||||
export const isOntimeCloud = Boolean(import.meta.env.VITE_IS_CLOUD);
|
export const isDockerImage = Boolean(import.meta.env.VITE_IS_DOCKER);
|
||||||
|
export const isOntimeCloud = window.location.hostname.includes('cloud.getontime.no');
|
||||||
|
|
||||||
// resolve protocol
|
// resolve entrypoint URLs
|
||||||
const socketProtocol = window.location.protocol === 'https:' ? 'wss' : 'ws';
|
|
||||||
|
|
||||||
// resolve port
|
/**
|
||||||
const STATIC_PORT = 4001; // this is used as a fallback port for development
|
* Resolve base
|
||||||
export const serverPort = isProduction ? window.location.port : STATIC_PORT;
|
* @example '' for electron
|
||||||
|
* @example '/client-hash' for cloud
|
||||||
|
*/
|
||||||
export const baseURI = resolveBaseURI();
|
export const baseURI = resolveBaseURI();
|
||||||
export const serverURL = `${window.location.protocol}//${window.location.hostname}:${serverPort}${baseURI}`;
|
export const serverURL = resolveUrl('http', '');
|
||||||
export const websocketUrl = `${socketProtocol}://${window.location.hostname}:${serverPort}${baseURI}/ws`;
|
export const websocketUrl = resolveUrl('ws', 'ws');
|
||||||
|
|
||||||
|
function resolveUrl(protocol: 'http' | 'ws', path: string) {
|
||||||
|
const url = new URL(window.location.origin);
|
||||||
|
|
||||||
|
// generate ws url
|
||||||
|
if (protocol === 'ws') {
|
||||||
|
// ensure we remain in a secure context
|
||||||
|
const isSecure = window.location.protocol === 'https:';
|
||||||
|
url.protocol = isSecure ? 'wss' : 'ws';
|
||||||
|
}
|
||||||
|
|
||||||
|
// make path name relative to the base URI
|
||||||
|
url.pathname = baseURI ? `${baseURI}/${path}` : path;
|
||||||
|
|
||||||
|
// in development mode, we use the React port for UI, but need the requests to target the server
|
||||||
|
if (isDev) {
|
||||||
|
// this is used as a fallback port for development
|
||||||
|
url.port = '4001';
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = url.toString();
|
||||||
|
|
||||||
|
// prevent trailing slash
|
||||||
|
return result.endsWith('/') ? result.slice(0, -1) : result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves a base URI for a client that is not at the root segment
|
* Resolves a base URI for a client that is not at the root segment
|
||||||
* ie: https://cloud.getontime.com/client-hash/timer
|
* ie: https://cloud.getontime.com/client-hash/timer
|
||||||
* This is necessary for ontime cloud and should otherwise not affect the client
|
* This is necessary for ontime cloud and should otherwise not affect the client
|
||||||
*/
|
*/
|
||||||
function resolveBaseURI() {
|
function resolveBaseURI(): string {
|
||||||
if (!isOntimeCloud) {
|
// in ontime cloud, the base tag is set by the server
|
||||||
return '';
|
const baseHref = document.querySelector('base')?.getAttribute('href');
|
||||||
}
|
const base = baseHref ?? '';
|
||||||
const [_, base, location] = window.location.pathname.split('/');
|
|
||||||
if (!location) {
|
// prevent a trailing slash from either an empty base or a base with a trailing slash
|
||||||
return '';
|
if (base.endsWith('/')) {
|
||||||
|
return base.slice(0, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return `/${base}`;
|
return base;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { IoArrowUp } from '@react-icons/all-files/io5/IoArrowUp';
|
|||||||
|
|
||||||
import CopyTag from '../../../../common/components/copy-tag/CopyTag';
|
import CopyTag from '../../../../common/components/copy-tag/CopyTag';
|
||||||
import useInfo from '../../../../common/hooks-query/useInfo';
|
import useInfo from '../../../../common/hooks-query/useInfo';
|
||||||
import { openLink } from '../../../../common/utils/linkUtils';
|
import { linkToOtherHost, openLink } from '../../../../common/utils/linkUtils';
|
||||||
import { isLocalhost, serverPort } from '../../../../externals';
|
import { isLocalhost } from '../../../../externals';
|
||||||
|
|
||||||
import style from './NetworkInterfaces.module.scss';
|
import style from './NetworkInterfaces.module.scss';
|
||||||
|
|
||||||
@@ -14,11 +14,11 @@ export default function InfoNif() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.interfaces}>
|
<div className={style.interfaces}>
|
||||||
{data.networkInterfaces?.map((nif) => {
|
{data.networkInterfaces.map((nif) => {
|
||||||
// interfaces outside localhost wont have access
|
// interfaces outside localhost wont have access
|
||||||
if (nif.name === 'localhost' && !isLocalhost) return null;
|
if (nif.name === 'localhost' && !isLocalhost) return null;
|
||||||
|
const address = linkToOtherHost(nif.address);
|
||||||
|
|
||||||
const address = `http://${nif.address}:${serverPort}`;
|
|
||||||
return (
|
return (
|
||||||
<CopyTag
|
<CopyTag
|
||||||
key={nif.name}
|
key={nif.name}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useEffect } from 'react';
|
|||||||
import useScrollIntoView from '../../../../common/hooks/useScrollIntoView';
|
import useScrollIntoView from '../../../../common/hooks/useScrollIntoView';
|
||||||
import { usePing } from '../../../../common/hooks/useSocket';
|
import { usePing } from '../../../../common/hooks/useSocket';
|
||||||
import { socketSendJson } from '../../../../common/utils/socket';
|
import { socketSendJson } from '../../../../common/utils/socket';
|
||||||
import { isOntimeCloud } from '../../../../externals';
|
import { isDockerImage } from '../../../../externals';
|
||||||
import type { PanelBaseProps } from '../../panel-list/PanelList';
|
import type { PanelBaseProps } from '../../panel-list/PanelList';
|
||||||
import * as Panel from '../../panel-utils/PanelUtils';
|
import * as Panel from '../../panel-utils/PanelUtils';
|
||||||
import ClientControlPanel from '../client-control-panel/ClientControlPanel';
|
import ClientControlPanel from '../client-control-panel/ClientControlPanel';
|
||||||
@@ -19,7 +19,7 @@ export default function NetworkLogPanel({ location }: PanelBaseProps) {
|
|||||||
<>
|
<>
|
||||||
<Panel.Header>Network</Panel.Header>
|
<Panel.Header>Network</Panel.Header>
|
||||||
<Panel.Section>
|
<Panel.Section>
|
||||||
{isOntimeCloud && <OntimeCloudStats />}
|
{isDockerImage && <OntimeCloudStats />}
|
||||||
<Panel.Paragraph>Ontime is streaming on the following network interfaces</Panel.Paragraph>
|
<Panel.Paragraph>Ontime is streaming on the following network interfaces</Panel.Paragraph>
|
||||||
</Panel.Section>
|
</Panel.Section>
|
||||||
<InfoNif />
|
<InfoNif />
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { useQueryClient } from '@tanstack/react-query';
|
|||||||
import { PROJECT_LIST } from '../../../../common/api/constants';
|
import { PROJECT_LIST } from '../../../../common/api/constants';
|
||||||
import { createProject } from '../../../../common/api/db';
|
import { createProject } from '../../../../common/api/db';
|
||||||
import { maybeAxiosError } from '../../../../common/api/utils';
|
import { maybeAxiosError } from '../../../../common/api/utils';
|
||||||
|
import { documentationUrl, websiteUrl } from '../../../../externals';
|
||||||
import * as Panel from '../../panel-utils/PanelUtils';
|
import * as Panel from '../../panel-utils/PanelUtils';
|
||||||
|
|
||||||
import style from './ProjectPanel.module.scss';
|
import style from './ProjectPanel.module.scss';
|
||||||
@@ -118,7 +119,7 @@ export default function ProjectCreateForm(props: ProjectCreateFromProps) {
|
|||||||
<Input
|
<Input
|
||||||
variant='ontime-filled'
|
variant='ontime-filled'
|
||||||
size='sm'
|
size='sm'
|
||||||
placeholder='www.getontime.no'
|
placeholder={websiteUrl}
|
||||||
autoComplete='off'
|
autoComplete='off'
|
||||||
{...register('publicUrl')}
|
{...register('publicUrl')}
|
||||||
/>
|
/>
|
||||||
@@ -140,7 +141,7 @@ export default function ProjectCreateForm(props: ProjectCreateFromProps) {
|
|||||||
<Input
|
<Input
|
||||||
variant='ontime-filled'
|
variant='ontime-filled'
|
||||||
size='sm'
|
size='sm'
|
||||||
placeholder='http://docs.getontime.no'
|
placeholder={documentationUrl}
|
||||||
autoComplete='off'
|
autoComplete='off'
|
||||||
{...register('backstageUrl')}
|
{...register('backstageUrl')}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { postProjectData, uploadProjectLogo } from '../../../../common/api/proje
|
|||||||
import { maybeAxiosError } from '../../../../common/api/utils';
|
import { maybeAxiosError } from '../../../../common/api/utils';
|
||||||
import useProjectData from '../../../../common/hooks-query/useProjectData';
|
import useProjectData from '../../../../common/hooks-query/useProjectData';
|
||||||
import { validateLogo } from '../../../../common/utils/uploadUtils';
|
import { validateLogo } from '../../../../common/utils/uploadUtils';
|
||||||
|
import { documentationUrl, websiteUrl } from '../../../../externals';
|
||||||
import * as Panel from '../../panel-utils/PanelUtils';
|
import * as Panel from '../../panel-utils/PanelUtils';
|
||||||
|
|
||||||
import style from './ProjectPanel.module.scss';
|
import style from './ProjectPanel.module.scss';
|
||||||
@@ -203,7 +204,7 @@ export default function ProjectData() {
|
|||||||
<Input
|
<Input
|
||||||
variant='ontime-filled'
|
variant='ontime-filled'
|
||||||
size='sm'
|
size='sm'
|
||||||
placeholder='www.getontime.no'
|
placeholder={websiteUrl}
|
||||||
autoComplete='off'
|
autoComplete='off'
|
||||||
{...register('publicUrl')}
|
{...register('publicUrl')}
|
||||||
/>
|
/>
|
||||||
@@ -225,7 +226,7 @@ export default function ProjectData() {
|
|||||||
<Input
|
<Input
|
||||||
variant='ontime-filled'
|
variant='ontime-filled'
|
||||||
size='sm'
|
size='sm'
|
||||||
placeholder='http://docs.getontime.no'
|
placeholder={documentationUrl}
|
||||||
autoComplete='off'
|
autoComplete='off'
|
||||||
{...register('backstageUrl')}
|
{...register('backstageUrl')}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ $orange-active: #f60;
|
|||||||
grid-area: schedule;
|
grid-area: schedule;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
margin-right: 2vw;
|
margin-right: 2vw;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.onAir {
|
.onAir {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ontime",
|
"name": "ontime",
|
||||||
"version": "3.9.2",
|
"version": "3.9.4",
|
||||||
"author": "Carlos Valente",
|
"author": "Carlos Valente",
|
||||||
"description": "Time keeping for live events",
|
"description": "Time keeping for live events",
|
||||||
"repository": "https://github.com/cpvalente/ontime",
|
"repository": "https://github.com/cpvalente/ontime",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "ontime-server",
|
"name": "ontime-server",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"version": "3.9.2",
|
"version": "3.9.4",
|
||||||
"exports": "./src/index.js",
|
"exports": "./src/index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@googleapis/sheets": "^5.0.5",
|
"@googleapis/sheets": "^5.0.5",
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
import { cleanURL } from '../url.js';
|
|
||||||
|
|
||||||
describe('url is correctly formatted', () => {
|
|
||||||
it('has no leading spaces', () => {
|
|
||||||
const test = ' http://testing';
|
|
||||||
const expected = 'http://testing';
|
|
||||||
expect(cleanURL(test)).toBe(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('has no trailing spaces', () => {
|
|
||||||
const test = 'http://testing ';
|
|
||||||
const expected = 'http://testing';
|
|
||||||
expect(cleanURL(test)).toBe(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('doesnt contain spaces', () => {
|
|
||||||
const test = 'http://t e s t i n g';
|
|
||||||
const expected = 'http://t%20e%20s%20t%20i%20n%20g';
|
|
||||||
expect(cleanURL(test)).toBe(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('only contains allowed characters', () => {
|
|
||||||
const test = 'http://<>[]{}|^';
|
|
||||||
const expected = 'http://';
|
|
||||||
expect(cleanURL(test)).toBe(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('begins with http://', () => {
|
|
||||||
const test = 'ontime.com';
|
|
||||||
const expected = 'http://ontime.com';
|
|
||||||
expect(cleanURL(test)).toBe(expected);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
/**
|
|
||||||
* @description Cleans given url
|
|
||||||
* @param {string} url - URL to be checked
|
|
||||||
* @returns {string} Sanitized url
|
|
||||||
*/
|
|
||||||
export const cleanURL = (url: string): string => {
|
|
||||||
// trim whitespaces
|
|
||||||
let sanitised = url.trim();
|
|
||||||
|
|
||||||
// clear any whitespaces
|
|
||||||
sanitised = sanitised.split(' ').join('%20');
|
|
||||||
|
|
||||||
// contain only allowed characters
|
|
||||||
sanitised = sanitised.replace(/([@\s<>[\]{}|\\^])+/g, '');
|
|
||||||
|
|
||||||
// starts with http://
|
|
||||||
if (!sanitised.startsWith('http://')) sanitised = `http://${sanitised}`;
|
|
||||||
|
|
||||||
return sanitised;
|
|
||||||
};
|
|
||||||
@@ -4,6 +4,10 @@ const fileToUpload = 'e2e/tests/fixtures/test-db.json';
|
|||||||
|
|
||||||
test('project file upload', async ({ page }) => {
|
test('project file upload', async ({ page }) => {
|
||||||
await page.goto('http://localhost:4001/editor');
|
await page.goto('http://localhost:4001/editor');
|
||||||
|
|
||||||
|
// close the welcome modal if it is open
|
||||||
|
await page.keyboard.down('Escape');
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Edit' }).click();
|
await page.getByRole('button', { name: 'Edit' }).click();
|
||||||
await page.getByRole('button', { name: 'Clear rundown' }).click();
|
await page.getByRole('button', { name: 'Clear rundown' }).click();
|
||||||
await page.getByRole('button', { name: 'Delete all' }).click();
|
await page.getByRole('button', { name: 'Delete all' }).click();
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ontime",
|
"name": "ontime",
|
||||||
"version": "3.9.2",
|
"version": "3.9.4",
|
||||||
"description": "Time keeping for live events",
|
"description": "Time keeping for live events",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"ontime",
|
"ontime",
|
||||||
|
|||||||
Reference in New Issue
Block a user