mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-15 04:13:47 +00:00
refactor: remove userFields (#791)
* refactor: process custom fields on cache generate * refactor: remove userFields
This commit is contained in:
@@ -9,7 +9,6 @@ export const PROJECT_LIST = ['projectList'];
|
||||
export const RUNDOWN = ['rundown'];
|
||||
export const RUNTIME = ['runtimeStore'];
|
||||
export const SHEET_STATE = ['sheetState'];
|
||||
export const USERFIELDS = ['userFields'];
|
||||
export const CUSTOM_FIELDS = ['customFields'];
|
||||
export const VIEW_SETTINGS = ['viewSettings'];
|
||||
|
||||
|
||||
@@ -14,10 +14,9 @@ import {
|
||||
ProjectData,
|
||||
ProjectFileListResponse,
|
||||
Settings,
|
||||
UserFields,
|
||||
ViewSettings,
|
||||
} from 'ontime-types';
|
||||
import { ExcelImportMap } from 'ontime-utils';
|
||||
import { ImportMap } from 'ontime-utils';
|
||||
|
||||
import { apiRepoLatest } from '../../externals';
|
||||
import fileDownload from '../utils/fileDownload';
|
||||
@@ -84,23 +83,6 @@ export async function postAliases(data: Alias[]) {
|
||||
return axios.post(`${ontimeURL}/aliases`, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to retrieve user fields
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function getUserFields(): Promise<UserFields> {
|
||||
const res = await axios.get(`${ontimeURL}/userfields`);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to mutate user fields
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function postUserFields(data: UserFields) {
|
||||
return axios.post(`${ontimeURL}/userfields`, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description HTTP request to retrieve osc settings
|
||||
* @return {Promise}
|
||||
@@ -189,40 +171,35 @@ export const uploadProjectFile = async (
|
||||
* @description Make patch changes to the objects in the db
|
||||
* @return {Promise}
|
||||
*/
|
||||
export async function patchData(patchDb: Partial<DatabaseModel>) {
|
||||
const response = await axios.patch(`${ontimeURL}/db`, patchDb);
|
||||
return response;
|
||||
export async function patchData(patchDb: Partial<DatabaseModel>): Promise<void> {
|
||||
return await axios.patch(`${ontimeURL}/db`, patchDb);
|
||||
}
|
||||
|
||||
type PostPreviewExcelResponse = {
|
||||
type PreviewSpreadsheetResponse = {
|
||||
rundown: OntimeRundown;
|
||||
userFields: UserFields;
|
||||
customFields: CustomFields;
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Make patch changes to the objects in the db
|
||||
* @return {Promise} - returns parsed rundown and userfields
|
||||
* @return {Promise} - returns parsed rundown and customFields
|
||||
*/
|
||||
export async function postPreviewExcel(file: File, setProgress: (value: number) => void, options?: ExcelImportMap) {
|
||||
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<PostPreviewExcelResponse> = await axios.post(
|
||||
`${ontimeURL}/preview-spreadsheet`,
|
||||
const response: AxiosResponse<PreviewSpreadsheetResponse> = await axios.post(
|
||||
`${ontimeURL}/spreadsheet/preview`,
|
||||
formData,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
onUploadProgress: (progressEvent) => {
|
||||
const complete = progressEvent?.total ? Math.round((progressEvent.loaded * 100) / progressEvent.total) : 0;
|
||||
setProgress(complete);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
return response;
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export type HasUpdate = {
|
||||
@@ -303,10 +280,10 @@ export const revokeAuthentication = async (): Promise<{ authenticated: Authentic
|
||||
*/
|
||||
export const previewRundown = async (
|
||||
sheetId: string,
|
||||
options: ExcelImportMap,
|
||||
options: ImportMap,
|
||||
): Promise<{
|
||||
rundown: OntimeRundown;
|
||||
userFields: UserFields;
|
||||
customFields: CustomFields;
|
||||
}> => {
|
||||
const response = await axios.post(`${ontimeURL}/sheet/${sheetId}/read`, { options });
|
||||
return response.data;
|
||||
@@ -315,7 +292,7 @@ export const previewRundown = async (
|
||||
/**
|
||||
* @description HTTP request to upload the rundown to a google sheet
|
||||
*/
|
||||
export const uploadRundown = async (sheetId: string, options: ExcelImportMap): Promise<void> => {
|
||||
export const uploadRundown = async (sheetId: string, options: ImportMap): Promise<void> => {
|
||||
const response = await axios.post(`${ontimeURL}/sheet/${sheetId}/write`, { options });
|
||||
return response.data;
|
||||
};
|
||||
@@ -371,11 +348,17 @@ export async function createProject(
|
||||
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,
|
||||
@@ -383,6 +366,9 @@ export async function postCustomField(newField: CustomField): Promise<CustomFiel
|
||||
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,
|
||||
@@ -390,6 +376,9 @@ export async function editCustomField(label: CustomFieldLabel, newField: CustomF
|
||||
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,9 @@
|
||||
.tag {
|
||||
font-size: calc(1rem - 3px);
|
||||
letter-spacing: 0.5px;
|
||||
background-color: $gray-900;
|
||||
color: $ui-white;
|
||||
border-radius: 2px;
|
||||
padding: 0 0.25rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
import style from './Tag.module.scss';
|
||||
|
||||
export default function Tag({ children }: { children: ReactNode }) {
|
||||
return <span className={style.tag}>{children}</span>;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { queryRefetchInterval } from '../../ontimeConfig';
|
||||
import { USERFIELDS } from '../api/apiConstants';
|
||||
import { getUserFields } from '../api/ontimeApi';
|
||||
import { userFieldsPlaceholder } from '../models/UserFields';
|
||||
|
||||
export default function useUserFields() {
|
||||
const { data, status, isFetching, isError, refetch } = useQuery({
|
||||
queryKey: USERFIELDS,
|
||||
queryFn: getUserFields,
|
||||
placeholderData: userFieldsPlaceholder,
|
||||
retry: 5,
|
||||
retryDelay: (attempt) => attempt * 2500,
|
||||
refetchInterval: queryRefetchInterval,
|
||||
networkMode: 'always',
|
||||
});
|
||||
|
||||
return { data, status, isFetching, isError, refetch };
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { UserFields } from 'ontime-types';
|
||||
|
||||
export const userFieldsPlaceholder: UserFields = {
|
||||
user0: '',
|
||||
user1: '',
|
||||
user2: '',
|
||||
user3: '',
|
||||
user4: '',
|
||||
user5: '',
|
||||
user6: '',
|
||||
user7: '',
|
||||
user8: '',
|
||||
user9: '',
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import { EndAction, OntimeEvent, SupportedEvent, TimerType } from 'ontime-types';
|
||||
import { EndAction, EventCustomFields, OntimeEvent, SupportedEvent, TimerType } from 'ontime-types';
|
||||
|
||||
import { cloneEvent } from '../eventsManager';
|
||||
|
||||
@@ -21,18 +21,11 @@ describe('cloneEvent()', () => {
|
||||
skip: false,
|
||||
colour: 'F00',
|
||||
revision: 10,
|
||||
user0: 'user0',
|
||||
user1: 'user1',
|
||||
user2: 'user2',
|
||||
user3: 'user3',
|
||||
user4: 'user4',
|
||||
user5: 'user5',
|
||||
user6: 'user6',
|
||||
user7: 'user7',
|
||||
user8: 'user8',
|
||||
user9: 'user9',
|
||||
timeWarning: 120000,
|
||||
timeDanger: 60000,
|
||||
custom: {
|
||||
lighting: { value: '3' },
|
||||
} as EventCustomFields,
|
||||
} as OntimeEvent;
|
||||
|
||||
const cloned = cloneEvent(original);
|
||||
@@ -55,5 +48,6 @@ describe('cloneEvent()', () => {
|
||||
expect(cloned.revision).toBe(0);
|
||||
expect(cloned.timeWarning).toBe(original.timeWarning);
|
||||
expect(cloned.timeDanger).toBe(original.timeDanger);
|
||||
expect(cloned.custom).toStrictEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,22 +6,7 @@ import { OntimeEvent, SupportedEvent } from 'ontime-types';
|
||||
* @param {string} [after]
|
||||
* @return {OntimeEvent} clean event
|
||||
*/
|
||||
type ClonedEvent = Omit<
|
||||
OntimeEvent,
|
||||
| 'id'
|
||||
| 'cue'
|
||||
| 'user0'
|
||||
| 'user1'
|
||||
| 'user2'
|
||||
| 'user3'
|
||||
| 'user4'
|
||||
| 'user5'
|
||||
| 'user6'
|
||||
| 'user7'
|
||||
| 'user8'
|
||||
| 'user9'
|
||||
| 'custom'
|
||||
>;
|
||||
type ClonedEvent = Omit<OntimeEvent, 'id' | 'cue'>;
|
||||
export const cloneEvent = (event: OntimeEvent, after?: string): ClonedEvent => {
|
||||
return {
|
||||
type: SupportedEvent.Event,
|
||||
@@ -43,5 +28,6 @@ export const cloneEvent = (event: OntimeEvent, after?: string): ClonedEvent => {
|
||||
revision: 0,
|
||||
timeWarning: event.timeWarning,
|
||||
timeDanger: event.timeDanger,
|
||||
custom: {},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Collection of rules for pre-validating a spreadsheet
|
||||
* @param file
|
||||
*/
|
||||
export function validateSpreadsheetImport(file: File) {
|
||||
if (!isExcelFile(file)) {
|
||||
throw new Error('Unknown file type');
|
||||
}
|
||||
|
||||
// Check if file is empty
|
||||
if (file.size === 0) {
|
||||
throw new Error('File is empty');
|
||||
}
|
||||
|
||||
// Limit file size of an excel file to around 10MB
|
||||
if (file.size > 10_000_000) {
|
||||
throw new Error('File size limit (10MB) exceeded');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collection of rules for pre-validating a project file
|
||||
* @param file
|
||||
*/
|
||||
export function validateProjectFile(file: File) {
|
||||
if (!isOntimeFile(file)) {
|
||||
throw new Error('Unknown file type');
|
||||
}
|
||||
|
||||
// Check if file is empty
|
||||
if (file.size === 0) {
|
||||
throw new Error('File is empty');
|
||||
}
|
||||
|
||||
// Limit file size of a project file to around 1MB
|
||||
if (file.size > 1_000_000) {
|
||||
throw new Error('File size limit (10MB) exceeded');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a file according to the app upload contract
|
||||
* @throws
|
||||
* @param file
|
||||
*/
|
||||
export function validateFile(file: File) {
|
||||
if (!file) {
|
||||
throw new Error('No file to upload');
|
||||
}
|
||||
|
||||
// Check if file is empty
|
||||
if (file.size === 0) {
|
||||
throw new Error('File is empty');
|
||||
}
|
||||
|
||||
// Limit file size of a project file to around 1MB
|
||||
if (file.name.endsWith('.json') && file.size > 1_000_000) {
|
||||
throw new Error('File size limit (1MB) exceeded');
|
||||
}
|
||||
|
||||
// Limit file size of an excel file to around 10MB
|
||||
if (file.name.endsWith('.xlsx') && file.size > 10_000_000) {
|
||||
throw new Error('File size limit (10MB) exceeded');
|
||||
}
|
||||
|
||||
// Check file extension
|
||||
if (!file.name.endsWith('.xlsx') && !file.name.endsWith('.json')) {
|
||||
throw new Error('Unhandled file type');
|
||||
}
|
||||
}
|
||||
|
||||
export function isExcelFile(file: File | null) {
|
||||
return file?.name.endsWith('.xlsx');
|
||||
}
|
||||
|
||||
export function isOntimeFile(file: File | null) {
|
||||
return file?.name.endsWith('.json');
|
||||
}
|
||||
Reference in New Issue
Block a user