From 2d30368f6a9576c9eb30e4fdc8b46b8e6d68bb3f Mon Sep 17 00:00:00 2001 From: Surat Das Date: Thu, 4 Feb 2021 00:14:18 -0800 Subject: [PATCH 1/2] Issue#197 : Possible to add/edit ci build id. --- src/components/BuildList.tsx | 156 ++++++++++++++++++++++----------- src/contexts/build.context.tsx | 7 +- src/services/builds.service.ts | 7 +- 3 files changed, 113 insertions(+), 57 deletions(-) diff --git a/src/components/BuildList.tsx b/src/components/BuildList.tsx index 39181a7c..23652db1 100644 --- a/src/components/BuildList.tsx +++ b/src/components/BuildList.tsx @@ -23,6 +23,7 @@ import { useBuildDispatch, deleteBuild, selectBuild, + modifyBuild, stopBuild, } from "../contexts"; import { BuildStatusChip } from "./BuildStatusChip"; @@ -31,6 +32,7 @@ import { formatDateTime } from "../_helpers/format.helper"; import { useSnackbar } from "notistack"; import { Build } from "../types"; import { BaseModal } from "./BaseModal"; +import { TextValidator } from "react-material-ui-form-validator"; const useStyles = makeStyles((theme: Theme) => createStyles({ @@ -57,8 +59,10 @@ const BuildList: FunctionComponent = () => { const { enqueueSnackbar } = useSnackbar(); const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false); + const [editDialogOpen, setEditDialogOpen] = React.useState(false); const [anchorEl, setAnchorEl] = React.useState(null); const [menuBuild, setMenuBuild] = React.useState(); + const [newCiBuildId, setNewCiBuildId] = React.useState(""); const handleMenuClick = ( event: React.MouseEvent, @@ -77,6 +81,10 @@ const BuildList: FunctionComponent = () => { setDeleteDialogOpen(!deleteDialogOpen); }; + const toggleEditDialogOpen = () => { + setEditDialogOpen(!editDialogOpen); + }; + React.useEffect(() => { if (!selectedBuild && buildList.length > 0) { selectBuild(buildDispatch, buildList[0].id); @@ -92,62 +100,61 @@ const BuildList: FunctionComponent = () => { ) : buildList.length === 0 ? ( No builds ) : ( - buildList.map((build) => ( - - { - history.push({ - search: "buildId=" + build.id, - }); - }} - classes={{ - container: classes.listItem, - }} - > - {`#${build.number} ${ - build.ciBuildId || "" - }`} - } - secondary={ - - - - {formatDateTime(build.createdAt)} - - - - + buildList.map((build) => ( + + { + history.push({ + search: "buildId=" + build.id, + }); + }} + classes={{ + container: classes.listItem, + }} + > + {`#${build.number} ${build.ciBuildId || "" + }`} + } + secondary={ + - + + {formatDateTime(build.createdAt)} + - + + + + + + + + - - - } - /> + } + /> - - handleMenuClick(event, build)} - > - - - - - {build.isRunning && } - - )) - )} + + handleMenuClick(event, build)} + > + + + + + {build.isRunning && } + + )) + )} {menuBuild && ( @@ -172,9 +179,53 @@ const BuildList: FunctionComponent = () => { Stop )} + Edit CI Build Delete )} + {menuBuild && ( + + {`Edit the ci build id for build: #${menuBuild.number || menuBuild.id + }`} + + setNewCiBuildId((event.target as HTMLInputElement).value), + "data-testid": "newCiBuildId", + }} + /> + + } + onSubmit={() => { + modifyBuild(buildDispatch, menuBuild.id, { "ciBuildId": newCiBuildId }) + .then((b) => { + toggleEditDialogOpen(); + }) + .catch((err) => + enqueueSnackbar(err, { + variant: "error", + }) + ); + handleMenuClose(); + }} + /> + )} {menuBuild && ( { submitButtonText={"Delete"} onCancel={toggleDeleteDialogOpen} content={ - {`Are you sure you want to delete build: #${ - menuBuild.number || menuBuild.id - }?`} + {`Are you sure you want to delete build: #${menuBuild.number || menuBuild.id + }?`} } onSubmit={() => { let indexOfBuildDeleted = buildList.findIndex((e) => e.id === menuBuild.id); diff --git a/src/contexts/build.context.tsx b/src/contexts/build.context.tsx index 976ee455..6cd3187c 100644 --- a/src/contexts/build.context.tsx +++ b/src/contexts/build.context.tsx @@ -174,7 +174,7 @@ async function deleteBuild(dispatch: Dispatch, id: string) { } async function stopBuild(dispatch: Dispatch, id: string) { - return buildsService.stop(id).then((build) => { + return buildsService.update(id, { "isRunning": false }).then((build) => { dispatch({ type: "update", payload: build }); return build; }); @@ -194,6 +194,10 @@ async function addBuild(dispatch: Dispatch, build: Build) { dispatch({ type: "add", payload: build }); } +async function modifyBuild(dispatch: Dispatch, id: string, body: object) { + return buildsService.update(id, body); +} + async function updateBuild(dispatch: Dispatch, build: Build) { dispatch({ type: "update", payload: build }); } @@ -207,5 +211,6 @@ export { selectBuild, addBuild, updateBuild, + modifyBuild, stopBuild, }; diff --git a/src/services/builds.service.ts b/src/services/builds.service.ts index 1b4fff6a..34d91d3d 100644 --- a/src/services/builds.service.ts +++ b/src/services/builds.service.ts @@ -42,10 +42,11 @@ async function remove(id: string): Promise { ); } -async function stop(id: string): Promise { +async function update(id: string, body: object): Promise { const requestOptions = { method: "PATCH", - headers: authHeader(), + headers: { "Content-Type": "application/json", ...authHeader() }, + body: JSON.stringify(body) }; return fetch(`${API_URL}${ENDPOINT_URL}/${id}`, requestOptions).then( @@ -70,5 +71,5 @@ export const buildsService = { getList, approve, remove, - stop, + update, }; From 22db818becdf66c65681fad8af63ba5657f6112e Mon Sep 17 00:00:00 2001 From: Surat Das Date: Fri, 5 Feb 2021 21:09:19 -0800 Subject: [PATCH 2/2] Fixed review comments: made use of DTO for passed body. --- src/contexts/build.context.tsx | 8 ++++---- src/services/builds.service.ts | 3 ++- src/types/dto/build.dto.ts | 4 ++++ 3 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 src/types/dto/build.dto.ts diff --git a/src/contexts/build.context.tsx b/src/contexts/build.context.tsx index 6cd3187c..76f5f8fd 100644 --- a/src/contexts/build.context.tsx +++ b/src/contexts/build.context.tsx @@ -180,6 +180,10 @@ async function stopBuild(dispatch: Dispatch, id: string) { }); } +async function modifyBuild(dispatch: Dispatch, id: string, body: object) { + return buildsService.update(id, body); +} + async function selectBuild(dispatch: Dispatch, id: string | null) { if (id === null) { dispatch({ type: "select", payload: null }); @@ -194,10 +198,6 @@ async function addBuild(dispatch: Dispatch, build: Build) { dispatch({ type: "add", payload: build }); } -async function modifyBuild(dispatch: Dispatch, id: string, body: object) { - return buildsService.update(id, body); -} - async function updateBuild(dispatch: Dispatch, build: Build) { dispatch({ type: "update", payload: build }); } diff --git a/src/services/builds.service.ts b/src/services/builds.service.ts index 34d91d3d..c8e190cc 100644 --- a/src/services/builds.service.ts +++ b/src/services/builds.service.ts @@ -1,6 +1,7 @@ import { Build, PaginatedData } from "../types"; import { handleResponse, authHeader } from "../_helpers/service.helpers"; import { API_URL } from "../_config/env.config"; +import {BuildDto} from "../types/dto/build.dto"; const ENDPOINT_URL = "/builds"; @@ -42,7 +43,7 @@ async function remove(id: string): Promise { ); } -async function update(id: string, body: object): Promise { +async function update(id: string, body: BuildDto): Promise { const requestOptions = { method: "PATCH", headers: { "Content-Type": "application/json", ...authHeader() }, diff --git a/src/types/dto/build.dto.ts b/src/types/dto/build.dto.ts new file mode 100644 index 00000000..7958eec5 --- /dev/null +++ b/src/types/dto/build.dto.ts @@ -0,0 +1,4 @@ +export interface BuildDto { + ciBuildId?: string; + isRunning?: boolean; +}