mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-15 07:35:27 +03:00
fix input for time_range filter
This commit is contained in:
parent
c0c81ef3f2
commit
a33bc563bc
@ -172,9 +172,9 @@ export default function SearchFilterGroup({
|
|||||||
)}
|
)}
|
||||||
{filters.includes("time") && (
|
{filters.includes("time") && (
|
||||||
<TimeRangeFilterButton
|
<TimeRangeFilterButton
|
||||||
timeRange={filter?.timeRange}
|
timeRange={filter?.time_range}
|
||||||
updateTimeRange={(timeRange) =>
|
updateTimeRange={(time_range) =>
|
||||||
onUpdateFilter({ ...filter, timeRange })
|
onUpdateFilter({ ...filter, time_range })
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@ -199,9 +199,9 @@ export default function SearchFilterGroup({
|
|||||||
{filters.includes("sub") && (
|
{filters.includes("sub") && (
|
||||||
<SubFilterButton
|
<SubFilterButton
|
||||||
allSubLabels={allSubLabels}
|
allSubLabels={allSubLabels}
|
||||||
selectedSubLabels={filter?.subLabels}
|
selectedSubLabels={filter?.sub_labels}
|
||||||
updateSubLabelFilter={(newSubLabels) =>
|
updateSubLabelFilter={(newSubLabels) =>
|
||||||
onUpdateFilter({ ...filter, subLabels: newSubLabels })
|
onUpdateFilter({ ...filter, sub_labels: newSubLabels })
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -35,9 +35,13 @@ import { SaveSearchDialog } from "./SaveSearchDialog";
|
|||||||
import { DeleteSearchDialog } from "./DeleteSearchDialog";
|
import { DeleteSearchDialog } from "./DeleteSearchDialog";
|
||||||
import {
|
import {
|
||||||
convertLocalDateToTimestamp,
|
convertLocalDateToTimestamp,
|
||||||
|
convertTo12Hour,
|
||||||
getIntlDateFormat,
|
getIntlDateFormat,
|
||||||
|
isValidTimeRange,
|
||||||
} from "@/utils/dateUtil";
|
} from "@/utils/dateUtil";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
import useSWR from "swr";
|
||||||
|
import { FrigateConfig } from "@/types/frigateConfig";
|
||||||
|
|
||||||
type InputWithTagsProps = {
|
type InputWithTagsProps = {
|
||||||
filters: SearchFilter;
|
filters: SearchFilter;
|
||||||
@ -56,6 +60,10 @@ export default function InputWithTags({
|
|||||||
setSearch,
|
setSearch,
|
||||||
allSuggestions,
|
allSuggestions,
|
||||||
}: InputWithTagsProps) {
|
}: InputWithTagsProps) {
|
||||||
|
const { data: config } = useSWR<FrigateConfig>("config", {
|
||||||
|
revalidateOnFocus: false,
|
||||||
|
});
|
||||||
|
|
||||||
const [inputValue, setInputValue] = useState(search || "");
|
const [inputValue, setInputValue] = useState(search || "");
|
||||||
const [currentFilterType, setCurrentFilterType] = useState<FilterType | null>(
|
const [currentFilterType, setCurrentFilterType] = useState<FilterType | null>(
|
||||||
null,
|
null,
|
||||||
@ -183,7 +191,6 @@ export default function InputWithTags({
|
|||||||
if (allSuggestions[type as FilterType]?.includes(value)) {
|
if (allSuggestions[type as FilterType]?.includes(value)) {
|
||||||
const newFilters = { ...filters };
|
const newFilters = { ...filters };
|
||||||
let timestamp = 0;
|
let timestamp = 0;
|
||||||
let times = ["", ""];
|
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "before":
|
case "before":
|
||||||
@ -223,18 +230,19 @@ export default function InputWithTags({
|
|||||||
newFilters[type] = timestamp / 1000;
|
newFilters[type] = timestamp / 1000;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "timeRange":
|
case "time_range":
|
||||||
if (!value.includes(",")) {
|
if (!value.includes(",")) {
|
||||||
toast.error("The correct format is after,before.", {
|
toast.error(
|
||||||
|
"The correct format is after,before. Example: 15:00,18:00.",
|
||||||
|
{
|
||||||
position: "top-center",
|
position: "top-center",
|
||||||
});
|
},
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
times = value.split(",");
|
if (!isValidTimeRange(value)) {
|
||||||
|
toast.error("Time range is not valid.", {
|
||||||
if (times[0] < "00" || times[1] > "24") {
|
|
||||||
toast.error("Times not in valid range", {
|
|
||||||
position: "top-center",
|
position: "top-center",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@ -276,6 +284,30 @@ export default function InputWithTags({
|
|||||||
[filters, setFilters, allSuggestions],
|
[filters, setFilters, allSuggestions],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function formatFilterValues(
|
||||||
|
filterType: string,
|
||||||
|
filterValues: number | string,
|
||||||
|
): string {
|
||||||
|
if (filterType === "before" || filterType === "after") {
|
||||||
|
return new Date(
|
||||||
|
(filterType === "before"
|
||||||
|
? (filterValues as number) + 1
|
||||||
|
: (filterValues as number)) * 1000,
|
||||||
|
).toLocaleDateString(window.navigator?.language || "en-US");
|
||||||
|
} else if (filterType === "time_range") {
|
||||||
|
const [startTime, endTime] = (filterValues as string).split(",");
|
||||||
|
return `${
|
||||||
|
config?.ui.time_format === "24hour"
|
||||||
|
? startTime
|
||||||
|
: convertTo12Hour(startTime)
|
||||||
|
} - ${
|
||||||
|
config?.ui.time_format === "24hour" ? endTime : convertTo12Hour(endTime)
|
||||||
|
}`;
|
||||||
|
} else {
|
||||||
|
return filterValues as string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// handlers
|
// handlers
|
||||||
|
|
||||||
const handleFilterCreation = useCallback(
|
const handleFilterCreation = useCallback(
|
||||||
@ -624,16 +656,8 @@ export default function InputWithTags({
|
|||||||
key={filterType}
|
key={filterType}
|
||||||
className="inline-flex items-center whitespace-nowrap rounded-full bg-green-100 px-2 py-0.5 text-sm capitalize text-green-800"
|
className="inline-flex items-center whitespace-nowrap rounded-full bg-green-100 px-2 py-0.5 text-sm capitalize text-green-800"
|
||||||
>
|
>
|
||||||
{filterType}:
|
{filterType.replaceAll("_", " ")}:{" "}
|
||||||
{filterType === "before" || filterType === "after"
|
{formatFilterValues(filterType, filterValues)}
|
||||||
? new Date(
|
|
||||||
(filterType === "before"
|
|
||||||
? (filterValues as number) + 1
|
|
||||||
: (filterValues as number)) * 1000,
|
|
||||||
).toLocaleDateString(
|
|
||||||
window.navigator?.language || "en-US",
|
|
||||||
)
|
|
||||||
: filterValues}
|
|
||||||
<button
|
<button
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
removeFilter(
|
removeFilter(
|
||||||
|
|||||||
@ -70,11 +70,11 @@ export default function Explore() {
|
|||||||
{
|
{
|
||||||
cameras: searchSearchParams["cameras"],
|
cameras: searchSearchParams["cameras"],
|
||||||
labels: searchSearchParams["labels"],
|
labels: searchSearchParams["labels"],
|
||||||
sub_labels: searchSearchParams["subLabels"],
|
sub_labels: searchSearchParams["sub_labels"],
|
||||||
zones: searchSearchParams["zones"],
|
zones: searchSearchParams["zones"],
|
||||||
before: searchSearchParams["before"],
|
before: searchSearchParams["before"],
|
||||||
after: searchSearchParams["after"],
|
after: searchSearchParams["after"],
|
||||||
time_range: searchSearchParams["timeRange"],
|
time_range: searchSearchParams["time_range"],
|
||||||
search_type: searchSearchParams["search_type"],
|
search_type: searchSearchParams["search_type"],
|
||||||
limit:
|
limit:
|
||||||
Object.keys(searchSearchParams).length == 0 ? API_LIMIT : undefined,
|
Object.keys(searchSearchParams).length == 0 ? API_LIMIT : undefined,
|
||||||
@ -96,10 +96,11 @@ export default function Explore() {
|
|||||||
query: similaritySearch ? undefined : searchTerm,
|
query: similaritySearch ? undefined : searchTerm,
|
||||||
cameras: searchSearchParams["cameras"],
|
cameras: searchSearchParams["cameras"],
|
||||||
labels: searchSearchParams["labels"],
|
labels: searchSearchParams["labels"],
|
||||||
sub_labels: searchSearchParams["subLabels"],
|
sub_labels: searchSearchParams["sub_labels"],
|
||||||
zones: searchSearchParams["zones"],
|
zones: searchSearchParams["zones"],
|
||||||
before: searchSearchParams["before"],
|
before: searchSearchParams["before"],
|
||||||
after: searchSearchParams["after"],
|
after: searchSearchParams["after"],
|
||||||
|
time_range: searchSearchParams["time_range"],
|
||||||
search_type: searchSearchParams["search_type"],
|
search_type: searchSearchParams["search_type"],
|
||||||
event_id: searchSearchParams["event_id"],
|
event_id: searchSearchParams["event_id"],
|
||||||
include_thumbnails: 0,
|
include_thumbnails: 0,
|
||||||
|
|||||||
@ -52,11 +52,11 @@ export type SearchFilter = {
|
|||||||
query?: string;
|
query?: string;
|
||||||
cameras?: string[];
|
cameras?: string[];
|
||||||
labels?: string[];
|
labels?: string[];
|
||||||
subLabels?: string[];
|
sub_labels?: string[];
|
||||||
zones?: string[];
|
zones?: string[];
|
||||||
before?: number;
|
before?: number;
|
||||||
after?: number;
|
after?: number;
|
||||||
timeRange?: string;
|
time_range?: string;
|
||||||
search_type?: SearchSource[];
|
search_type?: SearchSource[];
|
||||||
event_id?: string;
|
event_id?: string;
|
||||||
};
|
};
|
||||||
@ -74,6 +74,7 @@ export type SearchQueryParams = {
|
|||||||
include_thumbnails?: number;
|
include_thumbnails?: number;
|
||||||
query?: string;
|
query?: string;
|
||||||
page?: number;
|
page?: number;
|
||||||
|
time_range?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SearchQuery = [string, SearchQueryParams] | null;
|
export type SearchQuery = [string, SearchQueryParams] | null;
|
||||||
|
|||||||
@ -373,3 +373,35 @@ export function getIntlDateFormat() {
|
|||||||
}, [] as string[])
|
}, [] as string[])
|
||||||
.join("");
|
.join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isValidTimeRange(rangeString: string): boolean {
|
||||||
|
const range = rangeString.split(",");
|
||||||
|
|
||||||
|
if (range.length !== 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const toMinutes = (time: string): number => {
|
||||||
|
const [h, m] = time.split(":").map(Number);
|
||||||
|
return h * 60 + m;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isValidTime = (time: string): boolean =>
|
||||||
|
/^(?:([01]\d|2[0-3]):([0-5]\d)|24:00)$/.test(time);
|
||||||
|
|
||||||
|
const [startTime, endTime] = range;
|
||||||
|
|
||||||
|
return (
|
||||||
|
isValidTime(startTime) &&
|
||||||
|
isValidTime(endTime) &&
|
||||||
|
toMinutes(startTime) < toMinutes(endTime)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function convertTo12Hour(time: string) {
|
||||||
|
const [hours, minutes] = time.split(":");
|
||||||
|
const hour = parseInt(hours, 10);
|
||||||
|
const ampm = hour >= 12 ? "PM" : "AM";
|
||||||
|
const hour12 = hour % 12 || 12;
|
||||||
|
return `${hour12}:${minutes} ${ampm}`;
|
||||||
|
}
|
||||||
|
|||||||
@ -120,6 +120,7 @@ export default function SearchView({
|
|||||||
zones: Object.values(allZones || {}),
|
zones: Object.values(allZones || {}),
|
||||||
sub_labels: allSubLabels,
|
sub_labels: allSubLabels,
|
||||||
search_type: ["thumbnail", "description"] as SearchSource[],
|
search_type: ["thumbnail", "description"] as SearchSource[],
|
||||||
|
time_range: ["00:00,24:00"],
|
||||||
}),
|
}),
|
||||||
[config, allLabels, allZones, allSubLabels],
|
[config, allLabels, allZones, allSubLabels],
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user