feat: small improvements to instance info (#591)

* refactor: add typings to backend info

* refactor: write current version to project file

* feat: show location of css override
This commit is contained in:
Carlos Valente
2023-11-15 20:20:05 +01:00
committed by GitHub
parent 536e447eaa
commit 54def8b820
19 changed files with 105 additions and 58 deletions
+2 -2
View File
@@ -2,6 +2,7 @@ import axios, { AxiosResponse } from 'axios';
import { import {
Alias, Alias,
DatabaseModel, DatabaseModel,
GetInfo,
OntimeRundown, OntimeRundown,
OSCSettings, OSCSettings,
OscSubscription, OscSubscription,
@@ -13,7 +14,6 @@ import {
import { ExcelImportMap } from 'ontime-utils'; import { ExcelImportMap } from 'ontime-utils';
import { apiRepoLatest } from '../../externals'; import { apiRepoLatest } from '../../externals';
import { InfoType } from '../models/Info';
import fileDownload from '../utils/fileDownload'; import fileDownload from '../utils/fileDownload';
import { ontimeURL } from './apiConstants'; import { ontimeURL } from './apiConstants';
@@ -39,7 +39,7 @@ export async function postSettings(data: Settings) {
* @description HTTP request to retrieve application info * @description HTTP request to retrieve application info
* @return {Promise} * @return {Promise}
*/ */
export async function getInfo(): Promise<InfoType> { export async function getInfo(): Promise<GetInfo> {
const res = await axios.get(`${ontimeURL}/info`); const res = await axios.get(`${ontimeURL}/info`);
return res.data; return res.data;
} }
@@ -1,4 +1,5 @@
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { GetInfo } from 'ontime-types';
import { queryRefetchIntervalSlow } from '../../ontimeConfig'; import { queryRefetchIntervalSlow } from '../../ontimeConfig';
import { APP_INFO } from '../api/apiConstants'; import { APP_INFO } from '../api/apiConstants';
@@ -6,7 +7,7 @@ import { getInfo } from '../api/ontimeApi';
import { ontimePlaceholderInfo } from '../models/Info'; import { ontimePlaceholderInfo } from '../models/Info';
export default function useInfo() { export default function useInfo() {
const { data, status, isError, refetch } = useQuery({ const { data, status, isError, refetch, isFetching } = useQuery<GetInfo>({
queryKey: APP_INFO, queryKey: APP_INFO,
queryFn: getInfo, queryFn: getInfo,
placeholderData: ontimePlaceholderInfo, placeholderData: ontimePlaceholderInfo,
@@ -16,5 +17,5 @@ export default function useInfo() {
networkMode: 'always', networkMode: 'always',
}); });
return { data, status, isError, refetch }; return { data, status, isError, refetch, isFetching };
} }
+22 -16
View File
@@ -1,19 +1,25 @@
import { Settings } from 'ontime-types'; import { GetInfo, OSCSettings } from 'ontime-types';
type NetworkInterfaceType = { export const oscPlaceholderSettings: OSCSettings = {
name: string; portIn: 0,
address: string; portOut: 0,
}; targetIP: '',
enabledIn: false,
export type InfoType = { enabledOut: false,
networkInterfaces: NetworkInterfaceType[]; subscriptions: {
settings: Pick<Settings, 'version' | 'serverPort'>; onLoad: [],
}; onStart: [],
onPause: [],
export const ontimePlaceholderInfo: InfoType = { onStop: [],
networkInterfaces: [], onUpdate: [],
settings: { onFinish: [],
version: 2,
serverPort: 4001,
}, },
}; };
export const ontimePlaceholderInfo: GetInfo = {
networkInterfaces: [],
version: '2.0.0',
serverPort: 4001,
osc: oscPlaceholderSettings,
cssOverride: '',
};
@@ -2,7 +2,7 @@ import { Settings } from 'ontime-types';
export const ontimePlaceholderSettings: Settings = { export const ontimePlaceholderSettings: Settings = {
app: 'ontime', app: 'ontime',
version: 2, version: '2.0.0',
serverPort: 4001, serverPort: 4001,
editorKey: null, editorKey: null,
operatorKey: null, operatorKey: null,
@@ -3,19 +3,24 @@
.aliases { .aliases {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 0.5rem;
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
padding: 8px 0; padding: 0.5rem 0;
.aliasRow { .aliasRow {
width: 100%; width: 100%;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 0.5rem;
} }
.grow { .grow {
flex: 1; flex: 1;
} }
} }
.url {
font-size: calc(1rem - 2px);
user-select: text;
}
@@ -1,16 +1,18 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { Input, Switch } from '@chakra-ui/react'; import { Alert, AlertDescription, AlertIcon, AlertTitle, Input, Switch } from '@chakra-ui/react';
import { ViewSettings } from 'ontime-types'; import { ViewSettings } from 'ontime-types';
import { logAxiosError } from '../../../common/api/apiUtils'; import { logAxiosError } from '../../../common/api/apiUtils';
import { postViewSettings } from '../../../common/api/ontimeApi'; import { postViewSettings } from '../../../common/api/ontimeApi';
import { PopoverPickerRHF } from '../../../common/components/input/popover-picker/PopoverPicker'; import { PopoverPickerRHF } from '../../../common/components/input/popover-picker/PopoverPicker';
import useInfo from '../../../common/hooks-query/useInfo';
import useViewSettings from '../../../common/hooks-query/useViewSettings'; import useViewSettings from '../../../common/hooks-query/useViewSettings';
import { mtm } from '../../../common/utils/timeConstants'; import { mtm } from '../../../common/utils/timeConstants';
import ModalLoader from '../modal-loader/ModalLoader'; import ModalLoader from '../modal-loader/ModalLoader';
import { inputProps } from '../modalHelper'; import { inputProps } from '../modalHelper';
import ModalInput from '../ModalInput'; import ModalInput from '../ModalInput';
import ModalLink from '../ModalLink';
import ModalSplitInput from '../ModalSplitInput'; import ModalSplitInput from '../ModalSplitInput';
import OntimeModalFooter from '../OntimeModalFooter'; import OntimeModalFooter from '../OntimeModalFooter';
@@ -18,8 +20,12 @@ import InputMillisWithString from './InputMillisWithString';
import style from './SettingsModal.module.scss'; import style from './SettingsModal.module.scss';
const cssOverrideDocsUrl = 'https://ontime.gitbook.io/v2/features/custom-styling';
export default function ViewSettingsForm() { export default function ViewSettingsForm() {
const { data, status, refetch, isFetching } = useViewSettings(); const { data, status, refetch, isFetching } = useViewSettings();
const { data: info, isFetching: isFetchingInfo } = useInfo();
const { const {
control, control,
handleSubmit, handleSubmit,
@@ -75,13 +81,24 @@ export default function ViewSettingsForm() {
const disableInputs = status === 'loading'; const disableInputs = status === 'loading';
if (isFetching) { if (isFetching || isFetchingInfo) {
return <ModalLoader />; return <ModalLoader />;
} }
return ( return (
<form onSubmit={handleSubmit(onSubmit)} id='view-settings' className={style.sectionContainer}> <form onSubmit={handleSubmit(onSubmit)} id='view-settings' className={style.sectionContainer}>
<span className={style.title}>General view settings</span> <span className={style.title}>General view settings</span>
<Alert status='info' variant='ontime-on-light-info'>
<AlertIcon />
<div className={style.column}>
<AlertTitle>CSS Override</AlertTitle>
<AlertDescription>
Ontime will use the CSS file at its install location. <br />
<span className={style.url}>{info.cssOverride}</span>
<ModalLink href={cssOverrideDocsUrl}>For more information, see the docs</ModalLink>
</AlertDescription>
</div>
</Alert>
<ModalSplitInput <ModalSplitInput
field='overrideStyles' field='overrideStyles'
title='Override CSS Styles' title='Override CSS Styles'
@@ -11,7 +11,7 @@ describe('safeMerge', () => {
}, },
settings: { settings: {
app: 'ontime', app: 'ontime',
version: 2, version: '2.0.0',
serverPort: 4001, serverPort: 4001,
editorKey: null, editorKey: null,
operatorKey: null, operatorKey: null,
@@ -84,7 +84,7 @@ describe('safeMerge', () => {
const mergedData = safeMerge(existing, newData); const mergedData = safeMerge(existing, newData);
expect(mergedData.settings).toEqual({ expect(mergedData.settings).toEqual({
app: 'ontime', app: 'ontime',
version: 2, version: '2.0.0',
serverPort: 3000, serverPort: 3000,
operatorKey: null, operatorKey: null,
editorKey: null, editorKey: null,
@@ -144,7 +144,7 @@ describe('safeMerge', () => {
}, },
settings: { settings: {
app: 'ontime', app: 'ontime',
version: 2, version: '2.0.0',
serverPort: 4001, serverPort: 4001,
operatorKey: null, operatorKey: null,
editorKey: null, editorKey: null,
@@ -1,6 +1,6 @@
import { Alias, DatabaseModel, LogOrigin, ProjectData } from 'ontime-types'; import { Alias, DatabaseModel, GetInfo, LogOrigin, ProjectData } from 'ontime-types';
import { RequestHandler } from 'express'; import { RequestHandler, Request, Response } from 'express';
import fs from 'fs'; import fs from 'fs';
import { networkInterfaces } from 'os'; import { networkInterfaces } from 'os';
@@ -9,7 +9,7 @@ import { DataProvider } from '../classes/data-provider/DataProvider.js';
import { failEmptyObjects, failIsNotArray } from '../utils/routerUtils.js'; import { failEmptyObjects, failIsNotArray } from '../utils/routerUtils.js';
import { PlaybackService } from '../services/PlaybackService.js'; import { PlaybackService } from '../services/PlaybackService.js';
import { eventStore } from '../stores/EventStore.js'; import { eventStore } from '../stores/EventStore.js';
import { isDocker, resolveDbPath } from '../setup.js'; import { isDocker, pathToStartStyles, resolveDbPath } from '../setup.js';
import { oscIntegration } from '../services/integration-service/OscIntegration.js'; import { oscIntegration } from '../services/integration-service/OscIntegration.js';
import { logger } from '../classes/Logger.js'; import { logger } from '../classes/Logger.js';
import { deleteAllEvents, notifyChanges } from '../services/rundown-service/RundownService.js'; import { deleteAllEvents, notifyChanges } from '../services/rundown-service/RundownService.js';
@@ -105,15 +105,16 @@ const getNetworkInterfaces = () => {
return results; return results;
}; };
// Create controller for POST request to '/ontime/info' // Create controller for GET request to '/ontime/info'
// Returns - // Returns -
export const getInfo = async (req, res) => { export const getInfo = async (req: Request, res: Response<GetInfo>) => {
const { version, serverPort } = DataProvider.getSettings(); const { version, serverPort } = DataProvider.getSettings();
const osc = DataProvider.getOsc(); const osc = DataProvider.getOsc();
// get nif and inject localhost // get nif and inject localhost
const ni = getNetworkInterfaces(); const ni = getNetworkInterfaces();
ni.unshift({ name: 'localhost', address: '127.0.0.1' }); ni.unshift({ name: 'localhost', address: '127.0.0.1' });
const cssOverride = pathToStartStyles;
// send object with network information // send object with network information
res.status(200).send({ res.status(200).send({
@@ -121,6 +122,7 @@ export const getInfo = async (req, res) => {
version, version,
serverPort, serverPort,
osc, osc,
cssOverride,
}); });
}; };
+2 -1
View File
@@ -1,4 +1,5 @@
import { DatabaseModel } from 'ontime-types'; import { DatabaseModel } from 'ontime-types';
import { ONTIME_VERSION } from '../ONTIME_VERSION.js';
export const dbModel: DatabaseModel = { export const dbModel: DatabaseModel = {
rundown: [], rundown: [],
@@ -12,7 +13,7 @@ export const dbModel: DatabaseModel = {
}, },
settings: { settings: {
app: 'ontime', app: 'ontime',
version: 2, version: ONTIME_VERSION,
serverPort: 4001, serverPort: 4001,
editorKey: null, editorKey: null,
operatorKey: null, operatorKey: null,
+13 -13
View File
@@ -201,7 +201,7 @@ describe('test json parser with valid def', () => {
}, },
settings: { settings: {
app: 'ontime', app: 'ontime',
version: 2, version: '2.0.0',
timeFormat: '24', timeFormat: '24',
}, },
viewSettings: {}, viewSettings: {},
@@ -260,7 +260,7 @@ describe('test json parser with valid def', () => {
it('settings are for right app and version', () => { it('settings are for right app and version', () => {
const settings = parseResponse?.settings; const settings = parseResponse?.settings;
expect(settings.app).toBe('ontime'); expect(settings.app).toBe('ontime');
expect(settings.version).toBe(2); expect(settings.version).toEqual(expect.any(String));
}); });
it('missing settings', () => { it('missing settings', () => {
@@ -387,7 +387,7 @@ describe('test corrupt data', () => {
}, },
settings: { settings: {
app: 'ontime', app: 'ontime',
version: 2, version: '2.0.0',
serverPort: 4001, serverPort: 4001,
lock: null, lock: null,
timeFormat: '24', timeFormat: '24',
@@ -410,7 +410,7 @@ describe('test corrupt data', () => {
}, },
settings: { settings: {
app: 'ontime', app: 'ontime',
version: 2, version: '2.0.0',
serverPort: 4001, serverPort: 4001,
lock: null, lock: null,
timeFormat: '24', timeFormat: '24',
@@ -427,7 +427,7 @@ describe('test corrupt data', () => {
project: {}, project: {},
settings: { settings: {
app: 'ontime', app: 'ontime',
version: 2, version: '2.0.0',
serverPort: 4001, serverPort: 4001,
lock: null, lock: null,
timeFormat: '24', timeFormat: '24',
@@ -444,7 +444,7 @@ describe('test corrupt data', () => {
event: {}, event: {},
settings: { settings: {
app: 'ontime', app: 'ontime',
version: 2, version: '2.0.0',
}, },
}; };
@@ -734,7 +734,7 @@ describe('test aliases import', () => {
rundown: [], rundown: [],
settings: { settings: {
app: 'ontime', app: 'ontime',
version: 2, version: '2.0.0',
}, },
aliases: [ aliases: [
{ {
@@ -773,7 +773,7 @@ describe('test userFields import', () => {
rundown: [], rundown: [],
settings: { settings: {
app: 'ontime', app: 'ontime',
version: 2, version: '2.0.0',
}, },
userFields: testUserFields, userFields: testUserFields,
}; };
@@ -800,7 +800,7 @@ describe('test userFields import', () => {
rundown: [], rundown: [],
settings: { settings: {
app: 'ontime', app: 'ontime',
version: 2, version: '2.0.0',
}, },
userFields: testUserFields, userFields: testUserFields,
}; };
@@ -814,7 +814,7 @@ describe('test userFields import', () => {
rundown: [], rundown: [],
settings: { settings: {
app: 'ontime', app: 'ontime',
version: 2, version: '2.0.0',
}, },
}; };
@@ -828,7 +828,7 @@ describe('test userFields import', () => {
rundown: [], rundown: [],
settings: { settings: {
app: 'ontime', app: 'ontime',
version: 2, version: '2.0.0',
}, },
userFields: { userFields: {
notThis: 'this shouldng be accepted', notThis: 'this shouldng be accepted',
@@ -847,7 +847,7 @@ describe('test views import', () => {
rundown: [], rundown: [],
settings: { settings: {
app: 'ontime', app: 'ontime',
version: 2, version: '2.0.0',
}, },
viewSettings: { viewSettings: {
normalColor: '#ffffffcc', normalColor: '#ffffffcc',
@@ -881,7 +881,7 @@ describe('test views import', () => {
rundown: [], rundown: [],
settings: { settings: {
app: 'ontime', app: 'ontime',
version: 2, version: '2.0.0',
}, },
}; };
const parsed = parseViewSettings(testData); const parsed = parseViewSettings(testData);
+1 -4
View File
@@ -241,7 +241,7 @@ export const parseExcel = (excelData: unknown[][], options?: Partial<ExcelImport
project: projectData, project: projectData,
settings: { settings: {
app: 'ontime', app: 'ontime',
version: 2, version: '2.0.0',
}, },
userFields: customUserFields, userFields: customUserFields,
}; };
@@ -382,9 +382,6 @@ export const fileHandler = async (file: string, options: ExcelImportOptions): Pr
let uploadedJson = null; let uploadedJson = null;
uploadedJson = JSON.parse(rawdata); uploadedJson = JSON.parse(rawdata);
if (uploadedJson.settings.version !== 2) {
throw new Error(`Project version unknown ${uploadedJson.settings.version}`);
}
res.data = await parseJson(uploadedJson); res.data = await parseJson(uploadedJson);
// delete file // delete file
+1
View File
@@ -114,6 +114,7 @@ export const parseSettings = (data): Settings => {
console.log('ERROR: unknown app version, skipping'); console.log('ERROR: unknown app version, skipping');
} else { } else {
const settings = { const settings = {
version: dbModel.settings.version,
serverPort: s.serverPort || dbModel.settings.serverPort, serverPort: s.serverPort || dbModel.settings.serverPort,
editorKey: s.editorKey || null, editorKey: s.editorKey || null,
operatorKey: s.operatorKey || null, operatorKey: s.operatorKey || null,
+1 -1
View File
@@ -237,7 +237,7 @@
}, },
"settings": { "settings": {
"app": "ontime", "app": "ontime",
"version": 2, "version": "2.0.0",
"serverPort": 4001, "serverPort": 4001,
"editorKey": null, "editorKey": null,
"operatorKey": null, "operatorKey": null,
+1 -1
View File
@@ -99,7 +99,7 @@
}, },
"settings": { "settings": {
"app": "ontime", "app": "ontime",
"version": 2, "version": "2.0.0",
"serverPort": 4001, "serverPort": 4001,
"editorKey": null, "editorKey": null,
"operatorKey": null, "operatorKey": null,
+1 -1
View File
@@ -413,7 +413,7 @@
}, },
"settings": { "settings": {
"app": "ontime", "app": "ontime",
"version": 2, "version": "2.0.0",
"serverPort": 4001, "serverPort": 4001,
"editorKey": null, "editorKey": null,
"operatorKey": null, "operatorKey": null,
+1 -1
View File
@@ -103,7 +103,7 @@
}, },
"settings": { "settings": {
"app": "ontime", "app": "ontime",
"version": 2, "version": "2.0.0",
"serverPort": 4001, "serverPort": 4001,
"editorKey": null, "editorKey": null,
"operatorKey": null, "operatorKey": null,
@@ -0,0 +1,14 @@
import { OSCSettings } from '../../definitions/core/OscSettings.type.js';
export type NetworkInterface = {
name: string;
address: string;
};
export interface GetInfo {
networkInterfaces: NetworkInterface[];
version: string;
serverPort: number;
osc: OSCSettings;
cssOverride: string;
}
@@ -1,8 +1,8 @@
import { TimeFormat } from './TimeFormat.type'; import { TimeFormat } from './TimeFormat.type.js';
export type Settings = { export type Settings = {
app: 'ontime'; app: 'ontime';
version: 2; version: string;
serverPort: number; serverPort: number;
editorKey: null | string; editorKey: null | string;
operatorKey: null | string; operatorKey: null | string;
+3
View File
@@ -33,6 +33,9 @@ export type { OSCSettings, OscSubscription, OscSubscriptionOptions } from './def
// ---> HTTP // ---> HTTP
// SERVER RESPONSES
export type { NetworkInterface, GetInfo } from './api/ontime-controller/BackendResponse.type.js';
// SERVER RUNTIME // SERVER RUNTIME
export { type Log, LogLevel, type LogMessage, LogOrigin } from './definitions/runtime/Logger.type.js'; export { type Log, LogLevel, type LogMessage, LogOrigin } from './definitions/runtime/Logger.type.js';
export { Playback } from './definitions/runtime/Playback.type.js'; export { Playback } from './definitions/runtime/Playback.type.js';