diff --git a/web-ui/src/components/admin/permissions/__snapshots__/MobileTable.test.jsx.snap b/web-ui/src/components/admin/permissions/__snapshots__/MobileTable.test.jsx.snap
index bde9e448b0..6d3126a20e 100644
--- a/web-ui/src/components/admin/permissions/__snapshots__/MobileTable.test.jsx.snap
+++ b/web-ui/src/components/admin/permissions/__snapshots__/MobileTable.test.jsx.snap
@@ -20,7 +20,7 @@ exports[`MobileTable > renders correctly 1`] = `
scope="col"
>
+
`;
diff --git a/web-ui/src/components/reviews/TeamReviews.jsx b/web-ui/src/components/reviews/TeamReviews.jsx
index e32d3842ec..aeb6e02540 100644
--- a/web-ui/src/components/reviews/TeamReviews.jsx
+++ b/web-ui/src/components/reviews/TeamReviews.jsx
@@ -22,6 +22,10 @@ import {
import {
Alert,
Button,
+ Card,
+ CardActions,
+ CardContent,
+ CardHeader,
Chip,
Dialog,
DialogActions,
@@ -34,6 +38,7 @@ import {
List,
ListItem,
ListItemText,
+ Modal,
Switch,
TextField,
Tooltip,
@@ -122,12 +127,13 @@ const ReviewStatus = {
const TeamReviews = ({ onBack, periodId }) => {
const { state, dispatch } = useContext(AppContext);
- const history = useHistory();
const location = useLocation();
const [approvalMode, setApprovalMode] = useState(false);
const [assignments, setAssignments] = useState([]);
const [confirmApproveAllOpen, setConfirmApproveAllOpen] = useState(false);
+ const [confirmationDialogOpen, setConfirmationDialogOpen] = useState(false);
+ const [confirmationText, setConfirmationText] = useState('');
const [confirmDeleteOpen, setConfirmDeleteOpen] = useState(false);
const [memberSelectorOpen, setMemberSelectorOpen] = useState(false);
const [nameQuery, setNameQuery] = useState('');
@@ -140,6 +146,7 @@ const TeamReviews = ({ onBack, periodId }) => {
const [showAll, setShowAll] = useState(false);
const [teamMembers, setTeamMembers] = useState([]);
const [toDelete, setToDelete] = useState(null);
+ const [unapproved, setUnapproved] = useState([]);
const [validationMessage, setValidationMessage] = useState(null);
const loadedReviews = useRef(false);
@@ -357,7 +364,7 @@ const TeamReviews = ({ onBack, periodId }) => {
payload: toDelete
});
handleConfirmDeleteClose();
- history.goBack();
+ onBack();
}, [csrf, dispatch, toDelete, handleConfirmDeleteClose]);
const getReviewers = useCallback(
@@ -592,14 +599,10 @@ const TeamReviews = ({ onBack, periodId }) => {
member => getReviewers(member).length > 0
);
if (!haveReviewers) return 'One or more members have no reviewer.';
- return null;
+ return null; // no validtation errors
};
- const requestApproval = async () => {
- const msg = validateReviewPeriod(period);
- setValidationMessage(msg);
- if (msg) return;
-
+ const launchReviewPeriod = async () => {
try {
const res = await resolve({
method: 'PUT',
@@ -611,7 +614,7 @@ const TeamReviews = ({ onBack, periodId }) => {
},
data: {
...period,
- reviewStatus: ReviewStatus.AWAITING_APPROVAL
+ reviewStatus: ReviewStatus.OPEN
}
});
if (res.error) throw new Error(res.error.message);
@@ -621,6 +624,35 @@ const TeamReviews = ({ onBack, periodId }) => {
}
};
+ const requestApproval = async () => {
+ const msg = validateReviewPeriod(period);
+ setValidationMessage(msg);
+ if (msg) return;
+
+ const visibleIds = new Set(visibleTeamMembers().map(m => m.id));
+ const unapproved = assignments.filter(
+ a => !a.approved && visibleIds.has(a.revieweeId)
+ );
+ /* For debugging ...
+ for (const assignment of unapproved) {
+ const reviewee = currentMembers.find(m => m.id === assignment.revieweeId);
+ const reviewer = currentMembers.find(m => m.id === assignment.reviewerId);
+ console.log(reviewer.name, 'reviewing', reviewee.name, 'is unapproved.');
+ }
+ */
+ setUnapproved(unapproved);
+ setConfirmationText(
+ unapproved.length === 0
+ ? 'Are you sure you want to launch the review period?'
+ : unapproved.length === 1
+ ? 'There is one visible, unapproved review assignment. ' +
+ 'Would you like to approve it and launch this review period?'
+ : `There are ${unapproved.length} visible, unapproved review assignments. ` +
+ 'Would you like to approve all of them and launch this review period?'
+ );
+ setConfirmationDialogOpen(true);
+ };
+
const compareStrings = (s1, s2) => (s1 || '').localeCompare(s2 || '');
const sortMembers = members =>
@@ -725,6 +757,13 @@ const TeamReviews = ({ onBack, periodId }) => {
setConfirmApproveAllOpen(false);
};
+ const approveAllAndLaunch = () => {
+ if (unapproved.length) approveAll();
+ launchReviewPeriod();
+ setConfirmationDialogOpen(false);
+ onBack();
+ };
+
const unapproveAll = () => {
visibleTeamMembers().map(member => approveMember(member, false));
};
@@ -1001,6 +1040,34 @@ const TeamReviews = ({ onBack, periodId }) => {
+ setConfirmationDialogOpen(false)}
+ open={confirmationDialogOpen}
+ >
+
+
+ Approve and Launch
+
+ }
+ />
+
+ {confirmationText}
+
+
+
+
+
+
+
);
};
diff --git a/web-ui/src/components/view_feedback_responses/__snapshots__/ViewFeedbackResponses.test.jsx.snap b/web-ui/src/components/view_feedback_responses/__snapshots__/ViewFeedbackResponses.test.jsx.snap
index a06ea71fac..e2d28e9e50 100644
--- a/web-ui/src/components/view_feedback_responses/__snapshots__/ViewFeedbackResponses.test.jsx.snap
+++ b/web-ui/src/components/view_feedback_responses/__snapshots__/ViewFeedbackResponses.test.jsx.snap
@@ -82,7 +82,7 @@ exports[`renders correctly 1`] = `