mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-11 18:33:53 +00:00
refactor: organise API around resources (#798)
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
import axios from 'axios';
|
||||
import { Alias } from 'ontime-types';
|
||||
|
||||
import { apiEntryUrl } from './constants';
|
||||
|
||||
const aliasesPath = `${apiEntryUrl}/aliases`;
|
||||
|
||||
/**
|
||||
* HTTP request to retrieve aliases
|
||||
*/
|
||||
export async function getAliases(): Promise<Alias[]> {
|
||||
const res = await axios.get(aliasesPath);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request to mutate aliases
|
||||
*/
|
||||
export async function postAliases(data: Alias[]): Promise<Alias[]> {
|
||||
return axios.post(aliasesPath, data);
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
import axios, { AxiosError } from 'axios';
|
||||
import { LogLevel } from 'ontime-types';
|
||||
import { generateId, millisToString } from 'ontime-utils';
|
||||
|
||||
import { ontimeQueryClient } from '../queryClient';
|
||||
import { addLog } from '../stores/logger';
|
||||
import { nowInMillis } from '../utils/time';
|
||||
|
||||
export function maybeAxiosError(error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
const statusText = (error as AxiosError).response?.statusText ?? '';
|
||||
let data = (error as AxiosError).response?.data ?? '';
|
||||
if (typeof data === 'object') {
|
||||
if ('message' in data) {
|
||||
data = JSON.stringify(data.message);
|
||||
} else {
|
||||
data = JSON.stringify(data);
|
||||
}
|
||||
}
|
||||
return `${statusText}: ${data}`;
|
||||
} else {
|
||||
if (typeof error !== 'string') {
|
||||
return JSON.stringify(error);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
export function logAxiosError(prepend: string, error: unknown) {
|
||||
const message = `${prepend}: ${maybeAxiosError(error)}`;
|
||||
|
||||
addLog({
|
||||
id: generateId(),
|
||||
origin: 'SERVER',
|
||||
time: millisToString(nowInMillis()),
|
||||
level: LogLevel.Error,
|
||||
text: message,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function invalidates react-query caches
|
||||
*/
|
||||
export async function invalidateAllCaches() {
|
||||
await ontimeQueryClient.invalidateQueries();
|
||||
}
|
||||
+5
-1
@@ -1,4 +1,4 @@
|
||||
// REST stuff
|
||||
// keys in tanstack store
|
||||
export const ALIASES = ['aliases'];
|
||||
export const APP_INFO = ['appinfo'];
|
||||
export const APP_SETTINGS = ['appSettings'];
|
||||
@@ -12,16 +12,20 @@ export const SHEET_STATE = ['sheetState'];
|
||||
export const CUSTOM_FIELDS = ['customFields'];
|
||||
export const VIEW_SETTINGS = ['viewSettings'];
|
||||
|
||||
// resolve location
|
||||
const location = window.location;
|
||||
const socketProtocol = location.protocol === 'https:' ? 'wss' : 'ws';
|
||||
export const isProduction = import.meta.env.MODE === 'production';
|
||||
export const isDev = !isProduction;
|
||||
|
||||
// resolve port
|
||||
const STATIC_PORT = 4001;
|
||||
export const serverPort = isProduction ? location.port : STATIC_PORT;
|
||||
export const serverURL = `${location.protocol}//${location.hostname}:${serverPort}`;
|
||||
export const websocketUrl = `${socketProtocol}://${location.hostname}:${serverPort}/ws`;
|
||||
|
||||
export const apiEntryUrl = `${serverURL}/data`;
|
||||
|
||||
export const projectDataURL = `${serverURL}/project`;
|
||||
export const rundownURL = `${serverURL}/events`;
|
||||
export const ontimeURL = `${serverURL}/ontime`;
|
||||
@@ -0,0 +1,38 @@
|
||||
import axios from 'axios';
|
||||
import { CustomField, CustomFieldLabel, CustomFields } from 'ontime-types';
|
||||
|
||||
import { apiEntryUrl } from './constants';
|
||||
|
||||
const customFieldsPath = `${apiEntryUrl}/custom-fields`;
|
||||
|
||||
/**
|
||||
* Requests list of known custom fields
|
||||
*/
|
||||
export async function getCustomFields(): Promise<CustomFields> {
|
||||
const res = await axios.get(customFieldsPath);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets list of known custom fields
|
||||
*/
|
||||
export async function postCustomField(newField: CustomField): Promise<CustomFields> {
|
||||
const res = await axios.post(customFieldsPath, { ...newField });
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits single custom field
|
||||
*/
|
||||
export async function editCustomField(label: CustomFieldLabel, newField: CustomField): Promise<CustomFields> {
|
||||
const res = await axios.put(`${customFieldsPath}/${label}`, { ...newField });
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes single custom field
|
||||
*/
|
||||
export async function deleteCustomField(label: CustomFieldLabel): Promise<CustomFields> {
|
||||
const res = await axios.delete(`${customFieldsPath}/${label}`);
|
||||
return res.data;
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
import {
|
||||
CustomFields,
|
||||
DatabaseModel,
|
||||
GetInfo,
|
||||
MessageResponse,
|
||||
OntimeRundown,
|
||||
ProjectData,
|
||||
ProjectFileListResponse,
|
||||
} from 'ontime-types';
|
||||
import { ImportMap } from 'ontime-utils';
|
||||
|
||||
import { apiEntryUrl } from './constants';
|
||||
import fileDownload from './utils';
|
||||
|
||||
const dbPath = `${apiEntryUrl}/db`;
|
||||
|
||||
/**
|
||||
* HTTP request to download db in JSON format
|
||||
*/
|
||||
export async function downloadRundown(fileName?: string) {
|
||||
return fileDownload(
|
||||
dbPath,
|
||||
{ name: fileName ?? 'rundown', type: 'json' },
|
||||
{ type: 'application/json;charset=utf-8;' },
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request to download db in CSV format
|
||||
*/
|
||||
export async function downloadCSV(fileName?: string) {
|
||||
return fileDownload(dbPath, { name: fileName ?? 'rundown', type: 'csv' }, { type: 'text/csv;charset=utf-8;' });
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request to upload project file
|
||||
*/
|
||||
export async function uploadProjectFile(file: File): Promise<MessageResponse> {
|
||||
const formData = new FormData();
|
||||
formData.append('project', file);
|
||||
const response = await axios.post(`${dbPath}/upload`, formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make patch changes to the objects in the db
|
||||
*/
|
||||
export async function patchData(patchDb: Partial<DatabaseModel>): Promise<AxiosResponse<DatabaseModel>> {
|
||||
return await axios.patch(dbPath, patchDb);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request to create a project file
|
||||
*/
|
||||
export async function createProject(
|
||||
project: Partial<
|
||||
ProjectData & {
|
||||
filename: string;
|
||||
}
|
||||
>,
|
||||
): Promise<MessageResponse> {
|
||||
const res = await axios.post(`${dbPath}/new`, project);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request to get the list of available project files
|
||||
*/
|
||||
export async function getProjects(): Promise<ProjectFileListResponse> {
|
||||
const res = await axios.get(`${dbPath}/all`);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request to load a project file
|
||||
*/
|
||||
export async function loadProject(filename: string): Promise<MessageResponse> {
|
||||
const res = await axios.post(`${dbPath}/load`, {
|
||||
filename,
|
||||
});
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request to duplicate a project file
|
||||
*/
|
||||
export async function duplicateProject(filename: string, newFilename: string): Promise<MessageResponse> {
|
||||
const url = `${dbPath}/${filename}/duplicate`;
|
||||
const decodedUrl = decodeURIComponent(url);
|
||||
const res = await axios.post(decodedUrl, {
|
||||
newFilename,
|
||||
});
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request to rename a project file
|
||||
*/
|
||||
export async function renameProject(filename: string, newFilename: string): Promise<MessageResponse> {
|
||||
const url = `${dbPath}/${filename}/rename`;
|
||||
const decodedUrl = decodeURIComponent(url);
|
||||
const res = await axios.put(decodedUrl, {
|
||||
newFilename,
|
||||
});
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request to delete a project file
|
||||
*/
|
||||
export async function deleteProject(filename: string): Promise<MessageResponse> {
|
||||
const url = `${dbPath}/${filename}`;
|
||||
const decodedUrl = decodeURIComponent(url);
|
||||
const res = await axios.delete(decodedUrl);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request to retrieve application info
|
||||
*/
|
||||
export async function getInfo(): Promise<GetInfo> {
|
||||
const res = await axios.get(`${dbPath}/info`);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
type PreviewSpreadsheetResponse = {
|
||||
rundown: OntimeRundown;
|
||||
customFields: CustomFields;
|
||||
};
|
||||
|
||||
/**
|
||||
* Make patch changes to the objects in the db
|
||||
*/
|
||||
export async function importSpreadsheetPreview(file: File, options: ImportMap): Promise<PreviewSpreadsheetResponse> {
|
||||
const formData = new FormData();
|
||||
formData.append('spreadsheet', file);
|
||||
formData.append('options', JSON.stringify(options));
|
||||
|
||||
const response: AxiosResponse<PreviewSpreadsheetResponse> = await axios.post(
|
||||
`${dbPath}/spreadsheet/preview`,
|
||||
formData,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
import axios from 'axios';
|
||||
import { OntimeEvent, OntimeRundown, OntimeRundownEntry, RundownCached } from 'ontime-types';
|
||||
|
||||
import { rundownURL } from './apiConstants';
|
||||
|
||||
/**
|
||||
* @description HTTP request to fetch all events
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function fetchCachedRundown(): Promise<RundownCached> {
|
||||
const res = await axios.get(`${rundownURL}/cached`);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use fetchCachedRundown instead
|
||||
* @description HTTP request to fetch all events
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function fetchRundown(): Promise<OntimeRundown> {
|
||||
const res = await axios.get(rundownURL);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to post new event
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function requestPostEvent(data: Partial<OntimeRundownEntry>) {
|
||||
return axios.post(rundownURL, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to put new event
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function requestPutEvent(data: Partial<OntimeRundownEntry>) {
|
||||
return axios.put(rundownURL, data);
|
||||
}
|
||||
|
||||
type BatchEditEntry = {
|
||||
data: Partial<OntimeEvent>;
|
||||
ids: string[];
|
||||
};
|
||||
|
||||
/**
|
||||
* @description HTTP request to put multiple events
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export async function requestBatchPutEvents(data: BatchEditEntry) {
|
||||
return axios.put(`${rundownURL}/batchEdit`, data);
|
||||
}
|
||||
|
||||
export type ReorderEntry = {
|
||||
eventId: string;
|
||||
from: number;
|
||||
to: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* @description HTTP request to reorder events
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function requestReorderEvent(data: ReorderEntry) {
|
||||
return axios.patch(`${rundownURL}/reorder`, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to request application of delay
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function requestApplyDelay(eventId: string) {
|
||||
return axios.patch(`${rundownURL}/applydelay/${eventId}`);
|
||||
}
|
||||
|
||||
export type SwapEntry = {
|
||||
from: string;
|
||||
to: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* @description HTTP request to swap two events
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function requestEventSwap(data: SwapEntry) {
|
||||
return axios.patch(`${rundownURL}/swap`, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to delete given event
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function requestDelete(eventId: string) {
|
||||
return axios.delete(`${rundownURL}/${eventId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to delete all events
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function requestDeleteAll() {
|
||||
return axios.delete(`${rundownURL}/all`);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import axios from 'axios';
|
||||
|
||||
import { apiRepoLatest } from '../../externals';
|
||||
|
||||
export type HasUpdate = {
|
||||
url: string;
|
||||
version: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* HTTP request to get the latest version and url from github
|
||||
*/
|
||||
export async function getLatestVersion(): Promise<HasUpdate> {
|
||||
const res = await axios.get(`${apiRepoLatest}`);
|
||||
return {
|
||||
url: res.data.html_url as string,
|
||||
version: res.data.tag_name as string,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
import { HttpSettings } from 'ontime-types';
|
||||
|
||||
import { apiEntryUrl } from './constants';
|
||||
|
||||
const httpPath = `${apiEntryUrl}/http`;
|
||||
|
||||
/**
|
||||
* HTTP request to retrieve http settings
|
||||
*/
|
||||
export async function getHTTP(): Promise<HttpSettings> {
|
||||
const res = await axios.get(httpPath);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request to mutate http settings
|
||||
*/
|
||||
export async function postHTTP(data: HttpSettings): Promise<AxiosResponse<HttpSettings>> {
|
||||
return axios.post(httpPath, data);
|
||||
}
|
||||
@@ -1,397 +0,0 @@
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
import {
|
||||
Alias,
|
||||
AuthenticationStatus,
|
||||
CustomField,
|
||||
CustomFieldLabel,
|
||||
CustomFields,
|
||||
DatabaseModel,
|
||||
GetInfo,
|
||||
HttpSettings,
|
||||
MessageResponse,
|
||||
OntimeRundown,
|
||||
OSCSettings,
|
||||
ProjectData,
|
||||
ProjectFileListResponse,
|
||||
Settings,
|
||||
ViewSettings,
|
||||
} from 'ontime-types';
|
||||
import { ImportMap } from 'ontime-utils';
|
||||
|
||||
import { apiRepoLatest } from '../../externals';
|
||||
import fileDownload from '../utils/fileDownload';
|
||||
|
||||
import { ontimeURL, projectDataURL } from './apiConstants';
|
||||
|
||||
/**
|
||||
* @description HTTP request to retrieve application settings
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function getSettings(): Promise<Settings> {
|
||||
const res = await axios.get(`${ontimeURL}/settings`);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to mutate application settings
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function postSettings(data: Settings) {
|
||||
return axios.post(`${ontimeURL}/settings`, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to retrieve application info
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function getInfo(): Promise<GetInfo> {
|
||||
const res = await axios.get(`${ontimeURL}/info`);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to retrieve view settings
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function getView(): Promise<ViewSettings> {
|
||||
const res = await axios.get(`${ontimeURL}/views`);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to mutate view settings
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function postViewSettings(data: ViewSettings) {
|
||||
return axios.post(`${ontimeURL}/views`, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to retrieve aliases
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function getAliases(): Promise<Alias[]> {
|
||||
const res = await axios.get(`${ontimeURL}/aliases`);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to mutate aliases
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function postAliases(data: Alias[]) {
|
||||
return axios.post(`${ontimeURL}/aliases`, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to retrieve osc settings
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function getOSC(): Promise<OSCSettings> {
|
||||
const res = await axios.get(`${ontimeURL}/osc`);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to mutate osc settings
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function postOSC(data: OSCSettings): Promise<AxiosResponse<OSCSettings>> {
|
||||
return axios.post(`${ontimeURL}/osc`, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to retrieve http settings
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function getHTTP(): Promise<HttpSettings> {
|
||||
const res = await axios.get(`${ontimeURL}/http`);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to mutate http settings
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function postHTTP(data: HttpSettings): Promise<AxiosResponse<HttpSettings>> {
|
||||
return axios.post(`${ontimeURL}/http`, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to download db in CSV format
|
||||
*/
|
||||
export const downloadCSV = (fileName?: string) => {
|
||||
return fileDownload(ontimeURL, { name: fileName ?? 'rundown', type: 'csv' }, { type: 'text/csv;charset=utf-8;' });
|
||||
};
|
||||
|
||||
/**
|
||||
* @description HTTP request to download db in JSON format
|
||||
*/
|
||||
export const downloadRundown = (fileName?: string) => {
|
||||
return fileDownload(
|
||||
ontimeURL,
|
||||
{ name: fileName ?? 'rundown', type: 'json' },
|
||||
{ type: 'application/json;charset=utf-8;' },
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @description HTTP request to upload project file
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function importProjectFile(file: File): Promise<void> {
|
||||
const formData = new FormData();
|
||||
formData.append('userFile', file);
|
||||
const response = await axios.post(`${ontimeURL}/db`, formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
|
||||
// TODO: should this be extracted to shared code?
|
||||
export type ProjectFileImportOptions = {
|
||||
onlyRundown: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* @description HTTP request to upload events db
|
||||
* @return {Promise}
|
||||
*/
|
||||
export const uploadProjectFile = async (
|
||||
file: File,
|
||||
setProgress: (value: number) => void,
|
||||
options?: Partial<ProjectFileImportOptions>,
|
||||
) => {
|
||||
const formData = new FormData();
|
||||
formData.append('userFile', file);
|
||||
|
||||
const onlyRundown = Boolean(options?.onlyRundown);
|
||||
|
||||
await axios
|
||||
.post(`${ontimeURL}/db?onlyRundown=${onlyRundown}`, formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
onUploadProgress: (progressEvent) => {
|
||||
const complete = progressEvent?.total ? Math.round((progressEvent.loaded * 100) / progressEvent.total) : 0;
|
||||
setProgress(complete);
|
||||
},
|
||||
})
|
||||
.then((response) => response.data.id);
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Make patch changes to the objects in the db
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function patchData(patchDb: Partial<DatabaseModel>): Promise<void> {
|
||||
return await axios.patch(`${ontimeURL}/db`, patchDb);
|
||||
}
|
||||
|
||||
type PreviewSpreadsheetResponse = {
|
||||
rundown: OntimeRundown;
|
||||
customFields: CustomFields;
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Make patch changes to the objects in the db
|
||||
* @return {Promise} - returns parsed rundown and customFields
|
||||
*/
|
||||
export async function importSpreadsheetPreview(file: File, options: ImportMap): Promise<PreviewSpreadsheetResponse> {
|
||||
const formData = new FormData();
|
||||
formData.append('userFile', file);
|
||||
formData.append('options', JSON.stringify(options));
|
||||
|
||||
const response: AxiosResponse<PreviewSpreadsheetResponse> = await axios.post(
|
||||
`${ontimeURL}/spreadsheet/preview`,
|
||||
formData,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export type HasUpdate = {
|
||||
url: string;
|
||||
version: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* @description HTTP request to get the latest version and url from github
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function getLatestVersion(): Promise<HasUpdate> {
|
||||
const res = await axios.get(`${apiRepoLatest}`);
|
||||
return {
|
||||
url: res.data.html_url as string,
|
||||
version: res.data.tag_name as string,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to get the list of available project files
|
||||
*/
|
||||
export async function getProjects(): Promise<ProjectFileListResponse> {
|
||||
const res = await axios.get(`${ontimeURL}/projects`);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to load a project file
|
||||
*/
|
||||
export async function loadProject(filename: string): Promise<MessageResponse> {
|
||||
const res = await axios.post(`${ontimeURL}/load-project`, {
|
||||
filename,
|
||||
});
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to initiate the authentication service with google
|
||||
*/
|
||||
export const requestConnection = async (
|
||||
file: File,
|
||||
sheetId: string,
|
||||
): Promise<{
|
||||
verification_url: string;
|
||||
user_code: string;
|
||||
}> => {
|
||||
const formData = new FormData();
|
||||
formData.append('client_secret', file);
|
||||
|
||||
const response = await axios.post(`${ontimeURL}/sheet/${sheetId}/connect`, formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
});
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* @description HTTP request to verify whether we are authenticated with Google Sheet service
|
||||
*/
|
||||
export const verifyAuthenticationStatus = async (): Promise<{ authenticated: AuthenticationStatus }> => {
|
||||
const response = await axios.get(`${ontimeURL}/sheet/connect`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* @description HTTP request to revoke authentication to google sheet
|
||||
*/
|
||||
export const revokeAuthentication = async (): Promise<{ authenticated: AuthenticationStatus }> => {
|
||||
const response = await axios.post(`${ontimeURL}/sheet/revoke`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* @description HTTP request to upload preview the contents of a google sheet as rundown
|
||||
*/
|
||||
export const previewRundown = async (
|
||||
sheetId: string,
|
||||
options: ImportMap,
|
||||
): Promise<{
|
||||
rundown: OntimeRundown;
|
||||
customFields: CustomFields;
|
||||
}> => {
|
||||
const response = await axios.post(`${ontimeURL}/sheet/${sheetId}/read`, { options });
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* @description HTTP request to upload the rundown to a google sheet
|
||||
*/
|
||||
export const uploadRundown = async (sheetId: string, options: ImportMap): Promise<void> => {
|
||||
const response = await axios.post(`${ontimeURL}/sheet/${sheetId}/write`, { options });
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* @description HTTP request to rename a project file
|
||||
*/
|
||||
export async function renameProject(filename: string, newFilename: string): Promise<MessageResponse> {
|
||||
const url = `${ontimeURL}/project/${filename}/rename`;
|
||||
const decodedUrl = decodeURIComponent(url);
|
||||
const res = await axios.put(decodedUrl, {
|
||||
newFilename,
|
||||
});
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to duplicate a project file
|
||||
*/
|
||||
export async function duplicateProject(filename: string, newFilename: string): Promise<MessageResponse> {
|
||||
const url = `${ontimeURL}/project/${filename}/duplicate`;
|
||||
const decodedUrl = decodeURIComponent(url);
|
||||
const res = await axios.post(decodedUrl, {
|
||||
newFilename,
|
||||
});
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to delete a project file
|
||||
*/
|
||||
export async function deleteProject(filename: string): Promise<MessageResponse> {
|
||||
const url = `${ontimeURL}/project/${filename}`;
|
||||
const decodedUrl = decodeURIComponent(url);
|
||||
const res = await axios.delete(decodedUrl);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to create a project file
|
||||
*/
|
||||
export async function createProject(
|
||||
project: Partial<
|
||||
ProjectData & {
|
||||
filename: string;
|
||||
}
|
||||
>,
|
||||
): Promise<MessageResponse> {
|
||||
const res = await axios.post(`${ontimeURL}/project`, project);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests list of known custom fields
|
||||
*/
|
||||
export async function getCustomFields(): Promise<CustomFields> {
|
||||
const res = await axios.get(`${projectDataURL}/custom-field`);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets list of known custom fields
|
||||
*/
|
||||
export async function postCustomField(newField: CustomField): Promise<CustomFields> {
|
||||
const res = await axios.post(`${projectDataURL}/custom-field`, {
|
||||
...newField,
|
||||
});
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits single custom field
|
||||
*/
|
||||
export async function editCustomField(label: CustomFieldLabel, newField: CustomField): Promise<CustomFields> {
|
||||
const res = await axios.put(`${projectDataURL}/custom-field/${label}`, {
|
||||
...newField,
|
||||
});
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes single custom field
|
||||
*/
|
||||
export async function deleteCustomField(label: CustomFieldLabel): Promise<CustomFields> {
|
||||
const res = await axios.delete(`${projectDataURL}/custom-field/${label}`);
|
||||
return res.data;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
import { OSCSettings } from 'ontime-types';
|
||||
|
||||
import { apiEntryUrl } from './constants';
|
||||
|
||||
const oscPath = `${apiEntryUrl}/osc`;
|
||||
|
||||
/**
|
||||
* HTTP request to retrieve osc settings
|
||||
*/
|
||||
export async function getOSC(): Promise<OSCSettings> {
|
||||
const res = await axios.get(oscPath);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request to mutate osc settings
|
||||
*/
|
||||
export async function postOSC(data: OSCSettings): Promise<AxiosResponse<OSCSettings>> {
|
||||
return axios.post(oscPath, data);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
import { ProjectData } from 'ontime-types';
|
||||
|
||||
import { apiEntryUrl } from './constants';
|
||||
|
||||
const projectPath = `${apiEntryUrl}/project`;
|
||||
|
||||
/**
|
||||
* HTTP request to fetch project data
|
||||
*/
|
||||
export async function getProjectData(): Promise<ProjectData> {
|
||||
const res = await axios.get(projectPath);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request to mutate project data
|
||||
*/
|
||||
export async function postProjectData(data: ProjectData): Promise<AxiosResponse<ProjectData>> {
|
||||
return axios.post(projectPath, data);
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import axios from 'axios';
|
||||
import { ProjectData } from 'ontime-types';
|
||||
|
||||
import { projectDataURL } from './apiConstants';
|
||||
|
||||
/**
|
||||
* @description HTTP request to fetch project data
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function getProjectData(): Promise<ProjectData> {
|
||||
const res = await axios.get(projectDataURL);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to mutate project data
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function postProjectData(data: ProjectData) {
|
||||
return axios.post(projectDataURL, data);
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
import { MessageResponse, OntimeEvent, OntimeRundownEntry, RundownCached } from 'ontime-types';
|
||||
|
||||
import { apiEntryUrl } from './constants';
|
||||
|
||||
const rundownPath = `${apiEntryUrl}/rundown`;
|
||||
|
||||
/**
|
||||
* HTTP request to fetch all events
|
||||
*/
|
||||
export async function fetchNormalisedRundown(): Promise<RundownCached> {
|
||||
const res = await axios.get(`${rundownPath}/normalised`);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request to post new event
|
||||
*/
|
||||
export async function requestPostEvent(data: Partial<OntimeRundownEntry>): Promise<AxiosResponse<OntimeRundownEntry>> {
|
||||
return axios.post(rundownPath, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request to put new event
|
||||
*/
|
||||
export async function requestPutEvent(data: Partial<OntimeRundownEntry>): Promise<AxiosResponse<OntimeRundownEntry>> {
|
||||
return axios.put(rundownPath, data);
|
||||
}
|
||||
|
||||
type BatchEditEntry = {
|
||||
data: Partial<OntimeEvent>;
|
||||
ids: string[];
|
||||
};
|
||||
|
||||
/**
|
||||
* HTTP request to put multiple events
|
||||
*/
|
||||
export async function requestBatchPutEvents(data: BatchEditEntry): Promise<AxiosResponse<MessageResponse>> {
|
||||
return axios.put(`${rundownPath}/batch`, data);
|
||||
}
|
||||
|
||||
export type ReorderEntry = {
|
||||
eventId: string;
|
||||
from: number;
|
||||
to: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* HTTP request to reorder events
|
||||
*/
|
||||
export async function requestReorderEvent(data: ReorderEntry): Promise<AxiosResponse<OntimeRundownEntry>> {
|
||||
return axios.patch(`${rundownPath}/reorder`, data);
|
||||
}
|
||||
|
||||
export type SwapEntry = {
|
||||
from: string;
|
||||
to: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* HTTP request to swap two events
|
||||
*/
|
||||
export async function requestEventSwap(data: SwapEntry): Promise<AxiosResponse<MessageResponse>> {
|
||||
return axios.patch(`${rundownPath}/swap`, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request to request application of delay
|
||||
*/
|
||||
export async function requestApplyDelay(eventId: string): Promise<AxiosResponse<MessageResponse>> {
|
||||
return axios.patch(`${rundownPath}/applydelay/${eventId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request to delete given event
|
||||
*/
|
||||
export async function requestDelete(eventId: string): Promise<AxiosResponse<MessageResponse>> {
|
||||
return axios.delete(`${rundownPath}/${eventId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request to delete all events
|
||||
*/
|
||||
export async function requestDeleteAll(): Promise<AxiosResponse<MessageResponse>> {
|
||||
return axios.delete(`${rundownPath}/all`);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
import { Settings } from 'ontime-types';
|
||||
|
||||
import { apiEntryUrl } from './constants';
|
||||
|
||||
const settingsPath = `${apiEntryUrl}/settings`;
|
||||
|
||||
/**
|
||||
* HTTP request to retrieve application settings
|
||||
*/
|
||||
export async function getSettings(): Promise<Settings> {
|
||||
const res = await axios.get(settingsPath);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request to mutate application settings
|
||||
*/
|
||||
export async function postSettings(data: Settings): Promise<AxiosResponse<Settings>> {
|
||||
return axios.post(settingsPath, data);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import axios from 'axios';
|
||||
import { AuthenticationStatus, CustomFields, OntimeRundown } from 'ontime-types';
|
||||
import { ImportMap } from 'ontime-utils';
|
||||
|
||||
import { apiEntryUrl } from './constants';
|
||||
|
||||
const sheetsPath = `${apiEntryUrl}/sheets`;
|
||||
|
||||
/**
|
||||
* HTTP request to verify whether we are authenticated with Google Sheet service
|
||||
*/
|
||||
export const verifyAuthenticationStatus = async (): Promise<{ authenticated: AuthenticationStatus }> => {
|
||||
const response = await axios.get(`${apiEntryUrl}/connect`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* HTTP request to initiate the authentication service with google
|
||||
*/
|
||||
export const requestConnection = async (
|
||||
file: File,
|
||||
sheetId: string,
|
||||
): Promise<{
|
||||
verification_url: string;
|
||||
user_code: string;
|
||||
}> => {
|
||||
const formData = new FormData();
|
||||
formData.append('client_secret', file);
|
||||
|
||||
const response = await axios.post(`${sheetsPath}/${sheetId}/connect`, formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
});
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* HTTP request to revoke authentication to google sheet
|
||||
*/
|
||||
export const revokeAuthentication = async (): Promise<{ authenticated: AuthenticationStatus }> => {
|
||||
const response = await axios.post(`${sheetsPath}/revoke`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* HTTP request to upload preview the contents of a google sheet as rundown
|
||||
*/
|
||||
export const previewRundown = async (
|
||||
sheetId: string,
|
||||
options: ImportMap,
|
||||
): Promise<{
|
||||
rundown: OntimeRundown;
|
||||
customFields: CustomFields;
|
||||
}> => {
|
||||
const response = await axios.post(`${sheetsPath}/${sheetId}/read`, { options });
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* HTTP request to upload the rundown to a google sheet
|
||||
*/
|
||||
export const uploadRundown = async (sheetId: string, options: ImportMap): Promise<void> => {
|
||||
const response = await axios.post(`${sheetsPath}/${sheetId}/write`, { options });
|
||||
return response.data;
|
||||
};
|
||||
@@ -1,6 +1,60 @@
|
||||
import axios from 'axios';
|
||||
import axios, { AxiosError } from 'axios';
|
||||
import { LogLevel } from 'ontime-types';
|
||||
import { generateId, millisToString } from 'ontime-utils';
|
||||
|
||||
import { makeCSV, makeTable } from '../../features/cuesheet/cuesheetUtils';
|
||||
import { ontimeQueryClient } from '../queryClient';
|
||||
import { addLog } from '../stores/logger';
|
||||
import { nowInMillis } from '../utils/time';
|
||||
|
||||
/**
|
||||
* Utility unrwap a potential axios error
|
||||
* @param error
|
||||
* @returns
|
||||
*/
|
||||
export function maybeAxiosError(error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
const statusText = (error as AxiosError).response?.statusText ?? '';
|
||||
let data = (error as AxiosError).response?.data ?? '';
|
||||
if (typeof data === 'object') {
|
||||
if ('message' in data) {
|
||||
data = JSON.stringify(data.message);
|
||||
} else {
|
||||
data = JSON.stringify(data);
|
||||
}
|
||||
}
|
||||
return `${statusText}: ${data}`;
|
||||
} else {
|
||||
if (typeof error !== 'string') {
|
||||
return JSON.stringify(error);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility unrwaps a potential axios error and sends to logger
|
||||
* @param prepend
|
||||
* @param error
|
||||
*/
|
||||
export function logAxiosError(prepend: string, error: unknown) {
|
||||
const message = `${prepend}: ${maybeAxiosError(error)}`;
|
||||
|
||||
addLog({
|
||||
id: generateId(),
|
||||
origin: 'SERVER',
|
||||
time: millisToString(nowInMillis()),
|
||||
level: LogLevel.Error,
|
||||
text: message,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function invalidates react-query caches
|
||||
*/
|
||||
export async function invalidateAllCaches() {
|
||||
await ontimeQueryClient.invalidateQueries();
|
||||
}
|
||||
|
||||
type FileOptions = {
|
||||
name: string;
|
||||
@@ -61,3 +115,4 @@ export default async function fileDownload(url: string, fileOptions: FileOptions
|
||||
URL.revokeObjectURL(downloadUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import axios from 'axios';
|
||||
import { ViewSettings } from 'ontime-types';
|
||||
|
||||
import { apiEntryUrl } from './constants';
|
||||
|
||||
const viewSettingsPath = `${apiEntryUrl}/view-settings`;
|
||||
|
||||
/**
|
||||
* HTTP request to retrieve view settings
|
||||
*/
|
||||
export async function getView(): Promise<ViewSettings> {
|
||||
const res = await axios.get(viewSettingsPath);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request to mutate view settings
|
||||
*/
|
||||
export async function postViewSettings(data: ViewSettings) {
|
||||
return axios.post(viewSettingsPath, data);
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { queryRefetchIntervalSlow } from '../../ontimeConfig';
|
||||
import { ALIASES } from '../api/apiConstants';
|
||||
import { getAliases } from '../api/ontimeApi';
|
||||
import { getAliases } from '../api/aliases';
|
||||
import { ALIASES } from '../api/constants';
|
||||
|
||||
export default function useAliases() {
|
||||
const { data, status, isFetching, isError, refetch } = useQuery({
|
||||
|
||||
@@ -2,8 +2,8 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { CustomFields } from 'ontime-types';
|
||||
|
||||
import { queryRefetchInterval } from '../../ontimeConfig';
|
||||
import { CUSTOM_FIELDS } from '../api/apiConstants';
|
||||
import { getCustomFields } from '../api/ontimeApi';
|
||||
import { CUSTOM_FIELDS } from '../api/constants';
|
||||
import { getCustomFields } from '../api/customFields';
|
||||
|
||||
const placeholder: CustomFields = {};
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { queryRefetchIntervalSlow } from '../../ontimeConfig';
|
||||
import { HTTP_SETTINGS } from '../api/apiConstants';
|
||||
import { logAxiosError } from '../api/apiUtils';
|
||||
import { getHTTP, postHTTP } from '../api/ontimeApi';
|
||||
import { HTTP_SETTINGS } from '../api/constants';
|
||||
import { getHTTP, postHTTP } from '../api/http';
|
||||
import { logAxiosError } from '../api/utils';
|
||||
import { httpPlaceholder } from '../models/Http';
|
||||
import { ontimeQueryClient } from '../queryClient';
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { GetInfo } from 'ontime-types';
|
||||
|
||||
import { queryRefetchIntervalSlow } from '../../ontimeConfig';
|
||||
import { APP_INFO } from '../api/apiConstants';
|
||||
import { getInfo } from '../api/ontimeApi';
|
||||
import { APP_INFO } from '../api/constants';
|
||||
import { getInfo } from '../api/db';
|
||||
import { ontimePlaceholderInfo } from '../models/Info';
|
||||
|
||||
export default function useInfo() {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { queryRefetchIntervalSlow } from '../../ontimeConfig';
|
||||
import { OSC_SETTINGS } from '../api/apiConstants';
|
||||
import { logAxiosError } from '../api/apiUtils';
|
||||
import { getOSC, postOSC } from '../api/ontimeApi';
|
||||
import { OSC_SETTINGS } from '../api/constants';
|
||||
import { getOSC, postOSC } from '../api/osc';
|
||||
import { logAxiosError } from '../api/utils';
|
||||
import { oscPlaceholderSettings } from '../models/OscSettings';
|
||||
import { ontimeQueryClient } from '../queryClient';
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { queryRefetchIntervalSlow } from '../../ontimeConfig';
|
||||
import { PROJECT_DATA } from '../api/apiConstants';
|
||||
import { getProjectData } from '../api/projectDataApi';
|
||||
import { PROJECT_DATA } from '../api/constants';
|
||||
import { getProjectData } from '../api/project';
|
||||
import { projectDataPlaceholder } from '../models/ProjectData';
|
||||
|
||||
export default function useProjectData() {
|
||||
|
||||
@@ -2,8 +2,8 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { ProjectFileListResponse } from 'ontime-types';
|
||||
|
||||
import { queryRefetchIntervalSlow } from '../../ontimeConfig';
|
||||
import { PROJECT_LIST } from '../api/apiConstants';
|
||||
import { getProjects } from '../api/ontimeApi';
|
||||
import { PROJECT_LIST } from '../api/constants';
|
||||
import { getProjects } from '../api/db';
|
||||
|
||||
const placeholderProjectList: ProjectFileListResponse = {
|
||||
files: [],
|
||||
|
||||
@@ -3,8 +3,8 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { NormalisedRundown, OntimeRundown, RundownCached } from 'ontime-types';
|
||||
|
||||
import { queryRefetchInterval } from '../../ontimeConfig';
|
||||
import { RUNDOWN } from '../api/apiConstants';
|
||||
import { fetchCachedRundown } from '../api/eventsApi';
|
||||
import { RUNDOWN } from '../api/constants';
|
||||
import { fetchNormalisedRundown } from '../api/rundown';
|
||||
|
||||
// revision is -1 so that the remote revision is higher
|
||||
const cachedRundownPlaceholder = { order: [] as string[], rundown: {} as NormalisedRundown, revision: -1 };
|
||||
@@ -12,7 +12,7 @@ const cachedRundownPlaceholder = { order: [] as string[], rundown: {} as Normali
|
||||
export default function useRundown() {
|
||||
const { data, status, isError, refetch, isFetching } = useQuery<RundownCached>({
|
||||
queryKey: RUNDOWN,
|
||||
queryFn: fetchCachedRundown,
|
||||
queryFn: fetchNormalisedRundown,
|
||||
placeholderData: cachedRundownPlaceholder,
|
||||
retry: 5,
|
||||
retryDelay: (attempt) => attempt * 2500,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { queryRefetchIntervalSlow } from '../../ontimeConfig';
|
||||
import { APP_SETTINGS } from '../api/apiConstants';
|
||||
import { getSettings } from '../api/ontimeApi';
|
||||
import { APP_SETTINGS } from '../api/constants';
|
||||
import { getSettings } from '../api/settings';
|
||||
import { ontimePlaceholderSettings } from '../models/OntimeSettings';
|
||||
|
||||
export default function useSettings() {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { queryRefetchIntervalSlow } from '../../ontimeConfig';
|
||||
import { VIEW_SETTINGS } from '../api/apiConstants';
|
||||
import { getView } from '../api/ontimeApi';
|
||||
import { VIEW_SETTINGS } from '../api/constants';
|
||||
import { getView } from '../api/viewSettings';
|
||||
import { viewsSettingsPlaceholder } from '../models/ViewSettings.type';
|
||||
|
||||
export default function useViewSettings() {
|
||||
|
||||
@@ -3,8 +3,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { isOntimeEvent, MaybeString, OntimeEvent, OntimeRundownEntry, RundownCached } from 'ontime-types';
|
||||
import { getLinkedTimes, getPreviousEventNormal, reorderArray, swapEventData } from 'ontime-utils';
|
||||
|
||||
import { RUNDOWN } from '../api/apiConstants';
|
||||
import { logAxiosError } from '../api/apiUtils';
|
||||
import { RUNDOWN } from '../api/constants';
|
||||
import {
|
||||
ReorderEntry,
|
||||
requestApplyDelay,
|
||||
@@ -16,7 +15,8 @@ import {
|
||||
requestPutEvent,
|
||||
requestReorderEvent,
|
||||
SwapEntry,
|
||||
} from '../api/eventsApi';
|
||||
} from '../api/rundown';
|
||||
import { logAxiosError } from '../api/utils';
|
||||
import { useEditorSettings } from '../stores/editorSettings';
|
||||
import { forgivingStringToMillis } from '../utils/dateConfig';
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import { useMemo, useRef } from 'react';
|
||||
|
||||
import { isDev } from '../api/apiConstants';
|
||||
import { isDev } from '../api/constants';
|
||||
|
||||
type noop = (this: any, ...args: any[]) => any;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Log, RuntimeStore } from 'ontime-types';
|
||||
|
||||
import { isProduction, RUNTIME, websocketUrl } from '../api/apiConstants';
|
||||
import { isProduction, RUNTIME, websocketUrl } from '../api/constants';
|
||||
import { ontimeQueryClient } from '../queryClient';
|
||||
import { socketClientName } from '../stores/connectionName';
|
||||
import { addLog } from '../stores/logger';
|
||||
|
||||
@@ -2,7 +2,7 @@ import { MaybeNumber, Settings, TimeFormat } from 'ontime-types';
|
||||
import { formatFromMillis } from 'ontime-utils';
|
||||
|
||||
import { FORMAT_12, FORMAT_24 } from '../../viewerConfig';
|
||||
import { APP_SETTINGS } from '../api/apiConstants';
|
||||
import { APP_SETTINGS } from '../api/constants';
|
||||
import { ontimeQueryClient } from '../queryClient';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState } from 'react';
|
||||
import { Button } from '@chakra-ui/react';
|
||||
|
||||
import { getLatestVersion, HasUpdate } from '../../../../common/api/ontimeApi';
|
||||
import { getLatestVersion, HasUpdate } from '../../../../common/api/external';
|
||||
import ExternalLink from '../../../../common/components/external-link/ExternalLink';
|
||||
|
||||
import style from '../Panel.module.scss';
|
||||
@@ -52,7 +52,13 @@ export default function CheckUpdatesButton(props: CheckUpdatesButtonProps) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button onClick={versionCheck} variant='ontime-filled' isLoading={isFetching} isDisabled={disableButton} size='sm'>
|
||||
<Button
|
||||
onClick={versionCheck}
|
||||
variant='ontime-filled'
|
||||
isLoading={isFetching}
|
||||
isDisabled={disableButton}
|
||||
size='sm'
|
||||
>
|
||||
Check for updates
|
||||
</Button>
|
||||
<ResolveUpdateMessage updateMessage={updateMessage} />
|
||||
|
||||
@@ -5,7 +5,7 @@ import { IoTrash } from '@react-icons/all-files/io5/IoTrash';
|
||||
import { HttpSettings } from 'ontime-types';
|
||||
import { generateId } from 'ontime-utils';
|
||||
|
||||
import { maybeAxiosError } from '../../../../common/api/apiUtils';
|
||||
import { maybeAxiosError } from '../../../../common/api/utils';
|
||||
import { useHttpSettings, usePostHttpSettings } from '../../../../common/hooks-query/useHttpSettings';
|
||||
import { isKeyEscape } from '../../../../common/utils/keyEvent';
|
||||
import { startsWithHttp } from '../../../../common/utils/regex';
|
||||
|
||||
@@ -5,7 +5,7 @@ import { IoTrash } from '@react-icons/all-files/io5/IoTrash';
|
||||
import { OSCSettings } from 'ontime-types';
|
||||
import { generateId } from 'ontime-utils';
|
||||
|
||||
import { maybeAxiosError } from '../../../../common/api/apiUtils';
|
||||
import { maybeAxiosError } from '../../../../common/api/utils';
|
||||
import useOscSettings, { useOscSettingsMutation } from '../../../../common/hooks-query/useOscSettings';
|
||||
import { isKeyEscape } from '../../../../common/utils/keyEvent';
|
||||
import { isIPAddress, isOnlyNumbers, startsWithSlash } from '../../../../common/utils/regex';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { serverPort } from '../../../../common/api/apiConstants';
|
||||
import { serverPort } from '../../../../common/api/constants';
|
||||
import AppLink from '../../../../common/components/app-link/AppLink';
|
||||
import useInfo from '../../../../common/hooks-query/useInfo';
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { Button, Input, Textarea } from '@chakra-ui/react';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import { maybeAxiosError } from '../../../../common/api/apiUtils';
|
||||
import { createProject } from '../../../../common/api/ontimeApi';
|
||||
import { PROJECT_LIST } from '../../../../common/api/constants';
|
||||
import { createProject } from '../../../../common/api/db';
|
||||
import { maybeAxiosError } from '../../../../common/api/utils';
|
||||
import * as Panel from '../PanelUtils';
|
||||
|
||||
import style from './ProjectPanel.module.scss';
|
||||
@@ -25,6 +27,7 @@ export default function ProjectCreateForm(props: ProjectCreateFromProps) {
|
||||
const { onClose } = props;
|
||||
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const {
|
||||
handleSubmit,
|
||||
@@ -53,6 +56,7 @@ export default function ProjectCreateForm(props: ProjectCreateFromProps) {
|
||||
...values,
|
||||
filename,
|
||||
});
|
||||
await queryClient.invalidateQueries({ queryKey: PROJECT_LIST });
|
||||
onClose();
|
||||
} catch (error) {
|
||||
setError(maybeAxiosError(error));
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useState } from 'react';
|
||||
import { IconButton, Menu, MenuButton, MenuItem, MenuList } from '@chakra-ui/react';
|
||||
import { IoEllipsisHorizontal } from '@react-icons/all-files/io5/IoEllipsisHorizontal';
|
||||
|
||||
import { invalidateAllCaches, maybeAxiosError } from '../../../../common/api/apiUtils';
|
||||
import {
|
||||
deleteProject,
|
||||
downloadCSV,
|
||||
@@ -10,7 +9,8 @@ import {
|
||||
duplicateProject,
|
||||
loadProject,
|
||||
renameProject,
|
||||
} from '../../../../common/api/ontimeApi';
|
||||
} from '../../../../common/api/db';
|
||||
import { invalidateAllCaches, maybeAxiosError } from '../../../../common/api/utils';
|
||||
|
||||
import ProjectForm, { ProjectFormValues } from './ProjectForm';
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ import { ChangeEvent, useRef, useState } from 'react';
|
||||
import { Button, Input } from '@chakra-ui/react';
|
||||
import { IoAdd } from '@react-icons/all-files/io5/IoAdd';
|
||||
|
||||
import { invalidateAllCaches, maybeAxiosError } from '../../../../common/api/apiUtils';
|
||||
import { importProjectFile } from '../../../../common/api/ontimeApi';
|
||||
import { uploadProjectFile } from '../../../../common/api/db';
|
||||
import { invalidateAllCaches, maybeAxiosError } from '../../../../common/api/utils';
|
||||
import { validateProjectFile } from '../../../../common/utils/uploadUtils';
|
||||
import * as Panel from '../PanelUtils';
|
||||
|
||||
@@ -37,7 +37,7 @@ export default function ProjectPanel() {
|
||||
|
||||
try {
|
||||
validateProjectFile(selectedFile);
|
||||
await importProjectFile(selectedFile);
|
||||
await uploadProjectFile(selectedFile);
|
||||
} catch (error) {
|
||||
const errorMessage = maybeAxiosError(error);
|
||||
setError(`Error uploading file: ${errorMessage}`);
|
||||
@@ -48,6 +48,10 @@ export default function ProjectPanel() {
|
||||
setLoading(null);
|
||||
};
|
||||
|
||||
const handleCloseForm = () => {
|
||||
setIsCreatingProject(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Panel.Header>Project</Panel.Header>
|
||||
@@ -85,7 +89,7 @@ export default function ProjectPanel() {
|
||||
</div>
|
||||
</Panel.SubHeader>
|
||||
{error && <Panel.Error>{error}</Panel.Error>}
|
||||
{isCreatingProject && <ProjectCreateForm onClose={() => setIsCreatingProject(false)} />}
|
||||
{isCreatingProject && <ProjectCreateForm onClose={handleCloseForm} />}
|
||||
<ProjectList />
|
||||
</Panel.Card>
|
||||
</Panel.Section>
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import { Button, Input } from '@chakra-ui/react';
|
||||
import { CustomField } from 'ontime-types';
|
||||
import { isAlphanumeric } from 'ontime-utils';
|
||||
|
||||
import { maybeAxiosError } from '../../../../common/api/apiUtils';
|
||||
import { maybeAxiosError } from '../../../../common/api/utils';
|
||||
import SwatchSelect from '../../../../common/components/input/colour-input/SwatchSelect';
|
||||
import * as Panel from '../PanelUtils';
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { Alert, AlertDescription, AlertIcon, Button } from '@chakra-ui/react';
|
||||
import { IoAdd } from '@react-icons/all-files/io5/IoAdd';
|
||||
import { CustomField, CustomFieldLabel } from 'ontime-types';
|
||||
|
||||
import { deleteCustomField, editCustomField, postCustomField } from '../../../../common/api/ontimeApi';
|
||||
import { deleteCustomField, editCustomField, postCustomField } from '../../../../common/api/customFields';
|
||||
import ExternalLink from '../../../../common/components/external-link/ExternalLink';
|
||||
import useCustomFields from '../../../../common/hooks-query/useCustomFields';
|
||||
import * as Panel from '../PanelUtils';
|
||||
|
||||
@@ -4,8 +4,8 @@ import { IoCloudOutline } from '@react-icons/all-files/io5/IoCloudOutline';
|
||||
import { IoDownloadOutline } from '@react-icons/all-files/io5/IoDownloadOutline';
|
||||
import { ImportMap, unpackError } from 'ontime-utils';
|
||||
|
||||
import { maybeAxiosError } from '../../../../common/api/apiUtils';
|
||||
import { importSpreadsheetPreview } from '../../../../common/api/ontimeApi';
|
||||
import { importSpreadsheetPreview } from '../../../../common/api/db';
|
||||
import { maybeAxiosError } from '../../../../common/api/utils';
|
||||
import { validateSpreadsheetImport } from '../../../../common/utils/uploadUtils';
|
||||
import * as Panel from '../PanelUtils';
|
||||
|
||||
|
||||
@@ -2,16 +2,16 @@ import { useQueryClient } from '@tanstack/react-query';
|
||||
import { AuthenticationStatus, CustomFields, OntimeRundown } from 'ontime-types';
|
||||
import { ImportMap } from 'ontime-utils';
|
||||
|
||||
import { CUSTOM_FIELDS, RUNDOWN } from '../../../../common/api/apiConstants';
|
||||
import { maybeAxiosError } from '../../../../common/api/apiUtils';
|
||||
import { CUSTOM_FIELDS, RUNDOWN } from '../../../../common/api/constants';
|
||||
import { patchData } from '../../../../common/api/db';
|
||||
import {
|
||||
patchData,
|
||||
previewRundown,
|
||||
requestConnection,
|
||||
revokeAuthentication,
|
||||
uploadRundown,
|
||||
verifyAuthenticationStatus,
|
||||
} from '../../../../common/api/ontimeApi';
|
||||
} from '../../../../common/api/sheets';
|
||||
import { maybeAxiosError } from '../../../../common/api/utils';
|
||||
|
||||
import { useSheetStore } from './useSheetStore';
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ import { IoOpenOutline } from '@react-icons/all-files/io5/IoOpenOutline';
|
||||
import { IoRemove } from '@react-icons/all-files/io5/IoRemove';
|
||||
import { Alias } from 'ontime-types';
|
||||
|
||||
import { logAxiosError } from '../../../common/api/apiUtils';
|
||||
import { postAliases } from '../../../common/api/ontimeApi';
|
||||
import { postAliases } from '../../../common/api/aliases';
|
||||
import { logAxiosError } from '../../../common/api/utils';
|
||||
import TooltipActionBtn from '../../../common/components/buttons/TooltipActionBtn';
|
||||
import useAliases from '../../../common/hooks-query/useAliases';
|
||||
import { useEmitLog } from '../../../common/stores/logger';
|
||||
|
||||
@@ -3,8 +3,8 @@ import { useForm } from 'react-hook-form';
|
||||
import { Input, Select } from '@chakra-ui/react';
|
||||
import type { Settings } from 'ontime-types';
|
||||
|
||||
import { logAxiosError } from '../../../common/api/apiUtils';
|
||||
import { postSettings } from '../../../common/api/ontimeApi';
|
||||
import { postSettings } from '../../../common/api/settings';
|
||||
import { logAxiosError } from '../../../common/api/utils';
|
||||
import useSettings from '../../../common/hooks-query/useSettings';
|
||||
import { isOnlyNumbers } from '../../../common/utils/regex';
|
||||
import ModalLoader from '../modal-loader/ModalLoader';
|
||||
|
||||
@@ -3,8 +3,8 @@ import { useForm } from 'react-hook-form';
|
||||
import { Input, Textarea } from '@chakra-ui/react';
|
||||
import { ProjectData } from 'ontime-types';
|
||||
|
||||
import { logAxiosError } from '../../../common/api/apiUtils';
|
||||
import { postProjectData } from '../../../common/api/projectDataApi';
|
||||
import { postProjectData } from '../../../common/api/project';
|
||||
import { logAxiosError } from '../../../common/api/utils';
|
||||
import useProjectData from '../../../common/hooks-query/useProjectData';
|
||||
import ModalLoader from '../modal-loader/ModalLoader';
|
||||
import { inputProps } from '../modalHelper';
|
||||
|
||||
@@ -3,8 +3,8 @@ import { useForm } from 'react-hook-form';
|
||||
import { Alert, AlertDescription, AlertIcon, AlertTitle, Input, Switch } from '@chakra-ui/react';
|
||||
import { ViewSettings } from 'ontime-types';
|
||||
|
||||
import { logAxiosError } from '../../../common/api/apiUtils';
|
||||
import { postViewSettings } from '../../../common/api/ontimeApi';
|
||||
import { logAxiosError } from '../../../common/api/utils';
|
||||
import { postViewSettings } from '../../../common/api/viewSettings';
|
||||
import { PopoverPickerRHF } from '../../../common/components/input/popover-picker/PopoverPicker';
|
||||
import useInfo from '../../../common/hooks-query/useInfo';
|
||||
import useViewSettings from '../../../common/hooks-query/useViewSettings';
|
||||
|
||||
@@ -2,7 +2,7 @@ import { MouseEvent } from 'react';
|
||||
import { isOntimeEvent, OntimeEvent, RundownCached } from 'ontime-types';
|
||||
import { create } from 'zustand';
|
||||
|
||||
import { RUNDOWN } from '../../common/api/apiConstants';
|
||||
import { RUNDOWN } from '../../common/api/constants';
|
||||
import { ontimeQueryClient } from '../../common/queryClient';
|
||||
import { isMacOS } from '../../common/utils/deviceUtils';
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { CustomFields, Message, OntimeEvent, ProjectData, Settings, SupportedEvent, ViewSettings } from 'ontime-types';
|
||||
import { millisToString, removeLeadingZero } from 'ontime-utils';
|
||||
|
||||
import { overrideStylesURL } from '../../../common/api/apiConstants';
|
||||
import { overrideStylesURL } from '../../../common/api/constants';
|
||||
import NavigationMenu from '../../../common/components/navigation-menu/NavigationMenu';
|
||||
import ProgressBar from '../../../common/components/progress-bar/ProgressBar';
|
||||
import Schedule from '../../../common/components/schedule/Schedule';
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useEffect } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { Settings, ViewSettings } from 'ontime-types';
|
||||
|
||||
import { overrideStylesURL } from '../../../common/api/apiConstants';
|
||||
import { overrideStylesURL } from '../../../common/api/constants';
|
||||
import NavigationMenu from '../../../common/components/navigation-menu/NavigationMenu';
|
||||
import { getClockOptions } from '../../../common/components/view-params-editor/constants';
|
||||
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useSearchParams } from 'react-router-dom';
|
||||
import { OntimeEvent, OntimeRundownEntry, Playback, Settings, SupportedEvent, ViewSettings } from 'ontime-types';
|
||||
import { millisToString, removeLeadingZero } from 'ontime-utils';
|
||||
|
||||
import { overrideStylesURL } from '../../../common/api/apiConstants';
|
||||
import { overrideStylesURL } from '../../../common/api/constants';
|
||||
import NavigationMenu from '../../../common/components/navigation-menu/NavigationMenu';
|
||||
import { getCountdownOptions } from '../../../common/components/view-params-editor/constants';
|
||||
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useEffect, useMemo, useState } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { CustomFields, Message, OntimeEvent, ViewSettings } from 'ontime-types';
|
||||
|
||||
import { overrideStylesURL } from '../../../common/api/apiConstants';
|
||||
import { overrideStylesURL } from '../../../common/api/constants';
|
||||
import NavigationMenu from '../../../common/components/navigation-menu/NavigationMenu';
|
||||
import { getLowerThirdOptions } from '../../../common/components/view-params-editor/constants';
|
||||
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useSearchParams } from 'react-router-dom';
|
||||
import { Playback, TimerMessage, TimerType, ViewSettings } from 'ontime-types';
|
||||
import { millisToString, removeLeadingZero, removeSeconds } from 'ontime-utils';
|
||||
|
||||
import { overrideStylesURL } from '../../../common/api/apiConstants';
|
||||
import { overrideStylesURL } from '../../../common/api/constants';
|
||||
import NavigationMenu from '../../../common/components/navigation-menu/NavigationMenu';
|
||||
import { MINIMAL_TIMER_OPTIONS } from '../../../common/components/view-params-editor/constants';
|
||||
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useSearchParams } from 'react-router-dom';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { CustomFields, Message, OntimeEvent, ProjectData, Settings, ViewSettings } from 'ontime-types';
|
||||
|
||||
import { overrideStylesURL } from '../../../common/api/apiConstants';
|
||||
import { overrideStylesURL } from '../../../common/api/constants';
|
||||
import NavigationMenu from '../../../common/components/navigation-menu/NavigationMenu';
|
||||
import Schedule from '../../../common/components/schedule/Schedule';
|
||||
import { ScheduleProvider } from '../../../common/components/schedule/ScheduleContext';
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { OntimeEvent, OntimeRundown, Settings, ViewSettings } from 'ontime-
|
||||
import { isOntimeEvent, Playback } from 'ontime-types';
|
||||
import { millisToString, removeSeconds } from 'ontime-utils';
|
||||
|
||||
import { overrideStylesURL } from '../../../common/api/apiConstants';
|
||||
import { overrideStylesURL } from '../../../common/api/constants';
|
||||
import NavigationMenu from '../../../common/components/navigation-menu/NavigationMenu';
|
||||
import { getStudioClockOptions } from '../../../common/components/view-params-editor/constants';
|
||||
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
} from 'ontime-types';
|
||||
import { millisToString, removeLeadingZero, removeSeconds } from 'ontime-utils';
|
||||
|
||||
import { overrideStylesURL } from '../../../common/api/apiConstants';
|
||||
import { overrideStylesURL } from '../../../common/api/constants';
|
||||
import MultiPartProgressBar from '../../../common/components/multi-part-progress-bar/MultiPartProgressBar';
|
||||
import NavigationMenu from '../../../common/components/navigation-menu/NavigationMenu';
|
||||
import TitleCard from '../../../common/components/title-card/TitleCard';
|
||||
|
||||
Reference in New Issue
Block a user