Update api to use json and add button to mark all as reviewed

This commit is contained in:
Nicolas Mowen 2024-03-05 14:29:27 -07:00
parent 8f28dc0b9c
commit 33e98b4043
5 changed files with 35 additions and 29 deletions

View File

@ -195,26 +195,10 @@ def review_summary():
return jsonify([e for e in groups.dicts().iterator()]) return jsonify([e for e in groups.dicts().iterator()])
@ReviewBp.route("/review/<id>/viewed", methods=("POST",)) @ReviewBp.route("/reviews/viewed", methods=("POST",))
def set_reviewed(id): def set_multiple_reviewed():
try: json: dict[str, any] = request.get_json(silent=True) or {}
review: ReviewSegment = ReviewSegment.get(ReviewSegment.id == id) list_of_ids = json.get("ids", "")
except DoesNotExist:
return make_response(
jsonify({"success": False, "message": "Review " + id + " not found"}), 404
)
review.has_been_reviewed = True
review.save()
return make_response(
jsonify({"success": True, "message": "Reviewed " + id + " viewed"}), 200
)
@ReviewBp.route("/reviews/<ids>/viewed", methods=("POST",))
def set_multiple_reviewed(ids: str):
list_of_ids = ids.split(",")
if not list_of_ids or len(list_of_ids) == 0: if not list_of_ids or len(list_of_ids) == 0:
return make_response( return make_response(

View File

@ -22,7 +22,7 @@ export default function ReviewActionGroup({
const onMarkAsReviewed = useCallback(async () => { const onMarkAsReviewed = useCallback(async () => {
const idList = selectedReviews.join(","); const idList = selectedReviews.join(",");
await axios.post(`reviews/${idList}/viewed`); await axios.post(`reviews/viewed`, { ids: idList });
setSelectedReviews([]); setSelectedReviews([]);
pullLatestData(); pullLatestData();
}, [selectedReviews, setSelectedReviews, pullLatestData]); }, [selectedReviews, setSelectedReviews, pullLatestData]);

View File

@ -9,7 +9,7 @@ const buttonVariants = cva(
{ {
variants: { variants: {
variant: { variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90", default: "bg-selected text-primary-foreground hover:bg-opacity-60",
destructive: destructive:
"bg-destructive text-destructive-foreground hover:bg-destructive/90", "bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline: outline:

View File

@ -164,7 +164,7 @@ export default function Events() {
const markItemAsReviewed = useCallback( const markItemAsReviewed = useCallback(
async (review: ReviewSegment) => { async (review: ReviewSegment) => {
const resp = await axios.post(`review/${review.id}/viewed`); const resp = await axios.post(`reviews/viewed`, { ids: [review.id] });
if (resp.status == 200) { if (resp.status == 200) {
updateSegments( updateSegments(

View File

@ -35,6 +35,7 @@ import { LuFolderCheck } from "react-icons/lu";
import { MdCircle } from "react-icons/md"; import { MdCircle } from "react-icons/md";
import useSWR from "swr"; import useSWR from "swr";
import MotionReviewTimeline from "@/components/timeline/MotionReviewTimeline"; import MotionReviewTimeline from "@/components/timeline/MotionReviewTimeline";
import { Button } from "@/components/ui/button";
type EventViewProps = { type EventViewProps = {
reviewPages?: ReviewSegment[][]; reviewPages?: ReviewSegment[][];
@ -241,9 +242,7 @@ export default function EventView({
aria-label="Select motion" aria-label="Select motion"
> >
<MdCircle className="size-2 md:mr-[10px] text-severity_motion" /> <MdCircle className="size-2 md:mr-[10px] text-severity_motion" />
<div className="hidden md:block"> <div className="hidden md:block">Motion</div>
Motion {reviewCounts.significant_motion}
</div>
</ToggleGroupItem> </ToggleGroupItem>
</ToggleGroup> </ToggleGroup>
@ -303,6 +302,7 @@ type DetectionReviewProps = {
detection: ReviewSegment[]; detection: ReviewSegment[];
significant_motion: ReviewSegment[]; significant_motion: ReviewSegment[];
}; };
itemsToReview?: number;
relevantPreviews?: Preview[]; relevantPreviews?: Preview[];
pagingObserver: MutableRefObject<IntersectionObserver | null>; pagingObserver: MutableRefObject<IntersectionObserver | null>;
selectedReviews: string[]; selectedReviews: string[];
@ -320,6 +320,7 @@ function DetectionReview({
contentRef, contentRef,
currentItems, currentItems,
reviewItems, reviewItems,
itemsToReview,
relevantPreviews, relevantPreviews,
pagingObserver, pagingObserver,
selectedReviews, selectedReviews,
@ -359,6 +360,17 @@ function DetectionReview({
[isValidating, pagingObserver, reachedEnd, loadNextPage], [isValidating, pagingObserver, reachedEnd, loadNextPage],
); );
const markAllReviewed = useCallback(async () => {
if (!currentItems) {
return;
}
await axios.post(`reviews/viewed`, {
ids: currentItems?.map((seg) => seg.id),
});
pullLatestData();
}, [currentItems, pullLatestData]);
// timeline interaction // timeline interaction
const { alignStartDateToTimeline } = useEventUtils( const { alignStartDateToTimeline } = useEventUtils(
@ -453,7 +465,7 @@ function DetectionReview({
/> />
)} )}
{!isValidating && currentItems == null && ( {(itemsToReview == 0 || (currentItems == null && !isValidating)) && (
<div className="size-full flex flex-col justify-center items-center"> <div className="size-full flex flex-col justify-center items-center">
<LuFolderCheck className="size-16" /> <LuFolderCheck className="size-16" />
There are no {severity.replace(/_/g, " ")} items to review There are no {severity.replace(/_/g, " ")} items to review
@ -489,13 +501,23 @@ function DetectionReview({
onClick={onSelectReview} onClick={onSelectReview}
/> />
</div> </div>
{lastRow && !reachedEnd && <ActivityIndicator />}
</div> </div>
); );
}) })
) : severity != "alert" ? ( ) : itemsToReview != 0 ? (
<div ref={lastReviewRef} /> <div ref={lastReviewRef} />
) : null} ) : null}
{currentItems && (
<div className="col-span-full flex justify-center items-center">
{reachedEnd ? (
<Button className="text-white" onClick={markAllReviewed}>
Mark all items as reviewed
</Button>
) : (
<ActivityIndicator />
)}
</div>
)}
</div> </div>
</div> </div>
<div className="w-[55px] md:w-[100px] mt-2 overflow-y-auto no-scrollbar"> <div className="w-[55px] md:w-[100px] mt-2 overflow-y-auto no-scrollbar">