From c55cb3ae0a8bd030ffc31c02a0a38d08fcf4c1fa Mon Sep 17 00:00:00 2001 From: calvin Date: Mon, 10 Apr 2023 15:00:23 -0600 Subject: [PATCH] feat: [code-218]: pr review button --- .../components/Changes/Changes.module.scss | 42 ++++++ .../Changes/Changes.module.scss.d.ts | 6 + web/src/components/Changes/Changes.tsx | 12 +- .../ReviewSplitButton/ReviewSplitButton.tsx | 121 ++++++++++++++++ .../ThreadSection/ThreadSection.module.scss | 6 +- web/src/framework/strings/stringTypes.ts | 1 + web/src/i18n/strings.en.yaml | 1 + .../PullRequest/Conversation/Conversation.tsx | 2 +- .../PullRequestActionsBox.module.scss | 14 ++ .../PullRequestActionsBox.module.scss.d.ts | 1 + .../PullRequestActionsBox.tsx | 131 ++++++++++-------- .../GeneralSettingsContent.tsx | 4 +- 12 files changed, 273 insertions(+), 68 deletions(-) create mode 100644 web/src/components/Changes/ReviewSplitButton/ReviewSplitButton.tsx diff --git a/web/src/components/Changes/Changes.module.scss b/web/src/components/Changes/Changes.module.scss index 0a9be37ba..ed7d2530c 100644 --- a/web/src/components/Changes/Changes.module.scss +++ b/web/src/components/Changes/Changes.module.scss @@ -56,3 +56,45 @@ .repeatBtn { margin-left: var(--spacing-xsmall) !important; } + +.popover { + transform: translateY(5px) !important; + + .menuItem { + strong { + display: inline-block; + margin-left: 10px; + } + + p { + font-size: 12px; + padding-left: 27px; + line-height: 16px; + margin: 5px 0; + max-width: 320px; + } + } + .menuReviewItem { + .reviewIcon { + margin-top: 2px; + } + + strong { + display: inline-block; + margin-left: 10px; + } + + p { + font-size: 12px; + padding-left: var(--spacing-small); + line-height: 16px; + max-width: 320px; + } + } +} + +.btn { + &.hide { + visibility: hidden; + } +} diff --git a/web/src/components/Changes/Changes.module.scss.d.ts b/web/src/components/Changes/Changes.module.scss.d.ts index 3aecf316b..3b9603602 100644 --- a/web/src/components/Changes/Changes.module.scss.d.ts +++ b/web/src/components/Changes/Changes.module.scss.d.ts @@ -11,5 +11,11 @@ declare const styles: { readonly hideBtn: string readonly refreshIcon: string readonly repeatBtn: string + readonly popover: string + readonly menuItem: string + readonly menuReviewItem: string + readonly reviewIcon: string + readonly btn: string + readonly hide: string } export default styles diff --git a/web/src/components/Changes/Changes.tsx b/web/src/components/Changes/Changes.tsx index 77a46a1e9..eb1b2357c 100644 --- a/web/src/components/Changes/Changes.tsx +++ b/web/src/components/Changes/Changes.tsx @@ -35,7 +35,7 @@ import { useShowRequestError } from 'hooks/useShowRequestError' import { LoadingSpinner } from 'components/LoadingSpinner/LoadingSpinner' import { ChangesDropdown } from './ChangesDropdown' import { DiffViewConfiguration } from './DiffViewConfiguration' -import { ReviewDecisionButton } from './ReviewDecisionButton/ReviewDecisionButton' +import ReviewSplitButton from './ReviewSplitButton/ReviewSplitButton' import css from './Changes.module.scss' const STICKY_TOP_POSITION = 64 @@ -73,6 +73,7 @@ export const Changes: React.FC = ({ const [lineBreaks, setLineBreaks] = useUserPreference(UserPreference.DIFF_LINE_BREAKS, false) const [diffs, setDiffs] = useState([]) const [isSticky, setSticky] = useState(false) + const { data: rawDiff, error, @@ -209,11 +210,16 @@ export const Changes: React.FC = ({ - + {/* + /> */} diff --git a/web/src/components/Changes/ReviewSplitButton/ReviewSplitButton.tsx b/web/src/components/Changes/ReviewSplitButton/ReviewSplitButton.tsx new file mode 100644 index 000000000..f133627fa --- /dev/null +++ b/web/src/components/Changes/ReviewSplitButton/ReviewSplitButton.tsx @@ -0,0 +1,121 @@ +import { + ButtonVariation, + Color, + Container, + Icon, + IconName, + SplitButton, + useToaster, + Text, + FontVariation, + Layout +} from '@harness/uicore' +import { Menu, PopoverPosition } from '@blueprintjs/core' +import cx from 'classnames' +import { useMutate } from 'restful-react' +import React, { useCallback, useState } from 'react' +import { useStrings } from 'framework/strings' +import type { EnumPullReqReviewDecision, TypesPullReq } from 'services/code' +import type { GitInfoProps } from 'utils/GitUtils' +import { getErrorMessage } from 'utils/Utils' +import css from '../Changes.module.scss' + +interface PrReviewOption { + method: EnumPullReqReviewDecision | 'reject' + title: string + disabled?: boolean + icon: IconName + color: Color +} + +interface ReviewSplitButtonProps extends Pick { + shouldHide: boolean + pullRequestMetadata?: TypesPullReq +} +const ReviewSplitButton = (props: ReviewSplitButtonProps) => { + const { pullRequestMetadata, repoMetadata, shouldHide } = props + const { getString } = useStrings() + const { showError, showSuccess } = useToaster() + + const prDecisionOptions: PrReviewOption[] = [ + { + method: 'approved', + title: getString('approve'), + icon: 'tick-circle' as IconName, + color: Color.GREEN_700 + }, + { + method: 'changereq', + title: getString('requestChanges'), + icon: 'error' as IconName, + color: Color.ORANGE_700 + }, + { + method: 'reject', + title: getString('reject'), + disabled: true, + icon: 'danger-icon' as IconName, + color: Color.RED_700 + } + ] + + const [decisionOption, setDecisionOption] = useState(prDecisionOptions[0]) + const { mutate, loading } = useMutate({ + verb: 'POST', + path: `/api/v1/repos/${repoMetadata.path}/+/pullreq/${pullRequestMetadata?.number}/reviews` + }) + const submitReview = useCallback(() => { + mutate({ decision: decisionOption.method }) + .then(() => { + // setReset(true) + showSuccess(getString('pr.reviewSubmitted')) + }) + .catch(exception => showError(getErrorMessage(exception))) + }, [decisionOption, mutate, showError, showSuccess, getString]) + return ( + + { + submitReview() + }}> + {prDecisionOptions.map(option => { + return ( + + + + {option.title} + + + } + onClick={() => { + setDecisionOption(option) + }} + /> + ) + })} + + + ) +} + +export default ReviewSplitButton diff --git a/web/src/components/ThreadSection/ThreadSection.module.scss b/web/src/components/ThreadSection/ThreadSection.module.scss index f0ca3772e..a01e2e00e 100644 --- a/web/src/components/ThreadSection/ThreadSection.module.scss +++ b/web/src/components/ThreadSection/ThreadSection.module.scss @@ -29,11 +29,11 @@ > ::before { position: absolute; - top: 34px; + top: 28px; left: 15px; content: ''; width: 1px; - height: 28px; + height: 25px; border: 1px dashed var(--grey-200); opacity: 0.7; z-index: 2; @@ -45,7 +45,7 @@ > ::after { position: absolute; - bottom: -12px; + bottom: -10px; left: 15px; content: ''; width: 1px; diff --git a/web/src/framework/strings/stringTypes.ts b/web/src/framework/strings/stringTypes.ts index 7f3a62c85..a1db8aa55 100644 --- a/web/src/framework/strings/stringTypes.ts +++ b/web/src/framework/strings/stringTypes.ts @@ -241,6 +241,7 @@ export interface StringsMap { quote: string readMe: string refresh: string + reject: string rejected: string remove: string renameFile: string diff --git a/web/src/i18n/strings.en.yaml b/web/src/i18n/strings.en.yaml index 6ad58663f..3fafda07d 100644 --- a/web/src/i18n/strings.en.yaml +++ b/web/src/i18n/strings.en.yaml @@ -224,6 +224,7 @@ open: Open merged: Merged enabled: Enabled closed: Closed +reject: Reject rejected: Rejected yours: Yours all: All diff --git a/web/src/pages/PullRequest/Conversation/Conversation.tsx b/web/src/pages/PullRequest/Conversation/Conversation.tsx index 82f51000e..ce24a1083 100644 --- a/web/src/pages/PullRequest/Conversation/Conversation.tsx +++ b/web/src/pages/PullRequest/Conversation/Conversation.tsx @@ -538,7 +538,7 @@ const SystemBox: React.FC = ({ pullRequestMetadata, commentItems return ( - + diff --git a/web/src/pages/PullRequest/Conversation/PullRequestActionsBox/PullRequestActionsBox.module.scss b/web/src/pages/PullRequest/Conversation/PullRequestActionsBox/PullRequestActionsBox.module.scss index 2bb607a09..1b79c9985 100644 --- a/web/src/pages/PullRequest/Conversation/PullRequestActionsBox/PullRequestActionsBox.module.scss +++ b/web/src/pages/PullRequest/Conversation/PullRequestActionsBox/PullRequestActionsBox.module.scss @@ -63,6 +63,20 @@ max-width: 320px; } } + .menuReviewItem { + strong { + display: inline-block; + margin-left: 10px; + } + + p { + font-size: 12px; + padding-left: 2px; + line-height: 16px; + margin: 0px 1px; + max-width: 320px; + } + } } .btnWrapper { diff --git a/web/src/pages/PullRequest/Conversation/PullRequestActionsBox/PullRequestActionsBox.module.scss.d.ts b/web/src/pages/PullRequest/Conversation/PullRequestActionsBox/PullRequestActionsBox.module.scss.d.ts index 590173b3a..1f5752eaa 100644 --- a/web/src/pages/PullRequest/Conversation/PullRequestActionsBox/PullRequestActionsBox.module.scss.d.ts +++ b/web/src/pages/PullRequest/Conversation/PullRequestActionsBox/PullRequestActionsBox.module.scss.d.ts @@ -11,6 +11,7 @@ declare const styles: { readonly sub: string readonly popover: string readonly menuItem: string + readonly menuReviewItem: string readonly btnWrapper: string readonly hasError: string readonly mergeContainer: string diff --git a/web/src/pages/PullRequest/Conversation/PullRequestActionsBox/PullRequestActionsBox.tsx b/web/src/pages/PullRequest/Conversation/PullRequestActionsBox/PullRequestActionsBox.tsx index b9951cb9b..923e9b4c6 100644 --- a/web/src/pages/PullRequest/Conversation/PullRequestActionsBox/PullRequestActionsBox.tsx +++ b/web/src/pages/PullRequest/Conversation/PullRequestActionsBox/PullRequestActionsBox.tsx @@ -17,10 +17,17 @@ import { Case, Else, Match, Render, Truthy } from 'react-jsx-match' import { Menu, PopoverPosition, Icon as BIcon } from '@blueprintjs/core' import cx from 'classnames' import ReactTimeago from 'react-timeago' -import type { EnumMergeMethod, OpenapiMergePullReq, OpenapiStatePullReqRequest, TypesPullReq } from 'services/code' +import type { + EnumMergeMethod, + EnumPullReqState, + OpenapiMergePullReq, + OpenapiStatePullReqRequest, + TypesPullReq +} from 'services/code' import { useStrings } from 'framework/strings' import { CodeIcon, GitInfoProps, PullRequestFilterOption, PullRequestState } from 'utils/GitUtils' import { getErrorMessage } from 'utils/Utils' +import ReviewSplitButton from 'components/Changes/ReviewSplitButton/ReviewSplitButton' import css from './PullRequestActionsBox.module.scss' interface PullRequestActionsBoxProps extends Pick { @@ -135,46 +142,53 @@ export const PullRequestActionsBox: React.FC = ({ /> - - + + { - if (mergeOption.method !== 'close') { - const payload: OpenapiMergePullReq = { method: mergeOption.method } - - mergePR(payload) - .then(onPRStateChanged) - .catch(exception => showError(getErrorMessage(exception))) - } else { - const payload: OpenapiStatePullReqRequest = { state: 'closed' } - - updatePRState(payload) - .then(onPRStateChanged) - .catch(exception => showError(getErrorMessage(exception))) + [css.btnWrapper]: mergeOption.method !== 'close', + [css.hasError]: mergeable === false + })}> + - {/* TODO: These two items are used for creating a PR + popoverProps={{ + interactionKind: 'click', + usePortal: true, + popoverClassName: css.popover, + position: PopoverPosition.BOTTOM_RIGHT, + transitionDuration: 1000 + }} + onClick={() => { + if (mergeOption.method !== 'close') { + const payload: OpenapiMergePullReq = { method: mergeOption.method } + + mergePR(payload) + .then(onPRStateChanged) + .catch(exception => showError(getErrorMessage(exception))) + } else { + const payload: OpenapiStatePullReqRequest = { state: 'closed' } + + updatePRState(payload) + .then(onPRStateChanged) + .catch(exception => showError(getErrorMessage(exception))) + } + }}> + {/* TODO: These two items are used for creating a PR = ({ } /> */} - {mergeOptions.map(option => { - return ( - - - {option.title} -

{option.desc}

- - } - onClick={() => setMergeOption(option)} - /> - ) - })} -
-
+ {mergeOptions.map(option => { + return ( + + + {option.title} +

{option.desc}

+ + } + onClick={() => setMergeOption(option)} + /> + ) + })} +
+
+
diff --git a/web/src/pages/RepositorySettings/GeneralSettingsContent/GeneralSettingsContent.tsx b/web/src/pages/RepositorySettings/GeneralSettingsContent/GeneralSettingsContent.tsx index dffcc1f43..1b27df255 100644 --- a/web/src/pages/RepositorySettings/GeneralSettingsContent/GeneralSettingsContent.tsx +++ b/web/src/pages/RepositorySettings/GeneralSettingsContent/GeneralSettingsContent.tsx @@ -172,7 +172,6 @@ const GeneralSettingsContent = (props: GeneralSettingsProps) => { setEditDesc(ACCESS_MODES.EDIT) }} {...permissionProps(permEditResult, standalone)} - /> )} @@ -191,8 +190,7 @@ const GeneralSettingsContent = (props: GeneralSettingsProps) => { }} variation={ButtonVariation.SECONDARY} text={getString('delete')} - {...permissionProps(permDeleteResult, standalone)} - > + {...permissionProps(permDeleteResult, standalone)}>