-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* use id instead of index for object details and scrolling * long press package and hook * fix long press in review * search action group * multi select in explore * add bulk deletion to backend api * clean up * mimic behavior of review * don't open dialog on left click when mutli selecting * context menu on container ref * revert long press code * clean up
- Loading branch information
1 parent
5475672
commit 5f42caa
Showing
9 changed files
with
447 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
import { useCallback, useState } from "react"; | ||
import axios from "axios"; | ||
import { Button, buttonVariants } from "../ui/button"; | ||
import { isDesktop } from "react-device-detect"; | ||
import { HiTrash } from "react-icons/hi"; | ||
import { | ||
AlertDialog, | ||
AlertDialogAction, | ||
AlertDialogCancel, | ||
AlertDialogContent, | ||
AlertDialogDescription, | ||
AlertDialogFooter, | ||
AlertDialogHeader, | ||
AlertDialogTitle, | ||
} from "../ui/alert-dialog"; | ||
import useKeyboardListener from "@/hooks/use-keyboard-listener"; | ||
import { toast } from "sonner"; | ||
|
||
type SearchActionGroupProps = { | ||
selectedObjects: string[]; | ||
setSelectedObjects: (ids: string[]) => void; | ||
pullLatestData: () => void; | ||
}; | ||
export default function SearchActionGroup({ | ||
selectedObjects, | ||
setSelectedObjects, | ||
pullLatestData, | ||
}: SearchActionGroupProps) { | ||
const onClearSelected = useCallback(() => { | ||
setSelectedObjects([]); | ||
}, [setSelectedObjects]); | ||
|
||
const onDelete = useCallback(async () => { | ||
await axios | ||
.delete(`events/`, { | ||
data: { event_ids: selectedObjects }, | ||
}) | ||
.then((resp) => { | ||
if (resp.status == 200) { | ||
toast.success("Tracked objects deleted successfully.", { | ||
position: "top-center", | ||
}); | ||
setSelectedObjects([]); | ||
pullLatestData(); | ||
} | ||
}) | ||
.catch(() => { | ||
toast.error("Failed to delete tracked objects.", { | ||
position: "top-center", | ||
}); | ||
}); | ||
}, [selectedObjects, setSelectedObjects, pullLatestData]); | ||
|
||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); | ||
const [bypassDialog, setBypassDialog] = useState(false); | ||
|
||
useKeyboardListener(["Shift"], (_, modifiers) => { | ||
setBypassDialog(modifiers.shift); | ||
}); | ||
|
||
const handleDelete = useCallback(() => { | ||
if (bypassDialog) { | ||
onDelete(); | ||
} else { | ||
setDeleteDialogOpen(true); | ||
} | ||
}, [bypassDialog, onDelete]); | ||
|
||
return ( | ||
<> | ||
<AlertDialog | ||
open={deleteDialogOpen} | ||
onOpenChange={() => setDeleteDialogOpen(!deleteDialogOpen)} | ||
> | ||
<AlertDialogContent> | ||
<AlertDialogHeader> | ||
<AlertDialogTitle>Confirm Delete</AlertDialogTitle> | ||
</AlertDialogHeader> | ||
<AlertDialogDescription> | ||
Deleting these {selectedObjects.length} tracked objects removes the | ||
snapshot, any saved embeddings, and any associated object lifecycle | ||
entries. Recorded footage of these tracked objects in History view | ||
will <em>NOT</em> be deleted. | ||
<br /> | ||
<br /> | ||
Are you sure you want to proceed? | ||
<br /> | ||
<br /> | ||
Hold the <em>Shift</em> key to bypass this dialog in the future. | ||
</AlertDialogDescription> | ||
<AlertDialogFooter> | ||
<AlertDialogCancel>Cancel</AlertDialogCancel> | ||
<AlertDialogAction | ||
className={buttonVariants({ variant: "destructive" })} | ||
onClick={onDelete} | ||
> | ||
Delete | ||
</AlertDialogAction> | ||
</AlertDialogFooter> | ||
</AlertDialogContent> | ||
</AlertDialog> | ||
|
||
<div className="absolute inset-x-2 inset-y-0 flex items-center justify-between gap-2 bg-background py-2 md:left-auto"> | ||
<div className="mx-1 flex items-center justify-center text-sm text-muted-foreground"> | ||
<div className="p-1">{`${selectedObjects.length} selected`}</div> | ||
<div className="p-1">{"|"}</div> | ||
<div | ||
className="cursor-pointer p-2 text-primary hover:rounded-lg hover:bg-secondary" | ||
onClick={onClearSelected} | ||
> | ||
Unselect | ||
</div> | ||
</div> | ||
<div className="flex items-center gap-1 md:gap-2"> | ||
<Button | ||
className="flex items-center gap-2 p-2" | ||
aria-label="Delete" | ||
size="sm" | ||
onClick={handleDelete} | ||
> | ||
<HiTrash className="text-secondary-foreground" /> | ||
{isDesktop && ( | ||
<div className="text-primary"> | ||
{bypassDialog ? "Delete Now" : "Delete"} | ||
</div> | ||
)} | ||
</Button> | ||
</div> | ||
</div> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// https://gist.github.com/cpojer/641bf305e6185006ea453e7631b80f95 | ||
|
||
import { useCallback, useState } from "react"; | ||
import { | ||
LongPressCallbackMeta, | ||
LongPressReactEvents, | ||
useLongPress, | ||
} from "use-long-press"; | ||
|
||
export default function usePress( | ||
options: Omit<Parameters<typeof useLongPress>[1], "onCancel" | "onStart"> & { | ||
onLongPress: NonNullable<Parameters<typeof useLongPress>[0]>; | ||
onPress: (event: LongPressReactEvents<Element>) => void; | ||
}, | ||
) { | ||
const { onLongPress, onPress, ...actualOptions } = options; | ||
const [hasLongPress, setHasLongPress] = useState(false); | ||
|
||
const onCancel = useCallback(() => { | ||
if (hasLongPress) { | ||
setHasLongPress(false); | ||
} | ||
}, [hasLongPress]); | ||
|
||
const bind = useLongPress( | ||
useCallback( | ||
( | ||
event: LongPressReactEvents<Element>, | ||
meta: LongPressCallbackMeta<unknown>, | ||
) => { | ||
setHasLongPress(true); | ||
onLongPress(event, meta); | ||
}, | ||
[onLongPress], | ||
), | ||
{ | ||
...actualOptions, | ||
onCancel, | ||
onStart: onCancel, | ||
}, | ||
); | ||
|
||
return useCallback( | ||
() => ({ | ||
...bind(), | ||
onClick: (event: LongPressReactEvents<HTMLDivElement>) => { | ||
if (!hasLongPress) { | ||
onPress(event); | ||
} | ||
}, | ||
}), | ||
[bind, hasLongPress, onPress], | ||
); | ||
} |
Oops, something went wrong.