diff --git a/apps/client/src/common/api/ontimeApi.ts b/apps/client/src/common/api/ontimeApi.ts index ccd7388cb..d56f92dd6 100644 --- a/apps/client/src/common/api/ontimeApi.ts +++ b/apps/client/src/common/api/ontimeApi.ts @@ -306,21 +306,16 @@ export const postWorksheet = async (id: string, worksheet: string) => { /** * @description STEP 5 */ -export const postPreviewSheet = async (id: string, worksheet: string) => { - const response = await axios.post(`${ontimeURL}/sheet-preview`, { - id, - worksheet, - }); +export const postPreviewSheet = async (id: string, options: ExcelImportMap) => { + console.log(options); + const response = await axios.post(`${ontimeURL}/sheet/pull`, { id, options }); return response.data.data; }; /** * @description STEP 5 */ -export const postPushSheet = async (id: string, worksheet: string) => { - const response = await axios.post(`${ontimeURL}/sheet-push`, { - id, - worksheet, - }); +export const postPushSheet = async (id: string, options: ExcelImportMap) => { + const response = await axios.post(`${ontimeURL}/sheet-push`, { id, options }); return response.data.data; }; diff --git a/apps/client/src/features/modals/sheets-modal/SheetsModal.tsx b/apps/client/src/features/modals/sheets-modal/SheetsModal.tsx index 30248dbec..524994f92 100644 --- a/apps/client/src/features/modals/sheets-modal/SheetsModal.tsx +++ b/apps/client/src/features/modals/sheets-modal/SheetsModal.tsx @@ -18,6 +18,7 @@ import { } from '@chakra-ui/react'; import { useQueryClient } from '@tanstack/react-query'; import { OntimeRundown, ProjectData, UserFields } from 'ontime-types'; +import { defaultExcelImportMap, ExcelImportMap } from 'ontime-utils'; import { PROJECT_DATA, RUNDOWN, USERFIELDS } from '../../../common/api/apiConstants'; import { maybeAxiosError } from '../../../common/api/apiUtils'; @@ -37,6 +38,7 @@ import { userFieldsPlaceholder } from '../../../common/models/UserFields'; import { openLink } from '../../../common/utils/linkUtils'; import ModalLink from '../ModalLink'; import PreviewExcel from '../upload-modal/preview/PreviewExcel'; +import ExcelFileOptions from '../upload-modal/upload-options/ExcelFileOptions'; import Step from './Step'; @@ -58,6 +60,9 @@ export default function SheetsModal(props: SheetsModalProps) { const [worksheet, setWorksheet] = useState(''); const [worksheetOptions, setWorksheetOptions] = useState(new Array()); + const [direction, setDirection] = useState('none'); + const excelFileOptions = useRef(defaultExcelImportMap); + const fileInputRef = useRef(null); const [state, setState] = useState({ @@ -70,6 +75,7 @@ export default function SheetsModal(props: SheetsModalProps) { useEffect(() => { if (isOpen) { + setDirection('none'); testClientSecrect(); if (state.clientSecret.complet) testAuthentication(); if (state.authenticate.complet) testSheetId(); @@ -190,6 +196,7 @@ export default function SheetsModal(props: SheetsModalProps) { //SETP-4 Select Worksheet const testWorksheet = (value: string) => { + excelFileOptions.current.worksheet = value; setWorksheet(value); postWorksheet(id, worksheet) .then(() => { @@ -202,16 +209,32 @@ export default function SheetsModal(props: SheetsModalProps) { }; //SETP-5 Upload / Download + const updateExcelFileOptions = (field: T, value: ExcelImportMap[T]) => { + if (excelFileOptions.current[field] !== value) { + excelFileOptions.current = { ...excelFileOptions.current, [field]: value }; + } + }; + const handlePullData = () => { - postPreviewSheet(id, worksheet).then((data) => { - setProject(data.project); - setRundown(data.rundown); - setUserFields(data.userFields); - }); + postPreviewSheet(id, excelFileOptions.current) + .then((data) => { + setProject(data.project); + setRundown(data.rundown); + setUserFields(data.userFields); + }) + .catch((error) => { + const message = maybeAxiosError(error); + setDirection('none'); + setState({ ...state, pullPush: { complet: false, message } }); + }); }; const handlePushData = () => { - postPushSheet(id, worksheet); + postPushSheet(id, excelFileOptions.current).catch((error) => { + const message = maybeAxiosError(error); + setDirection('none'); + setState({ ...state, pullPush: { complet: false, message } }); + }); }; //GET preview @@ -266,119 +289,125 @@ export default function SheetsModal(props: SheetsModalProps) { {!rundown ? ( - <> - - -
- - -
-
- - -
- - -
-
- - - - setSheetId(event.target.value)} - /> - - - - - - - + +
+ + +
+ - -
- + +
+
+ + + + setSheetId(event.target.value)} + /> + + + + + + + + + +
+ + +
+
+ + ) ) : ( - {rundown && ( - + {rundown ? ( +
+ + +
+ ) : direction === 'up' ? ( +
+ + +
+ ) : direction === 'down' ? ( +
+ + +
+ ) : ( + <> )}
diff --git a/apps/server/src/controllers/ontimeController.ts b/apps/server/src/controllers/ontimeController.ts index 1291e2d5b..151b3d10a 100644 --- a/apps/server/src/controllers/ontimeController.ts +++ b/apps/server/src/controllers/ontimeController.ts @@ -554,10 +554,10 @@ export const postWorksheet = async (req, res) => { * @description STEP-5 POST download undown to sheet * @returns parsed result */ -export async function previewSheet(req, res) { +export async function pullSheet(req, res) { try { - const { id, worksheet } = req.body; - const data = await sheet.pull(id, worksheet); + const { id, options } = req.body; + const data = await sheet.pull(id, options); res.status(200).send(data); } catch (error) { res.status(500).send({ message: error.toString() }); @@ -569,8 +569,8 @@ export async function previewSheet(req, res) { */ export async function pushSheet(req, res) { try { - const { id, worksheet } = req.data; - await sheet.push(id, worksheet); + const { id, options } = req.body; + await sheet.push(id, options); res.status(200).send(); } catch (error) { res.status(500).send({ message: error.toString() }); diff --git a/apps/server/src/controllers/ontimeController.validate.ts b/apps/server/src/controllers/ontimeController.validate.ts index 753e3078f..809ce9cb7 100644 --- a/apps/server/src/controllers/ontimeController.validate.ts +++ b/apps/server/src/controllers/ontimeController.validate.ts @@ -171,3 +171,13 @@ export const validateWorksheet = [ next(); }, ]; + +export const validateSheetOptions = [ + body('id').exists().isString(), + // body('options').exists().isObject(), TODO: + (req, res, next) => { + const errors = validationResult(req); + if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() }); + next(); + }, +]; diff --git a/apps/server/src/routes/ontimeRouter.ts b/apps/server/src/routes/ontimeRouter.ts index 4f1280452..f758fbfec 100644 --- a/apps/server/src/routes/ontimeRouter.ts +++ b/apps/server/src/routes/ontimeRouter.ts @@ -23,7 +23,7 @@ import { postHTTP, getAuthenticationUrl, uploadSheetClientFile, - previewSheet, + pullSheet, pushSheet, postId, getAuthentication, @@ -41,6 +41,7 @@ import { validateOscSubscription, validateSheetid, validateWorksheet, + validateSheetOptions, } from '../controllers/ontimeController.validate.js'; import { projectSanitiser } from '../controllers/projectController.validate.js'; @@ -106,7 +107,6 @@ router.post('/http', validateHTTP, postHTTP); // create route between controller and '/ontime/new' endpoint router.post('/new', projectSanitiser, postNew); - //SETP-1 router.post('/sheet/clientsecrect', uploadFile, uploadSheetClientFile); router.get('/sheet/clientsecrect', uploadFile, getClientSecrect); @@ -122,7 +122,7 @@ router.post('/sheet/id', validateSheetid, postId); router.post('/sheet/worksheet', validateWorksheet, postId); //STEP-5 download and generate preview -router.post('/sheet-preview', validateWorksheet, previewSheet); +router.post('/sheet/pull', validateSheetOptions, pullSheet); //STEP-5 upload -router.post('/sheet-push', validateWorksheet, pushSheet); +router.post('/sheet-push', validateSheetOptions, pushSheet); diff --git a/apps/server/src/utils/sheetsAuth.ts b/apps/server/src/utils/sheetsAuth.ts index 2d82c16f0..fca1be6aa 100644 --- a/apps/server/src/utils/sheetsAuth.ts +++ b/apps/server/src/utils/sheetsAuth.ts @@ -13,6 +13,7 @@ import { ensureDirectory } from './fileManagement.js'; import { cellRequenstFromEvent, cellRequenstFromProjectData, getA1Notation } from './sheetUtils.js'; import { parseExcel } from './parser.js'; import { parseProject, parseRundown, parseUserFields } from './parserFunctions.js'; +import { ExcelImportMap } from 'ontime-utils'; type ResponseOK = { data: Partial; @@ -265,11 +266,11 @@ class Sheet { /** * @description SETP 5 - Upload the rundown to sheet * @param {string} id - id of the sheet https://docs.google.com/spreadsheets/d/[[spreadsheetId]]/edit#gid=0 - * @param {string} worksheet - the name of the worksheet containing ontime data + * @param {ExcelImportMap} options * @throws */ - public async push(id: string, worksheet: string) { - const { worksheetId, range } = await this.exist(id, worksheet); + public async push(id: string, options: ExcelImportMap) { + const { worksheetId, range } = await this.exist(id, options.worksheet); const rq = await sheets({ version: 'v4', auth: Sheet.client }).spreadsheets.values.get({ spreadsheetId: id, @@ -278,7 +279,7 @@ class Sheet { range: range, }); if (rq.status === 200) { - const { rundownMetadata, projectMetadata } = parseExcel(rq.data.values); + const { rundownMetadata, projectMetadata } = parseExcel(rq.data.values, options); const rundown = DataProvider.getRundown(); const projectData = DataProvider.getProjectData(); const titleRow = Object.values(rundownMetadata)[0]['row']; @@ -344,12 +345,12 @@ class Sheet { /** * @description SETP 5 - Downpload the rundown from sheet * @param {string} id - id of the sheet https://docs.google.com/spreadsheets/d/[[spreadsheetId]]/edit#gid=0 - * @param {string} worksheet - the name of the worksheet containing ontime data + * @param {ExcelImportMap} options * @returns {Promise>} * @throws */ - public async pull(id: string, worksheet: string): Promise> { - const { range } = await this.exist(id, worksheet); + public async pull(id: string, options: ExcelImportMap): Promise> { + const { range } = await this.exist(id, options.worksheet); const res: Partial = {}; @@ -362,12 +363,13 @@ class Sheet { if (rq.status === 200) { res.data = {}; - const dataFromSheet = parseExcel(rq.data.values); + const dataFromSheet = parseExcel(rq.data.values, options); res.data.rundown = parseRundown(dataFromSheet); if (res.data.rundown.length < 1) { throw new Error(`Sheet: Could not find data to import in the worksheet`); } - console.log(parseProject(dataFromSheet)); + console.log(dataFromSheet.project); + console.log(dataFromSheet.userFields); res.data.project = parseProject(dataFromSheet); res.data.userFields = parseUserFields(dataFromSheet); return res;