mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-20 22:49:18 +00:00
dont save sheet settings
This commit is contained in:
@@ -9,7 +9,6 @@ export const HTTP_SETTINGS = ['httpSettings'];
|
|||||||
export const APP_SETTINGS = ['appSettings'];
|
export const APP_SETTINGS = ['appSettings'];
|
||||||
export const VIEW_SETTINGS = ['viewSettings'];
|
export const VIEW_SETTINGS = ['viewSettings'];
|
||||||
export const RUNTIME = ['runtimeStore'];
|
export const RUNTIME = ['runtimeStore'];
|
||||||
export const SHEET = ['sheet'];
|
|
||||||
export const SHEET_STATE = ['sheetState'];
|
export const SHEET_STATE = ['sheetState'];
|
||||||
|
|
||||||
const location = window.location;
|
const location = window.location;
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import {
|
|||||||
OscSubscription,
|
OscSubscription,
|
||||||
ProjectData,
|
ProjectData,
|
||||||
Settings,
|
Settings,
|
||||||
Sheet,
|
|
||||||
SheetState,
|
SheetState,
|
||||||
UserFields,
|
UserFields,
|
||||||
ViewSettings,
|
ViewSettings,
|
||||||
@@ -270,39 +269,28 @@ export const getSheetsAuthUrl = async () => {
|
|||||||
return res.data;
|
return res.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const postPreviewSheet = async () => {
|
export const postPreviewSheet = async (id: string, worksheet: string) => {
|
||||||
const response = await axios.post(`${ontimeURL}/sheet-preview`);
|
const response = await axios.post(`${ontimeURL}/sheet-preview`, { id, worksheet });
|
||||||
return response.data.data;
|
return response.data.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const postPushSheet = async () => {
|
export const postPushSheet = async (id: string, worksheet: string) => {
|
||||||
const response = await axios.post(`${ontimeURL}/sheet-push`);
|
const response = await axios.post(`${ontimeURL}/sheet-push`, { id, worksheet });
|
||||||
return response.data.data;
|
return response.data.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @description HTTP request to retrieve sheets settings
|
|
||||||
* @return {Promise}
|
|
||||||
*/
|
|
||||||
export async function getSheetSettings(): Promise<Sheet> {
|
|
||||||
const res = await axios.get(`${ontimeURL}/sheet-settings`);
|
|
||||||
return res.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description HTTP request to mutate sheets settings
|
|
||||||
* @return {Promise}
|
|
||||||
*/
|
|
||||||
export async function postSheetSettings(data: Sheet): Promise<Sheet> {
|
|
||||||
const res = await axios.post(`${ontimeURL}/sheet-settings`, data);
|
|
||||||
return res.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description HTTP request to retrieve sheets state
|
* @description HTTP request to retrieve sheets state
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
export async function getSheetState(): Promise<SheetState> {
|
export const getSheetState = async ({ queryKey }): Promise<SheetState> => {
|
||||||
const res = await axios.get(`${ontimeURL}/sheet-state`);
|
const [_key, id, worksheet] = queryKey;
|
||||||
|
console.log(queryKey);
|
||||||
|
|
||||||
|
const res = await axios.post(`${ontimeURL}/sheet-state`, {
|
||||||
|
id: '',
|
||||||
|
worksheet: '',
|
||||||
|
});
|
||||||
|
console.log(res.data);
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
|
||||||
|
|
||||||
import { queryRefetchIntervalSlow } from '../../ontimeConfig';
|
|
||||||
import { SHEET } from '../api/apiConstants';
|
|
||||||
import { getSheetSettings } from '../api/ontimeApi';
|
|
||||||
|
|
||||||
const sheetPlaceholder = { worksheet: null, id: null };
|
|
||||||
|
|
||||||
export default function useSheet() {
|
|
||||||
const { data, status, isFetching, isError, refetch } = useQuery({
|
|
||||||
queryKey: SHEET,
|
|
||||||
queryFn: getSheetSettings,
|
|
||||||
placeholderData: sheetPlaceholder,
|
|
||||||
retry: 5,
|
|
||||||
retryDelay: (attempt) => attempt * 2500,
|
|
||||||
refetchInterval: queryRefetchIntervalSlow,
|
|
||||||
networkMode: 'always',
|
|
||||||
});
|
|
||||||
|
|
||||||
return { data, status, isFetching, isError, refetch };
|
|
||||||
}
|
|
||||||
@@ -3,9 +3,9 @@ import { useQuery } from '@tanstack/react-query';
|
|||||||
import { SHEET_STATE } from '../api/apiConstants';
|
import { SHEET_STATE } from '../api/apiConstants';
|
||||||
import { getSheetState } from '../api/ontimeApi';
|
import { getSheetState } from '../api/ontimeApi';
|
||||||
|
|
||||||
export default function useSheetState() {
|
export default function useSheetState(id, worksheet) {
|
||||||
const { data, status, isFetching, isError, refetch } = useQuery({
|
const { data, status, isFetching, isError, refetch } = useQuery({
|
||||||
queryKey: SHEET_STATE,
|
queryKey: [SHEET_STATE, { id, worksheet }],
|
||||||
queryFn: getSheetState,
|
queryFn: getSheetState,
|
||||||
placeholderData: null,
|
placeholderData: null,
|
||||||
enabled: false,
|
enabled: false,
|
||||||
|
|||||||
@@ -15,20 +15,19 @@ import {
|
|||||||
ModalOverlay,
|
ModalOverlay,
|
||||||
Select,
|
Select,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { useQueryClient } from '@tanstack/react-query';
|
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
import { OntimeRundown, ProjectData, UserFields } from 'ontime-types';
|
import { OntimeRundown, ProjectData, UserFields } from 'ontime-types';
|
||||||
|
|
||||||
import { PROJECT_DATA, RUNDOWN, USERFIELDS } from '../../../common/api/apiConstants';
|
import { PROJECT_DATA, RUNDOWN, SHEET_STATE, USERFIELDS } from '../../../common/api/apiConstants';
|
||||||
import { maybeAxiosError } from '../../../common/api/apiUtils';
|
import { maybeAxiosError } from '../../../common/api/apiUtils';
|
||||||
import {
|
import {
|
||||||
getSheetsAuthUrl,
|
getSheetsAuthUrl,
|
||||||
|
getSheetState,
|
||||||
patchData,
|
patchData,
|
||||||
postPreviewSheet,
|
postPreviewSheet,
|
||||||
postPushSheet,
|
postPushSheet,
|
||||||
postSheetSettings,
|
|
||||||
uploadSheetClientFile,
|
uploadSheetClientFile,
|
||||||
} from '../../../common/api/ontimeApi';
|
} from '../../../common/api/ontimeApi';
|
||||||
import useSheet from '../../../common/hooks-query/useSheet';
|
|
||||||
import useSheetState from '../../../common/hooks-query/useSheetState';
|
import useSheetState from '../../../common/hooks-query/useSheetState';
|
||||||
import { projectDataPlaceholder } from '../../../common/models/ProjectData';
|
import { projectDataPlaceholder } from '../../../common/models/ProjectData';
|
||||||
import { userFieldsPlaceholder } from '../../../common/models/UserFields';
|
import { userFieldsPlaceholder } from '../../../common/models/UserFields';
|
||||||
@@ -46,8 +45,6 @@ export default function SheetsModal(props: SheetsModalProps) {
|
|||||||
const { isOpen, onClose } = props;
|
const { isOpen, onClose } = props;
|
||||||
|
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const { data } = useSheet();
|
|
||||||
const { data: sheetState, refetch } = useSheetState();
|
|
||||||
|
|
||||||
const [rundown, setRundown] = useState<OntimeRundown | null>(null);
|
const [rundown, setRundown] = useState<OntimeRundown | null>(null);
|
||||||
const [userFields, setUserFields] = useState<UserFields | null>(null);
|
const [userFields, setUserFields] = useState<UserFields | null>(null);
|
||||||
@@ -57,6 +54,19 @@ export default function SheetsModal(props: SheetsModalProps) {
|
|||||||
const sheetid = useRef<HTMLInputElement>(null);
|
const sheetid = useRef<HTMLInputElement>(null);
|
||||||
const worksheet = useRef<HTMLSelectElement>(null);
|
const worksheet = useRef<HTMLSelectElement>(null);
|
||||||
|
|
||||||
|
const { data: sheetState, refetch } = useQuery({
|
||||||
|
queryKey: [SHEET_STATE, sheetid, sheetid],
|
||||||
|
queryFn: getSheetState,
|
||||||
|
placeholderData: null,
|
||||||
|
enabled: false,
|
||||||
|
networkMode: 'always',
|
||||||
|
});
|
||||||
|
|
||||||
|
const onChange = () => {
|
||||||
|
if (sheetid.current?.value && sheetid.current?.value.length > 43) {
|
||||||
|
refetch();
|
||||||
|
}
|
||||||
|
};
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setRundown(null);
|
setRundown(null);
|
||||||
setProject(null);
|
setProject(null);
|
||||||
@@ -80,47 +90,18 @@ export default function SheetsModal(props: SheetsModalProps) {
|
|||||||
// TODO: show this in the modal
|
// TODO: show this in the modal
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
_onChange();
|
refetch();
|
||||||
};
|
};
|
||||||
|
|
||||||
const _onChange = () => refetch();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!data) {
|
if (isOpen) {
|
||||||
return;
|
refetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedSheetIdChanged = sheetid.current?.value !== data.id;
|
|
||||||
const selectedWorksheetChanged = worksheet.current?.value !== data.worksheet && worksheet.current?.value;
|
|
||||||
if (selectedSheetIdChanged || selectedWorksheetChanged) {
|
|
||||||
_onChange();
|
|
||||||
if (sheetid.current) {
|
|
||||||
sheetid.current.value = data.id;
|
|
||||||
}
|
|
||||||
if (worksheet.current) {
|
|
||||||
worksheet.current.value = data.worksheet;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [data]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
return () => {
|
return () => {
|
||||||
// Alex: This function will be run when the component unmounts
|
// Alex: This function will be run when the component unmounts
|
||||||
console.log('Component is unmounting');
|
console.log('Component is unmounting');
|
||||||
};
|
};
|
||||||
}, []);
|
}, [isOpen]);
|
||||||
|
|
||||||
const handleSave = () => {
|
|
||||||
postSheetSettings({ id: sheetid.current?.value ?? '', worksheet: worksheet.current?.value ?? '' }).then((data) => {
|
|
||||||
_onChange();
|
|
||||||
if (sheetid.current) {
|
|
||||||
sheetid.current.value = data.id;
|
|
||||||
}
|
|
||||||
if (worksheet.current) {
|
|
||||||
worksheet.current.value = data.worksheet;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleAuthenticate = () => {
|
const handleAuthenticate = () => {
|
||||||
getSheetsAuthUrl().then((data) => {
|
getSheetsAuthUrl().then((data) => {
|
||||||
@@ -132,7 +113,7 @@ export default function SheetsModal(props: SheetsModalProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handlePullData = () => {
|
const handlePullData = () => {
|
||||||
postPreviewSheet().then((data) => {
|
postPreviewSheet(sheetid.current?.value ?? '', worksheet.current?.value ?? '').then((data) => {
|
||||||
setProject(data.project);
|
setProject(data.project);
|
||||||
setRundown(data.rundown);
|
setRundown(data.rundown);
|
||||||
setUserFields(data.userFields);
|
setUserFields(data.userFields);
|
||||||
@@ -140,7 +121,7 @@ export default function SheetsModal(props: SheetsModalProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handlePushData = () => {
|
const handlePushData = () => {
|
||||||
postPushSheet();
|
postPushSheet(sheetid.current?.value ?? '', worksheet.current?.value ?? '');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFinalise = async () => {
|
const handleFinalise = async () => {
|
||||||
@@ -236,6 +217,7 @@ export default function SheetsModal(props: SheetsModalProps) {
|
|||||||
ref={sheetid}
|
ref={sheetid}
|
||||||
id='sheetid'
|
id='sheetid'
|
||||||
size='sm'
|
size='sm'
|
||||||
|
onChange={onChange}
|
||||||
variant='ontime-filled-on-light'
|
variant='ontime-filled-on-light'
|
||||||
disabled={!sheetState?.auth}
|
disabled={!sheetState?.auth}
|
||||||
/>
|
/>
|
||||||
@@ -245,7 +227,7 @@ export default function SheetsModal(props: SheetsModalProps) {
|
|||||||
<Step
|
<Step
|
||||||
step={4}
|
step={4}
|
||||||
title='Select Worksheet to import'
|
title='Select Worksheet to import'
|
||||||
completed={Boolean(sheetState?.auth)}
|
completed={Boolean(sheetState?.worksheet)}
|
||||||
disabled={!sheetState?.worksheetOptions}
|
disabled={!sheetState?.worksheetOptions}
|
||||||
>
|
>
|
||||||
<label htmlFor='worksheet'>
|
<label htmlFor='worksheet'>
|
||||||
@@ -291,11 +273,6 @@ export default function SheetsModal(props: SheetsModalProps) {
|
|||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button variant='ontime-ghost-on-light'>Reset</Button>
|
<Button variant='ontime-ghost-on-light'>Reset</Button>
|
||||||
{!rundown && (
|
|
||||||
<Button variant='ontime-filled' padding='0 2em' onClick={handleSave}>
|
|
||||||
Save
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{rundown && (
|
{rundown && (
|
||||||
<Button variant='ontime-filled' padding='0 2em' onClick={handleFinalise}>
|
<Button variant='ontime-filled' padding='0 2em' onClick={handleFinalise}>
|
||||||
Import
|
Import
|
||||||
|
|||||||
@@ -525,9 +525,10 @@ export async function sheetAuthUrl(req, res) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Get sheet state
|
* @description Get sheet state
|
||||||
* @method GET
|
* @method POST
|
||||||
*/
|
*/
|
||||||
export const getSheetState = async (req, res) => {
|
export const getSheetState = async (req, res) => {
|
||||||
const { id, worksheet } = req.data;
|
console.log('getstate', req.body);
|
||||||
|
const { id, worksheet } = req.body;
|
||||||
res.status(200).send(await Sheet.getSheetState(id, worksheet));
|
res.status(200).send(await Sheet.getSheetState(id, worksheet));
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -154,10 +154,9 @@ export const validatePatchProjectFile = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
//TODO: is thise correct
|
//TODO: is thise correct
|
||||||
export const validateSheetPreview = [
|
export const validateSheetParams = [
|
||||||
body('sheetid').isString().optional({ nullable: false }),
|
body('sheetid').isString().optional({ nullable: false }),
|
||||||
body('worksheet').isString().optional({ nullable: false }),
|
body('worksheet').isString().optional({ nullable: false }),
|
||||||
body('options').isObject().optional({ nullable: true }),
|
|
||||||
(req, res, next) => {
|
(req, res, next) => {
|
||||||
const errors = validationResult(req);
|
const errors = validationResult(req);
|
||||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import {
|
|||||||
validateOSC,
|
validateOSC,
|
||||||
validatePatchProjectFile,
|
validatePatchProjectFile,
|
||||||
validateSettings,
|
validateSettings,
|
||||||
validateSheetPreview,
|
validateSheetParams,
|
||||||
validateUserFields,
|
validateUserFields,
|
||||||
viewValidator,
|
viewValidator,
|
||||||
validateHTTP,
|
validateHTTP,
|
||||||
@@ -110,10 +110,10 @@ router.post('/sheet-clientsecrect', uploadFile, uploadSheetClientFile);
|
|||||||
router.get('/sheet-authurl', sheetAuthUrl);
|
router.get('/sheet-authurl', sheetAuthUrl);
|
||||||
|
|
||||||
// create route between controller and '/ontime/preview-sheet' endpoint
|
// create route between controller and '/ontime/preview-sheet' endpoint
|
||||||
router.post('/sheet-preview', validateSheetPreview, previewSheet);
|
router.post('/sheet-preview', validateSheetParams, previewSheet);
|
||||||
|
|
||||||
// create route between controller and '/ontime/preview-sheet' endpoint
|
// create route between controller and '/ontime/preview-sheet' endpoint
|
||||||
router.post('/sheet-push', pushSheet);
|
router.post('/sheet-push', validateSheetParams, pushSheet);
|
||||||
|
|
||||||
// create route between controller and '/ontime/sheet-state' endpoint
|
// create route between controller and '/ontime/sheet-state' endpoint
|
||||||
router.get('/sheet-state', getSheetState);
|
router.post('/sheet-state', validateSheetParams, getSheetState);
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class sheet {
|
|||||||
constructor() {
|
constructor() {
|
||||||
const appDataPath = getAppDataPath();
|
const appDataPath = getAppDataPath();
|
||||||
if (appDataPath === '') {
|
if (appDataPath === '') {
|
||||||
throw new Error('Could not resolve public folder for platform');
|
throw new Error('Could not resolve sheet folser');
|
||||||
}
|
}
|
||||||
this.sheetsFolder = join(appDataPath, 'sheets');
|
this.sheetsFolder = join(appDataPath, 'sheets');
|
||||||
this.clientSecretFile = join(this.sheetsFolder, 'client_secret.json');
|
this.clientSecretFile = join(this.sheetsFolder, 'client_secret.json');
|
||||||
@@ -42,7 +42,7 @@ class sheet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async getSheetState(id: string, worksheet: string): Promise<SheetState> {
|
public async getSheetState(id: string, worksheet: string): Promise<SheetState> {
|
||||||
const ret: SheetState = {
|
const state: SheetState = {
|
||||||
secret: false,
|
secret: false,
|
||||||
auth: false,
|
auth: false,
|
||||||
id: false,
|
id: false,
|
||||||
@@ -50,22 +50,10 @@ class sheet {
|
|||||||
worksheetOptions: [],
|
worksheetOptions: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!sheet.clientSecret) {
|
state.secret = sheet.clientSecret !== null;
|
||||||
return ret;
|
state.auth = sheet.client !== null;
|
||||||
}
|
|
||||||
ret.secret = true;
|
if (id != '' && state.auth) {
|
||||||
if (!sheet.client) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
ret.auth = await this.refreshToken();
|
|
||||||
} catch (err) {
|
|
||||||
logger.error(LogOrigin.Server, `Sheet: Faild to refresh token ${err}`);
|
|
||||||
}
|
|
||||||
if (!ret.auth) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
if (id != '') {
|
|
||||||
const spreadsheets = await sheets({ version: 'v4', auth: sheet.client })
|
const spreadsheets = await sheets({ version: 'v4', auth: sheet.client })
|
||||||
.spreadsheets.get({
|
.spreadsheets.get({
|
||||||
spreadsheetId: id,
|
spreadsheetId: id,
|
||||||
@@ -75,16 +63,13 @@ class sheet {
|
|||||||
logger.error(LogOrigin.Server, `Sheet: faild to load sheet ${err}`);
|
logger.error(LogOrigin.Server, `Sheet: faild to load sheet ${err}`);
|
||||||
});
|
});
|
||||||
if (!spreadsheets || spreadsheets.status != 200) {
|
if (!spreadsheets || spreadsheets.status != 200) {
|
||||||
return ret;
|
return state;
|
||||||
}
|
}
|
||||||
ret.id = true;
|
state.id = true;
|
||||||
ret.worksheetOptions = spreadsheets.data.sheets.map((i) => i.properties.title);
|
state.worksheetOptions = spreadsheets.data.sheets.map((i) => i.properties.title);
|
||||||
if (ret.worksheetOptions.indexOf(worksheet) < 0) {
|
state.worksheet = state.worksheetOptions.indexOf(worksheet) >= 0;
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
ret.worksheet = true;
|
|
||||||
}
|
}
|
||||||
return ret;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -248,23 +233,6 @@ class sheet {
|
|||||||
sheet.clientSecret = secrets;
|
sheet.clientSecret = secrets;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* refresh the client token
|
|
||||||
* @returns {Promise<boolean>}
|
|
||||||
*/
|
|
||||||
async refreshToken(): Promise<boolean> {
|
|
||||||
if (!sheet.client?.credentials?.refresh_token) return false;
|
|
||||||
try {
|
|
||||||
const response = await sheet.client.refreshAccessToken();
|
|
||||||
if (response?.credentials) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (_) {
|
|
||||||
logger.info(LogOrigin.Server, 'Sheets token expired');
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private authServerTimeout;
|
private authServerTimeout;
|
||||||
/**
|
/**
|
||||||
* create local Auth Server
|
* create local Auth Server
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
export type Sheet = {
|
|
||||||
worksheet: string | null;
|
|
||||||
id: string | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type SheetState = {
|
export type SheetState = {
|
||||||
secret: boolean;
|
secret: boolean;
|
||||||
auth: boolean;
|
auth: boolean;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export type { OSCSettings, OscSubscription, OscSubscriptionOptions } from './def
|
|||||||
export type { HttpSettings, HttpSubscription, HttpSubscriptionOptions } from './definitions/core/HttpSettings.type.js';
|
export type { HttpSettings, HttpSubscription, HttpSubscriptionOptions } from './definitions/core/HttpSettings.type.js';
|
||||||
|
|
||||||
// ---> Sheet
|
// ---> Sheet
|
||||||
export type { Sheet, SheetState } from './definitions/core/Sheet.type.js';
|
export type { SheetState } from './definitions/core/Sheet.type.js';
|
||||||
|
|
||||||
// SERVER RESPONSES
|
// SERVER RESPONSES
|
||||||
export type { NetworkInterface, GetInfo } from './api/ontime-controller/BackendResponse.type.js';
|
export type { NetworkInterface, GetInfo } from './api/ontime-controller/BackendResponse.type.js';
|
||||||
|
|||||||
Reference in New Issue
Block a user