diff --git a/ui/src/components/DeployConfirm.tsx b/ui/src/components/DeployConfirm.tsx
deleted file mode 100644
index a6a15633..00000000
--- a/ui/src/components/DeployConfirm.tsx
+++ /dev/null
@@ -1,202 +0,0 @@
-import { Form, Typography, Avatar, Button, Collapse, Timeline } from "antd"
-import moment from "moment"
-import { useState } from "react"
-
-import { Deployment, Commit, Review } from "../models"
-import DeploymentRefCode from "./DeploymentRefCode"
-import DeploymentStatusBadge from "./DeploymentStatusBadge"
-import DeploymentStatusSteps from "./DeploymentStatusSteps"
-import ReviewerList, { ReviewStatus } from "./ReviewerList"
-
-const { Paragraph, Text } = Typography
-const { Panel } = Collapse
-
-interface DeployConfirmProps {
- isDeployable: boolean
- deploying: boolean
- deployment: Deployment
- changes: Commit[]
- reviews: Review[]
- onClickDeploy(): void
-}
-
-export default function DeployConfirm(props: DeployConfirmProps): JSX.Element {
- const layout = {
- labelCol: { span: 5},
- wrapperCol: { span: 16 },
- style: {marginBottom: 12}
- };
- const submitLayout = {
- wrapperCol: { offset: 6, span: 16 },
- };
-
- // Form makes it to display organized.
- return (
-
- {props.deployment.env}
-
-
-
-
- 0)? {marginBottom: 0} : {marginBottom: 12}}
- >
- {(props.deployment.statuses && props.deployment.statuses.length > 0)?
-
- }
- style={{position: "relative", top: "-5px", left: "-15px"}}
- >
-
-
- :
-
- }
-
-
- {(props.deployment.deployer)?
-
- {props.deployment.deployer.login}
- :
-
- U
- }
-
-
- {moment(props.deployment.createdAt).format("YYYY-MM-DD HH:mm:ss")}
-
- 0)? {marginBottom: 0} : {}}
- >
- {(props.reviews.length > 0)?
-
- }
- style={{position: "relative", top: "-5px", left: "-15px"}}
- >
-
-
- :
- No Reviewers}
-
-
-
-
-
-
-
-
-
- {(props.isDeployable)?
- :
- }
-
-
- )
-}
-
-interface CommitChangesProps {
- changes: Commit[]
-}
-
-function CommitChanges(props: CommitChangesProps): JSX.Element {
- if (props.changes.length === 0) {
- return There are no commits.
- }
-
- return (
-
- {props.changes.map((change, idx) => {
- return
-
-
- })}
-
- )
-}
-
-interface CommitChangeProps {
- commit: Commit
-}
-
-function CommitChange(props: CommitChangeProps): JSX.Element {
- const [message, ...description] = props.commit.message.split(/(\r\n|\n|\r)/g)
-
- const [hide, setHide] = useState(true)
-
- const onClickHide = () => {
- setHide(!hide)
- }
-
- return (
-
-
- {message}
-
- {(description.length) ?
- :
- null}
- {/* Display the description of the commit. */}
- {(!hide) ?
-
-
- {description.join("").trim()}
-
- :
- null}
-
- {(props.commit?.author) ?
-
- {props.commit.author.login} committed {moment(props.commit.author?.date).fromNow()}
- :
- null}
-
- )
-}
\ No newline at end of file
diff --git a/ui/src/components/DeploymentDescriptor/CommitChanges.tsx b/ui/src/components/DeploymentDescriptor/CommitChanges.tsx
new file mode 100644
index 00000000..97c5c1eb
--- /dev/null
+++ b/ui/src/components/DeploymentDescriptor/CommitChanges.tsx
@@ -0,0 +1,81 @@
+import { useState } from "react"
+import { Button, Typography, List, Avatar } from "antd"
+import moment from "moment"
+
+import { Commit } from "../../models"
+
+interface CommitChangesProps {
+ changes:Commit[]
+}
+
+export default function CommitChanges(props: CommitChangesProps): JSX.Element {
+ return (
+ {
+ return (
+
+ )
+ }}
+ />
+ )
+}
+
+function CommitChange(props: {commit: Commit}): JSX.Element {
+ const [message, ...description] = props.commit.message.split(/(\r\n|\n|\r)/g)
+
+ const [hide, setHide] = useState(true)
+
+ const onClickHide = () => {
+ setHide(!hide)
+ }
+
+ return (
+
+
+ {message}
+ {/* Display the description when the button is clicked. */}
+ {(description.length)?
+
+ :
+ <>>}
+ {(!hide) ?
+
+
+ {description.join("").trim()}
+
+
+ :
+ <>>}
+ >
+ }
+ description={(props.commit?.author)?
+ <>
+
+ {props.commit.author.login} committed
+ {moment(props.commit.author?.date).fromNow()}
+ >
+ :
+ <>>
+ }
+ />
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/ui/src/components/DeploymentDescriptor/DeploymentDescriptor.tsx b/ui/src/components/DeploymentDescriptor/DeploymentDescriptor.tsx
new file mode 100644
index 00000000..1fb14caa
--- /dev/null
+++ b/ui/src/components/DeploymentDescriptor/DeploymentDescriptor.tsx
@@ -0,0 +1,67 @@
+import { Button, Descriptions, Modal, Typography } from "antd"
+import moment from "moment"
+
+import DeploymentStatusBadge from "../DeploymentStatusBadge"
+import UserAvatar from "../UserAvatar"
+import CommitChanges from "./CommitChanges"
+
+import { Commit, Deployment } from "../../models"
+import { getShortRef } from "../../libs"
+import { useState } from "react"
+
+const { Text } = Typography
+
+interface DeploymentDescriptorProps {
+ deployment: Deployment
+ commits: Commit[]
+}
+
+export default function DeploymentDescriptor(props: DeploymentDescriptorProps): JSX.Element {
+ const [visible, setVisible] = useState(false)
+
+ const showModal = () => {
+ setVisible(true)
+ }
+
+ const hideModal = () => {
+ setVisible(false)
+ }
+
+ return (
+
+ {props.deployment.env}
+
+ {getShortRef(props.deployment)}
+
+
+
+
+
+
+
+
+ {moment(props.deployment.createdAt).format("YYYY-MM-DD HH:mm:ss")}
+
+
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/ui/src/components/DeploymentDescriptor/index.tsx b/ui/src/components/DeploymentDescriptor/index.tsx
new file mode 100644
index 00000000..eccc5548
--- /dev/null
+++ b/ui/src/components/DeploymentDescriptor/index.tsx
@@ -0,0 +1,3 @@
+import DeploymentDescriptor from "./DeploymentDescriptor"
+
+export default DeploymentDescriptor
diff --git a/ui/src/components/DeploymentStatusSteps.tsx b/ui/src/components/DeploymentStatusSteps.tsx
index 1ef622bf..ba502bd4 100644
--- a/ui/src/components/DeploymentStatusSteps.tsx
+++ b/ui/src/components/DeploymentStatusSteps.tsx
@@ -1,9 +1,10 @@
import { Timeline, Typography } from "antd"
+import { ClockCircleOutlined } from "@ant-design/icons"
import moment from "moment"
import { DeploymentStatus } from "../models"
-const { Paragraph, Text, Link } = Typography
+const { Text, Link } = Typography
interface DeploymentStatusStepsProps {
statuses: DeploymentStatus[]
@@ -17,13 +18,14 @@ export default function DeploymentStatusSteps(props: DeploymentStatusStepsProps)
-
- {status.description}
- {(status.logUrl !== "")? View : <>>}
- Updated {status.status} at {moment(status.createdAt).format('HH:mm:ss')}
-
+ {moment(status.createdAt).format("YYYY-MM-DD HH:mm:ss")}
+ {status.description}
+ {(status.logUrl !== "")?
+ View Detail
+ :
+ <>>}
+ Updated {status.status} {moment(status.createdAt).fromNow()}
)
})}
diff --git a/ui/src/components/ReviewerList.tsx b/ui/src/components/ReviewerList.tsx
index 60b8f722..8364cd5b 100644
--- a/ui/src/components/ReviewerList.tsx
+++ b/ui/src/components/ReviewerList.tsx
@@ -1,53 +1,62 @@
-import { List, Avatar, Popover, Button } from "antd"
+import { Popover, Button, Descriptions, Typography } from "antd"
import { CheckOutlined, CloseOutlined, CommentOutlined, ClockCircleOutlined } from "@ant-design/icons"
-import { User, Review, ReviewStatusEnum } from "../models"
+import { Review, ReviewStatusEnum } from "../models"
+import UserAvatar from "./UserAvatar"
+const { Text } = Typography
export interface ReviewerListProps {
reviews: Review[]
}
export default function ReviewerList(props: ReviewerListProps): JSX.Element {
+ if (props.reviews.length === 0) {
+ return (
+
+ No reviewers
+
+ )
+ }
+
return (
- {
+
+ {props.reviews.map((review, idx) => {
return (
-
-
-
+
+
+
+
+
)
- }}
- />
+ })}
+
)
}
-function ReviewItem(props: {review: Review}): JSX.Element {
- const status = (status: ReviewStatusEnum) => {
- switch (status) {
- case ReviewStatusEnum.Pending:
- return
- case ReviewStatusEnum.Approved:
- return
- case ReviewStatusEnum.Rejected:
- return
- default:
- return
- }
+function ReviewStatusIcon(props: {review: Review}): JSX.Element {
+ switch (props.review.status) {
+ case ReviewStatusEnum.Pending:
+ return
+ case ReviewStatusEnum.Approved:
+ return
+ case ReviewStatusEnum.Rejected:
+ return
+ default:
+ return
}
+}
- const avatar = (user?: User) => {
- return user?
- {user.login}:
- U
- }
+function ReviewCommentIcon(props: {review: Review}): JSX.Element {
+ const comment = props.review.comment
- const commentIcon = (comment: string) => {
- return comment !== ""?
+ return (
+ comment?
{comment}}
+ content={
+ {comment}
+ }
>
- :
+
+ :
<>>
- }
-
- return (
-
- {status(props.review.status)} {avatar(props.review.user)} {commentIcon(props.review.comment)}
-
)
}
-export function ReviewStatus(props: {reviews: Review[]}): JSX.Element {
- for (let i = 0; i < props.reviews.length; i++) {
- if (props.reviews[i].status === ReviewStatusEnum.Rejected) {
- return
- Rejected
-
- }
- }
-
- for (let i = 0; i < props.reviews.length; i++) {
- if (props.reviews[i].status === ReviewStatusEnum.Approved) {
- return
- Approved
-
- }
- }
-
- return Pending
-}
diff --git a/ui/src/components/UserAvatar.tsx b/ui/src/components/UserAvatar.tsx
index a54a460e..0699ff19 100644
--- a/ui/src/components/UserAvatar.tsx
+++ b/ui/src/components/UserAvatar.tsx
@@ -5,13 +5,21 @@ import { User } from "../models";
const { Text } = Typography
interface UserAvatarProps {
+ boldName?: boolean
user?: User
}
export default function UserAvatar(props: UserAvatarProps): JSX.Element {
+ const boldName = props.boldName === undefined? true : props.boldName
return (
props.user?
- {props.user.login} :
- U
+
+
+ {props.user.login}
+
+ :
+
+ U
+
)
}
\ No newline at end of file
diff --git a/ui/src/views/Deployment.tsx b/ui/src/views/Deployment.tsx
index 900c1a7d..6be9abdd 100644
--- a/ui/src/views/Deployment.tsx
+++ b/ui/src/views/Deployment.tsx
@@ -1,8 +1,8 @@
import { useEffect } from "react"
-import { Breadcrumb, PageHeader, Result } from "antd"
import { shallowEqual } from 'react-redux'
import { useParams } from "react-router-dom"
import { Helmet } from "react-helmet"
+import { Breadcrumb, Button, PageHeader, Result, Row, Col } from "antd"
import { useAppSelector, useAppDispatch } from "../redux/hooks"
import {
@@ -27,7 +27,9 @@ import { subscribeEvents } from "../apis"
import Main from "./Main"
import ReviewModal from "../components/ReviewModal"
import Spin from "../components/Spin"
-import DeployConfirm from "../components/DeployConfirm"
+import DeploymentDescriptor from "../components/DeploymentDescriptor"
+import ReviewerList from "../components/ReviewerList"
+import DeploymentStatusSteps from "../components/DeploymentStatusSteps"
interface Params {
namespace: string
@@ -150,16 +152,41 @@ export default function DeploymentView(): JSX.Element {
onBack={onBack}
/>
-
-
-
+
+
+
+
+
+
+
+
+
+
+ {deployment.statuses?
+
+ :
+ <>>}
+
+
+
+
+ {isDeployable(deployment, reviews)?
+
+ :
+ }
+
+
)
}