feat: polish release v2 experience (#6800)
This commit is contained in:
1 parent
925b0fb801
commit
a4a903d7c3
295 files changed
+10627
-7115
No files matched your search
@@ -3,10 +3,12 @@
|
||||
import type { ChangeEvent } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
import { Loader, TextInput } from "@mantine/core";
|
||||
import { Input, Loader, TextInput } from "@mantine/core";
|
||||
import { useDebouncedCallback } from "@mantine/hooks";
|
||||
import { IconSearch } from "@tabler/icons-react";
|
||||
|
||||
import { useI18n } from "@homarr/translation/client";
|
||||
|
||||
interface SearchInputProps {
|
||||
defaultValue?: string;
|
||||
placeholder: string;
|
||||
@@ -18,6 +20,7 @@ export const SearchInput = ({ placeholder, ariaLabel, defaultValue, flexExpand =
|
||||
const router = useRouter();
|
||||
const pathName = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
const t = useI18n("common.action");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [value, setValue] = useState(defaultValue ?? "");
|
||||
useEffect(() => {
|
||||
@@ -47,11 +50,26 @@ export const SearchInput = ({ placeholder, ariaLabel, defaultValue, flexExpand =
|
||||
[setLoading, handleSearchDebounced],
|
||||
);
|
||||
|
||||
const clearSearch = useCallback(() => {
|
||||
setValue("");
|
||||
setLoading(true);
|
||||
handleSearchDebounced("");
|
||||
handleSearchDebounced.flush();
|
||||
}, [handleSearchDebounced]);
|
||||
|
||||
return (
|
||||
<TextInput
|
||||
leftSection={<LeftSection loading={loading} />}
|
||||
rightSection={value ? <Input.ClearButton aria-label={t("clearSearch")} onClick={clearSearch} /> : undefined}
|
||||
rightSectionPointerEvents="all"
|
||||
value={value}
|
||||
onChange={handleSearch}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key !== "Escape" || !value) return;
|
||||
|
||||
event.preventDefault();
|
||||
clearSearch();
|
||||
}}
|
||||
placeholder={placeholder}
|
||||
aria-label={ariaLabel}
|
||||
style={{ flex: flexExpand ? "1" : undefined }}
|
||||
|
||||
@@ -18,7 +18,7 @@ export const TablePagination = ({ total }: TablePaginationProps) => {
|
||||
const pathName = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
const t = useI18n("common.pagination");
|
||||
const current = Number(searchParams.get("page")) || 1;
|
||||
const current = parsePage(searchParams.getAll("page"));
|
||||
|
||||
const getItemProps = useCallback(
|
||||
(page: number) => {
|
||||
@@ -62,6 +62,18 @@ export const TablePagination = ({ total }: TablePaginationProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
const parsePage = (pageValues: string[]) => {
|
||||
if (pageValues.length !== 1) return 1;
|
||||
|
||||
const [pageValue] = pageValues;
|
||||
if (!pageValue || !/^[1-9]\d*$/u.test(pageValue)) return 1;
|
||||
|
||||
const page = Number(pageValue);
|
||||
if (!Number.isSafeInteger(page)) return 1;
|
||||
|
||||
return page;
|
||||
};
|
||||
|
||||
type ControlType = Parameters<Exclude<PaginationProps["getControlProps"], undefined>>[0];
|
||||
const calculatePageFor = (type: ControlType, current: number, total: number) => {
|
||||
switch (type) {
|
||||
|
||||
Reference in new issue
Block a user