From af320c8c093348e8c4a6a12f5e1738fa80b4c8d6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 7 Apr 2024 06:13:26 -0600 Subject: [PATCH 01/29] Bump actions/setup-python from 5.0.0 to 5.1.0 (#10703) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5.0.0 to 5.1.0. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v5.0.0...v5.1.0) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pull_request.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index ca10bfc3d..26d729bdd 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -65,7 +65,7 @@ jobs: - name: Check out the repository uses: actions/checkout@v4 - name: Set up Python ${{ env.DEFAULT_PYTHON }} - uses: actions/setup-python@v5.0.0 + uses: actions/setup-python@v5.1.0 with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Install requirements From b26ceff44d40421685ab42471a557f6a35112cfd Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Sun, 7 Apr 2024 14:35:45 -0600 Subject: [PATCH 02/29] Add ability to search exports (#10850) * Add ability to search exports * Fix export saving --- web/src/components/card/ExportCard.tsx | 10 ++- web/src/components/overlay/ExportDialog.tsx | 11 +-- .../overlay/MobileReviewSettingsDrawer.tsx | 11 +-- web/src/pages/Export.tsx | 67 ++++++++++++++----- 4 files changed, 72 insertions(+), 27 deletions(-) diff --git a/web/src/components/card/ExportCard.tsx b/web/src/components/card/ExportCard.tsx index 7431781ea..5ebd4be80 100644 --- a/web/src/components/card/ExportCard.tsx +++ b/web/src/components/card/ExportCard.tsx @@ -12,6 +12,7 @@ import { Input } from "../ui/input"; import useKeyboardListener from "@/hooks/use-keyboard-listener"; type ExportProps = { + className: string; file: { name: string; }; @@ -19,7 +20,12 @@ type ExportProps = { onDelete: (file: string) => void; }; -export default function ExportCard({ file, onRename, onDelete }: ExportProps) { +export default function ExportCard({ + className, + file, + onRename, + onDelete, +}: ExportProps) { const videoRef = useRef(null); const [hovered, setHovered] = useState(false); const [playing, setPlaying] = useState(false); @@ -94,7 +100,7 @@ export default function ExportCard({ file, onRename, onDelete }: ExportProps) {
setHovered(true) : undefined } diff --git a/web/src/components/overlay/ExportDialog.tsx b/web/src/components/overlay/ExportDialog.tsx index 6468c2d16..924de2ffa 100644 --- a/web/src/components/overlay/ExportDialog.tsx +++ b/web/src/components/overlay/ExportDialog.tsx @@ -64,10 +64,13 @@ export default function ExportDialog({ } axios - .post(`export/${camera}/start/${range.after}/end/${range.before}`, { - playback: "realtime", - name, - }) + .post( + `export/${camera}/start/${Math.round(range.after)}/end/${Math.round(range.before)}`, + { + playback: "realtime", + name, + }, + ) .then((response) => { if (response.status == 200) { toast.success( diff --git a/web/src/components/overlay/MobileReviewSettingsDrawer.tsx b/web/src/components/overlay/MobileReviewSettingsDrawer.tsx index 26c6d9bbc..da5c6ec6a 100644 --- a/web/src/components/overlay/MobileReviewSettingsDrawer.tsx +++ b/web/src/components/overlay/MobileReviewSettingsDrawer.tsx @@ -66,10 +66,13 @@ export default function MobileReviewSettingsDrawer({ } axios - .post(`export/${camera}/start/${range.after}/end/${range.before}`, { - playback: "realtime", - name, - }) + .post( + `export/${camera}/start/${Math.round(range.after)}/end/${Math.round(range.before)}`, + { + playback: "realtime", + name, + }, + ) .then((response) => { if (response.status == 200) { toast.success( diff --git a/web/src/pages/Export.tsx b/web/src/pages/Export.tsx index a5f775419..dfd524e44 100644 --- a/web/src/pages/Export.tsx +++ b/web/src/pages/Export.tsx @@ -10,8 +10,9 @@ import { AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; import axios from "axios"; -import { useCallback, useState } from "react"; +import { useCallback, useMemo, useState } from "react"; import useSWR from "swr"; type ExportItem = { @@ -19,24 +20,30 @@ type ExportItem = { }; function Export() { - const { data: exports, mutate } = useSWR( + const { data: allExports, mutate } = useSWR( "exports/", (url: string) => axios({ baseURL: baseUrl, url }).then((res) => res.data), ); - const [deleteClip, setDeleteClip] = useState(); + // Search - const onHandleRename = useCallback( - (original: string, update: string) => { - axios.patch(`export/${original}/${update}`).then((response) => { - if (response.status == 200) { - setDeleteClip(undefined); - mutate(); - } - }); - }, - [mutate], - ); + const [search, setSearch] = useState(""); + + const exports = useMemo(() => { + if (!search || !allExports) { + return allExports; + } + + return allExports.filter((exp) => + exp.name + .toLowerCase() + .includes(search.toLowerCase().replaceAll(" ", "_")), + ); + }, [allExports, search]); + + // Deleting + + const [deleteClip, setDeleteClip] = useState(); const onHandleDelete = useCallback(() => { if (!deleteClip) { @@ -51,8 +58,22 @@ function Export() { }); }, [deleteClip, mutate]); + // Renaming + + const onHandleRename = useCallback( + (original: string, update: string) => { + axios.patch(`export/${original}/${update}`).then((response) => { + if (response.status == 200) { + setDeleteClip(undefined); + mutate(); + } + }); + }, + [mutate], + ); + return ( -
+
setDeleteClip(undefined)} @@ -73,12 +94,24 @@ function Export() { +
+ setSearch(e.target.value)} + /> +
+
- {exports && ( + {allExports && exports && (
- {Object.values(exports).map((item) => ( + {Object.values(allExports).map((item) => ( setDeleteClip(file)} From cf2dfd9a54dedf18a2a7d554a25733bfe9ce0cfe Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Sun, 7 Apr 2024 14:36:08 -0600 Subject: [PATCH 03/29] Redesign logs page (#10853) * Adjust outline and structure to match designs * More color changes to fit design * Properly parse go2rtc severity * Add ability to filter by clicking item * Implement sheet / drawer for viewing full log * Add toast and filtering * Add links to docs when specific log items are selected * Cleanup log seeking * Use header in layout * Fix mobile menus * Fix safari theme * Hide rings * Theme adjustment --- web/src/components/filter/LogLevelFilter.tsx | 126 ++++++++++ .../components/filter/ReviewFilterGroup.tsx | 4 +- web/src/components/indicators/Chip.tsx | 35 ++- web/src/components/overlay/LogInfoDialog.tsx | 129 ++++++++++ .../components/settings/GeneralSettings.tsx | 8 +- web/src/pages/Logs.tsx | 221 ++++++++++-------- web/src/pages/SubmitPlus.tsx | 1 + web/tailwind.config.js | 8 +- web/themes/theme-default.css | 36 ++- 9 files changed, 449 insertions(+), 119 deletions(-) create mode 100644 web/src/components/filter/LogLevelFilter.tsx create mode 100644 web/src/components/overlay/LogInfoDialog.tsx diff --git a/web/src/components/filter/LogLevelFilter.tsx b/web/src/components/filter/LogLevelFilter.tsx new file mode 100644 index 000000000..4eb19d350 --- /dev/null +++ b/web/src/components/filter/LogLevelFilter.tsx @@ -0,0 +1,126 @@ +import { Button } from "../ui/button"; +import { FaFilter } from "react-icons/fa"; +import { isMobile } from "react-device-detect"; +import { Drawer, DrawerContent, DrawerTrigger } from "../ui/drawer"; +import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover"; +import { LogSeverity } from "@/types/log"; +import { Label } from "../ui/label"; +import { Switch } from "../ui/switch"; +import { DropdownMenuSeparator } from "../ui/dropdown-menu"; + +type LogLevelFilterButtonProps = { + selectedLabels?: LogSeverity[]; + updateLabelFilter: (labels: LogSeverity[] | undefined) => void; +}; +export function LogLevelFilterButton({ + selectedLabels, + updateLabelFilter, +}: LogLevelFilterButtonProps) { + const trigger = ( + + ); + const content = ( + + ); + + if (isMobile) { + return ( + + {trigger} + + {content} + + + ); + } + + return ( + + {trigger} + {content} + + ); +} + +type GeneralFilterContentProps = { + selectedLabels: LogSeverity[] | undefined; + updateLabelFilter: (labels: LogSeverity[] | undefined) => void; +}; +export function GeneralFilterContent({ + selectedLabels, + updateLabelFilter, +}: GeneralFilterContentProps) { + return ( + <> +
+
+ + { + if (isChecked) { + updateLabelFilter(undefined); + } + }} + /> +
+ +
+ {["debug", "info", "warning", "error"].map((item) => ( +
+ + { + if (isChecked) { + const updatedLabels = selectedLabels + ? [...selectedLabels] + : []; + + updatedLabels.push(item as LogSeverity); + updateLabelFilter(updatedLabels); + } else { + const updatedLabels = selectedLabels + ? [...selectedLabels] + : []; + + // can not deselect the last item + if (updatedLabels.length > 1) { + updatedLabels.splice( + updatedLabels.indexOf(item as LogSeverity), + 1, + ); + updateLabelFilter(updatedLabels); + } + } + }} + /> +
+ ))} +
+
+ + + ); +} diff --git a/web/src/components/filter/ReviewFilterGroup.tsx b/web/src/components/filter/ReviewFilterGroup.tsx index a3c3fadbc..91e390847 100644 --- a/web/src/components/filter/ReviewFilterGroup.tsx +++ b/web/src/components/filter/ReviewFilterGroup.tsx @@ -567,7 +567,7 @@ export function GeneralFilterContent({ {allLabels.map((item) => (