diff --git a/apps/client/src/common/api/ontimeApi.ts b/apps/client/src/common/api/ontimeApi.ts index 389df3522..9794a1c03 100644 --- a/apps/client/src/common/api/ontimeApi.ts +++ b/apps/client/src/common/api/ontimeApi.ts @@ -80,6 +80,14 @@ export async function postAliases(data: Alias[]) { return axios.post(`${ontimeURL}/aliases`, data); } +/** + * @description HTTP request to update aliases + * @return {Promise} + */ +export async function updateAliases(data: Partial) { + return axios.put(`${ontimeURL}/aliases`, data); +} + /** * @description HTTP request to retrieve user fields * @return {Promise} diff --git a/apps/client/src/features/app-settings/panel/url-alias-panel/UrlAliasList.tsx b/apps/client/src/features/app-settings/panel/url-alias-panel/UrlAliasList.tsx index b7fedaa23..14983de17 100644 --- a/apps/client/src/features/app-settings/panel/url-alias-panel/UrlAliasList.tsx +++ b/apps/client/src/features/app-settings/panel/url-alias-panel/UrlAliasList.tsx @@ -13,7 +13,7 @@ type Aliases = { }; export default function UrlAliasList() { - const { data, status, isFetching } = useAliases(); + const { data, status, isFetching, refetch } = useAliases(); // const { emitError } = useEmitLog(); const { @@ -43,6 +43,10 @@ export default function UrlAliasList() { } }, [data, reset]); + const handleRefetch = async () => { + await refetch(); + }; + // const onReset = () => { // reset({ aliases: data }); // }; @@ -62,9 +66,6 @@ export default function UrlAliasList() { const disableInputs = status === 'pending'; // const hasTooManyOptions = fields.length >= 20; - console.log('bolama'); - console.log({ isFetching }); - if (isFetching) { return ; } @@ -86,6 +87,7 @@ export default function UrlAliasList() { alias={alias.alias} enabled={alias.enabled} pathAndParams={alias.pathAndParams} + onRefetch={handleRefetch} key={alias.id} /> ); diff --git a/apps/client/src/features/app-settings/panel/url-alias-panel/UrlAliasListItem.tsx b/apps/client/src/features/app-settings/panel/url-alias-panel/UrlAliasListItem.tsx index 2068afadd..2f5d7d3fa 100644 --- a/apps/client/src/features/app-settings/panel/url-alias-panel/UrlAliasListItem.tsx +++ b/apps/client/src/features/app-settings/panel/url-alias-panel/UrlAliasListItem.tsx @@ -1,82 +1,78 @@ +import { useCallback, useMemo, useState } from 'react'; import { IconButton, Menu, MenuButton, MenuItem, MenuList, Switch } from '@chakra-ui/react'; import { IoEllipsisHorizontal } from '@react-icons/all-files/io5/IoEllipsisHorizontal'; -export type EditMode = 'rename' | 'duplicate' | null; +import { updateAliases } from '../../../../common/api/ontimeApi'; interface UrlAliasListItemProps { alias: string; enabled: boolean; pathAndParams: string; - // onToggleEditMode: (editMode: EditMode, filename: string | null) => void; - // onSubmit: () => void; - // onRefetch: () => Promise; - // editingFilename: string | null; - // editingMode: EditMode | null; + onRefetch: () => Promise; } -export default function UrlAliasListItem({ alias, enabled, pathAndParams }: UrlAliasListItemProps) { - // const [submitError, setSubmitError] = useState(null); +export default function UrlAliasListItem({ alias, enabled, pathAndParams, onRefetch }: UrlAliasListItemProps) { + const [isEditing, setIsEditing] = useState(false); - // const handleSubmitRename = async (values: ProjectFormValues) => { - // try { - // setSubmitError(null); + const handleToggle = useCallback(async () => { + // TODO: Error handling + await updateAliases({ + alias, + enabled: !enabled, + pathAndParams, + }); - // if (!values.filename) { - // setSubmitError('Filename cannot be blank'); - // return; - // } - // await renameProject(filename, values.filename); - // await onRefetch(); - // onSubmit(); - // } catch (error) { - // setSubmitError(maybeAxiosError(error)); - // } - // }; + await onRefetch(); + }, [alias, enabled, onRefetch, pathAndParams]); - // const handleSubmitDuplicate = async (values: ProjectFormValues) => { - // try { - // setSubmitError(null); + const handleToggleEditMode = useCallback(() => { + setIsEditing(!isEditing); + }, [isEditing]); - // if (!values.filename) { - // setSubmitError('Filename cannot be blank'); - // return; - // } - // await duplicateProject(filename, values.filename); - // await onRefetch(); - // onSubmit(); - // } catch (error) { - // setSubmitError(maybeAxiosError(error)); - // } - // }; - - // const handleToggleEditMode = (editMode: EditMode, filename: string | null) => { - // setSubmitError(null); - // onToggleEditMode(editMode, filename); - // }; + const handleRenderAliases = useMemo(() => { + if (!isEditing) { + return ( + <> + + {alias} + + + {pathAndParams} + + + + + + + + + ); + } else { + // Return a form + return null; + } + }, [alias, enabled, handleToggle, handleToggleEditMode, isEditing, pathAndParams]); return ( - {alias} - {pathAndParams} - - - - - - + {handleRenderAliases} {/* {new Date(updatedAt).toLocaleString()} */} ); } -function ActionMenu() { - const handleRename = () => { - // onChangeEditMode('rename', filename); +function ActionMenu({ onChangeEditMode }: { onChangeEditMode: () => void }) { + const handleEdit = () => { + onChangeEditMode(); }; const handleDelete = async () => { @@ -94,7 +90,7 @@ function ActionMenu() { size='sm' /> - Edit + Edit Delete diff --git a/apps/server/src/controllers/ontimeController.ts b/apps/server/src/controllers/ontimeController.ts index 6c30faee6..b182f50fb 100644 --- a/apps/server/src/controllers/ontimeController.ts +++ b/apps/server/src/controllers/ontimeController.ts @@ -189,6 +189,34 @@ export const postAliases = async (req: Request, res: Response) => { } }; +// Update controller for PUT request to '/ontime/aliases' +// Returns ACK message +export const updateAliases = async (req: Request, res: Response) => { + try { + const { alias, enabled, pathAndParams } = req.body; + + const aliases = DataProvider.getAliases(); + + const index = aliases.findIndex((a) => a.alias === alias); + + if (index === -1) { + return res.status(404).send({ message: `Alias ${alias} not found` }); + } + + aliases[index] = { + alias, + enabled, + pathAndParams, + }; + + await DataProvider.setAliases(aliases); + + res.status(200).send(aliases); + } catch (error) { + res.status(400).send({ message: String(error) }); + } +}; + // Create controller for GET request to '/ontime/userfields' // Returns - export const getUserFields = async (_req: Request, res: Response) => { diff --git a/apps/server/src/controllers/ontimeController.validate.ts b/apps/server/src/controllers/ontimeController.validate.ts index f385e6b82..38e13669b 100644 --- a/apps/server/src/controllers/ontimeController.validate.ts +++ b/apps/server/src/controllers/ontimeController.validate.ts @@ -39,6 +39,21 @@ export const validateAliases = [ }, ]; +/** + * @description Validates object for PUT /ontime/aliases + */ +export const validateUpdateAlises = [ + body('alias').isString().trim(), + body('pathAndParams').isString().trim().optional(), + body('enabled').isBoolean().optional(), + + (req: Request, res: Response, next: NextFunction) => { + const errors = validationResult(req); + if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() }); + next(); + }, +]; + /** * @description Validates object for POST /ontime/userfields */ diff --git a/apps/server/src/routes/ontimeRouter.ts b/apps/server/src/routes/ontimeRouter.ts index a6957a827..ef8389ceb 100644 --- a/apps/server/src/routes/ontimeRouter.ts +++ b/apps/server/src/routes/ontimeRouter.ts @@ -32,6 +32,7 @@ import { postId, getAuthentication, getClientSecrect as getClientSecret, + updateAliases, } from '../controllers/ontimeController.js'; import { @@ -48,6 +49,7 @@ import { validateSheetid, validateWorksheet, validateSheetOptions, + validateUpdateAlises, } from '../controllers/ontimeController.validate.js'; import { projectSanitiser } from '../controllers/projectController.validate.js'; import { sanitizeProjectFilename } from '../utils/sanitizeProjectFilename.js'; @@ -87,6 +89,9 @@ router.get('/aliases', getAliases); // create route between controller and '/ontime/aliases' endpoint router.post('/aliases', validateAliases, postAliases); +// create route between controller and /ontime/aliases' endpoint +router.put('/aliases', validateUpdateAlises, updateAliases); + // create route between controller and '/ontime/aliases' endpoint router.get('/userfields', getUserFields);