mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feature: clear filters when navigating down and restore filters when navigating up folders in secrets dashboard
This commit is contained in:
@@ -77,7 +77,7 @@ export const InfisicalSecretInput = forwardRef<HTMLTextAreaElement, Props>(
|
|||||||
const { currentWorkspace } = useWorkspace();
|
const { currentWorkspace } = useWorkspace();
|
||||||
const workspaceId = currentWorkspace?.id || "";
|
const workspaceId = currentWorkspace?.id || "";
|
||||||
|
|
||||||
const debouncedValue = useDebounce(value, 500);
|
const [debouncedValue] = useDebounce(value, 500);
|
||||||
|
|
||||||
const [highlightedIndex, setHighlightedIndex] = useState(-1);
|
const [highlightedIndex, setHighlightedIndex] = useState(-1);
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export const SecretPathInput = ({
|
|||||||
const [suggestions, setSuggestions] = useState<string[]>([]);
|
const [suggestions, setSuggestions] = useState<string[]>([]);
|
||||||
const [isInputFocused, setIsInputFocus] = useState(false);
|
const [isInputFocused, setIsInputFocus] = useState(false);
|
||||||
const [highlightedIndex, setHighlightedIndex] = useState(-1);
|
const [highlightedIndex, setHighlightedIndex] = useState(-1);
|
||||||
const debouncedInputValue = useDebounce(inputValue, 200);
|
const [debouncedInputValue] = useDebounce(inputValue, 200);
|
||||||
|
|
||||||
const { currentWorkspace } = useWorkspace();
|
const { currentWorkspace } = useWorkspace();
|
||||||
const workspaceId = currentWorkspace?.id || "";
|
const workspaceId = currentWorkspace?.id || "";
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { Dispatch, SetStateAction, useEffect, useState } from "react";
|
||||||
|
|
||||||
// Ref: https://usehooks.com/useDebounce/
|
// Ref: https://usehooks.com/useDebounce/
|
||||||
export const useDebounce = <T extends unknown>(value: T, delay = 500): T => {
|
export const useDebounce = <T extends unknown>(
|
||||||
|
value: T,
|
||||||
|
delay = 500
|
||||||
|
): [T, Dispatch<SetStateAction<T>>] => {
|
||||||
// State and setters for debounced value
|
// State and setters for debounced value
|
||||||
const [debouncedValue, setDebouncedValue] = useState(value);
|
const [debouncedValue, setDebouncedValue] = useState(value);
|
||||||
|
|
||||||
@@ -22,5 +25,5 @@ export const useDebounce = <T extends unknown>(value: T, delay = 500): T => {
|
|||||||
[value, delay] // Only re-call effect if value or delay changes
|
[value, delay] // Only re-call effect if value or delay changes
|
||||||
);
|
);
|
||||||
|
|
||||||
return debouncedValue;
|
return [debouncedValue, setDebouncedValue];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
|
|||||||
const [orderDirection, setOrderDirection] = useState(OrderByDirection.ASC);
|
const [orderDirection, setOrderDirection] = useState(OrderByDirection.ASC);
|
||||||
const [orderBy, setOrderBy] = useState(OrgIdentityOrderBy.Name);
|
const [orderBy, setOrderBy] = useState(OrgIdentityOrderBy.Name);
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const debouncedSearch = useDebounce(search);
|
const [debouncedSearch] = useDebounce(search);
|
||||||
|
|
||||||
const organizationId = currentOrg?.id || "";
|
const organizationId = currentOrg?.id || "";
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export const OrgAdminProjects = withPermission(
|
|||||||
() => {
|
() => {
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const debouncedSearch = useDebounce(search);
|
const [debouncedSearch] = useDebounce(search);
|
||||||
const [perPage, setPerPage] = useState(25);
|
const [perPage, setPerPage] = useState(25);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const orgAdminAccessProject = useOrgAdminAccessProject();
|
const orgAdminAccessProject = useOrgAdminAccessProject();
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export const IdentityTab = withProjectPermission(
|
|||||||
const [orderDirection, setOrderDirection] = useState(OrderByDirection.ASC);
|
const [orderDirection, setOrderDirection] = useState(OrderByDirection.ASC);
|
||||||
const [orderBy, setOrderBy] = useState(ProjectIdentityOrderBy.Name);
|
const [orderBy, setOrderBy] = useState(ProjectIdentityOrderBy.Name);
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const debouncedSearch = useDebounce(search);
|
const [debouncedSearch] = useDebounce(search);
|
||||||
|
|
||||||
const workspaceId = currentWorkspace?.id ?? "";
|
const workspaceId = currentWorkspace?.id ?? "";
|
||||||
|
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ export const SecretMainPage = () => {
|
|||||||
ProjectPermissionSub.SecretRollback
|
ProjectPermissionSub.SecretRollback
|
||||||
);
|
);
|
||||||
|
|
||||||
const [filter, setFilter] = useState<Filter>({
|
const defaultFilterState = {
|
||||||
tags: {},
|
tags: {},
|
||||||
searchFilter: (router.query.searchFilter as string) || "",
|
searchFilter: (router.query.searchFilter as string) || "",
|
||||||
include: {
|
include: {
|
||||||
@@ -88,8 +88,11 @@ export const SecretMainPage = () => {
|
|||||||
[RowType.DynamicSecret]: canReadSecret,
|
[RowType.DynamicSecret]: canReadSecret,
|
||||||
[RowType.Secret]: canReadSecret
|
[RowType.Secret]: canReadSecret
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
const debouncedSearchFilter = useDebounce(filter.searchFilter);
|
|
||||||
|
const [filter, setFilter] = useState<Filter>(defaultFilterState);
|
||||||
|
const [debouncedSearchFilter, setDebouncedSearchFilter] = useDebounce(filter.searchFilter);
|
||||||
|
const [filterHistory, setFilterHistory] = useState<Map<string, Filter>>(new Map());
|
||||||
|
|
||||||
// change filters if permissions change at different paths/env
|
// change filters if permissions change at different paths/env
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -255,10 +258,39 @@ export const SecretMainPage = () => {
|
|||||||
if (totalCount < paginationOffset) setPage(1);
|
if (totalCount < paginationOffset) setPage(1);
|
||||||
}, [totalCount]);
|
}, [totalCount]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// restore filters for path if set
|
||||||
|
const restore = filterHistory.get(secretPath);
|
||||||
|
setFilter(restore ?? defaultFilterState);
|
||||||
|
setDebouncedSearchFilter(restore?.searchFilter ?? "");
|
||||||
|
const { searchFilter, ...query } = router.query;
|
||||||
|
|
||||||
|
// this is a temp work around until we fully transition state to query params,
|
||||||
|
// setting the initial search filter by query and then moving it to internal state
|
||||||
|
if (router.query.searchFilter) {
|
||||||
|
router.push({
|
||||||
|
pathname: router.pathname,
|
||||||
|
query
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [secretPath]);
|
||||||
|
|
||||||
if (isDetailsLoading) {
|
if (isDetailsLoading) {
|
||||||
return <ContentLoader text={LOADER_TEXT} />;
|
return <ContentLoader text={LOADER_TEXT} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleResetFilter = () => {
|
||||||
|
// store for breadcrumb nav to restore previously used filters
|
||||||
|
setFilterHistory((prev) => {
|
||||||
|
const curr = new Map(prev);
|
||||||
|
curr.set(secretPath, filter);
|
||||||
|
return curr;
|
||||||
|
});
|
||||||
|
|
||||||
|
setFilter(defaultFilterState);
|
||||||
|
setDebouncedSearchFilter("");
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StoreProvider>
|
<StoreProvider>
|
||||||
<div className="container mx-auto flex flex-col px-6 text-mineshaft-50 dark:[color-scheme:dark]">
|
<div className="container mx-auto flex flex-col px-6 text-mineshaft-50 dark:[color-scheme:dark]">
|
||||||
@@ -339,6 +371,7 @@ export const SecretMainPage = () => {
|
|||||||
environment={environment}
|
environment={environment}
|
||||||
workspaceId={workspaceId}
|
workspaceId={workspaceId}
|
||||||
secretPath={secretPath}
|
secretPath={secretPath}
|
||||||
|
onNavigateToFolder={handleResetFilter}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{canReadSecret && dynamicSecrets?.length && (
|
{canReadSecret && dynamicSecrets?.length && (
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { useState } from "react";
|
|
||||||
import { TypeOptions } from "react-toastify";
|
import { TypeOptions } from "react-toastify";
|
||||||
import { subject } from "@casl/ability";
|
import { subject } from "@casl/ability";
|
||||||
import {
|
import {
|
||||||
@@ -56,7 +55,6 @@ import { usePopUp } from "@app/hooks";
|
|||||||
import { useCreateFolder, useDeleteSecretBatch, useMoveSecrets } from "@app/hooks/api";
|
import { useCreateFolder, useDeleteSecretBatch, useMoveSecrets } from "@app/hooks/api";
|
||||||
import { fetchProjectSecrets } from "@app/hooks/api/secrets/queries";
|
import { fetchProjectSecrets } from "@app/hooks/api/secrets/queries";
|
||||||
import { SecretType, SecretV3RawSanitized, WsTag } from "@app/hooks/api/types";
|
import { SecretType, SecretV3RawSanitized, WsTag } from "@app/hooks/api/types";
|
||||||
import { debounce } from "@app/lib/fn/debounce";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
PopUpNames,
|
PopUpNames,
|
||||||
@@ -118,7 +116,6 @@ export const ActionBar = ({
|
|||||||
] as const);
|
] as const);
|
||||||
const { subscription } = useSubscription();
|
const { subscription } = useSubscription();
|
||||||
const { openPopUp } = usePopUpAction();
|
const { openPopUp } = usePopUpAction();
|
||||||
const [search, setSearch] = useState(filter.searchFilter);
|
|
||||||
|
|
||||||
const { mutateAsync: createFolder } = useCreateFolder();
|
const { mutateAsync: createFolder } = useCreateFolder();
|
||||||
const { mutateAsync: deleteBatchSecretV3 } = useDeleteSecretBatch();
|
const { mutateAsync: deleteBatchSecretV3 } = useDeleteSecretBatch();
|
||||||
@@ -134,8 +131,6 @@ export const ActionBar = ({
|
|||||||
(rule.subject as ProjectPermissionSub[]).includes(ProjectPermissionSub.SecretFolders)
|
(rule.subject as ProjectPermissionSub[]).includes(ProjectPermissionSub.SecretFolders)
|
||||||
);
|
);
|
||||||
|
|
||||||
const debouncedOnSearch = debounce(onSearchChange, 500);
|
|
||||||
|
|
||||||
const handleFolderCreate = async (folderName: string) => {
|
const handleFolderCreate = async (folderName: string) => {
|
||||||
try {
|
try {
|
||||||
await createFolder({
|
await createFolder({
|
||||||
@@ -286,11 +281,15 @@ export const ActionBar = ({
|
|||||||
<Input
|
<Input
|
||||||
className="bg-mineshaft-800 placeholder-mineshaft-50 duration-200 focus:bg-mineshaft-700/80"
|
className="bg-mineshaft-800 placeholder-mineshaft-50 duration-200 focus:bg-mineshaft-700/80"
|
||||||
placeholder="Search by folder name, key name, comment..."
|
placeholder="Search by folder name, key name, comment..."
|
||||||
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
|
leftIcon={
|
||||||
value={search}
|
<FontAwesomeIcon
|
||||||
|
className={filter.searchFilter ? "text-primary" : ""}
|
||||||
|
icon={faMagnifyingGlass}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
value={filter.searchFilter}
|
||||||
onChange={(evt) => {
|
onChange={(evt) => {
|
||||||
setSearch(evt.target.value);
|
onSearchChange(evt.target.value);
|
||||||
debouncedOnSearch(evt.target.value);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -18,13 +18,15 @@ type Props = {
|
|||||||
environment: string;
|
environment: string;
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
secretPath?: string;
|
secretPath?: string;
|
||||||
|
onNavigateToFolder: (path: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FolderListView = ({
|
export const FolderListView = ({
|
||||||
folders = [],
|
folders = [],
|
||||||
environment,
|
environment,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
secretPath = "/"
|
secretPath = "/",
|
||||||
|
onNavigateToFolder
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const { popUp, handlePopUpToggle, handlePopUpOpen, handlePopUpClose } = usePopUp([
|
const { popUp, handlePopUpToggle, handlePopUpOpen, handlePopUpClose } = usePopUp([
|
||||||
"updateFolder",
|
"updateFolder",
|
||||||
@@ -88,13 +90,16 @@ export const FolderListView = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleFolderClick = (name: string) => {
|
const handleFolderClick = (name: string) => {
|
||||||
router.push({
|
const path = `${router.query?.secretPath || ""}/${name}`;
|
||||||
pathname: router.pathname,
|
router
|
||||||
query: {
|
.push({
|
||||||
...router.query,
|
pathname: router.pathname,
|
||||||
secretPath: `${router.query?.secretPath || ""}/${name}`
|
query: {
|
||||||
}
|
...router.query,
|
||||||
});
|
secretPath: path
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(() => onNavigateToFolder(path));
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ export const CopySecretsFromBoard = ({
|
|||||||
|
|
||||||
const envCopySecPath = watch("secretPath");
|
const envCopySecPath = watch("secretPath");
|
||||||
const selectedEnvSlug = watch("environment");
|
const selectedEnvSlug = watch("environment");
|
||||||
const debouncedEnvCopySecretPath = useDebounce(envCopySecPath);
|
const [debouncedEnvCopySecretPath] = useDebounce(envCopySecPath);
|
||||||
|
|
||||||
const { data: secrets, isLoading: isSecretsLoading } = useGetProjectSecrets({
|
const { data: secrets, isLoading: isSecretsLoading } = useGetProjectSecrets({
|
||||||
workspaceId,
|
workspaceId,
|
||||||
|
|||||||
@@ -97,11 +97,16 @@ type Filter = {
|
|||||||
};
|
};
|
||||||
const INIT_PER_PAGE = 20;
|
const INIT_PER_PAGE = 20;
|
||||||
|
|
||||||
|
const DEFAULT_FILTER_STATE = {
|
||||||
|
[RowType.Folder]: true,
|
||||||
|
[RowType.DynamicSecret]: true,
|
||||||
|
[RowType.Secret]: true
|
||||||
|
};
|
||||||
|
|
||||||
export const SecretOverviewPage = () => {
|
export const SecretOverviewPage = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
// this is to set expandable table width
|
// this is to set expandable table width
|
||||||
// coz when overflow the table goes to the right
|
// coz when overflow the table goes to the right
|
||||||
const parentTableRef = useRef<HTMLTableElement>(null);
|
const parentTableRef = useRef<HTMLTableElement>(null);
|
||||||
@@ -121,14 +126,13 @@ export const SecretOverviewPage = () => {
|
|||||||
const workspaceId = currentWorkspace?.id as string;
|
const workspaceId = currentWorkspace?.id as string;
|
||||||
const projectSlug = currentWorkspace?.slug as string;
|
const projectSlug = currentWorkspace?.slug as string;
|
||||||
const [searchFilter, setSearchFilter] = useState("");
|
const [searchFilter, setSearchFilter] = useState("");
|
||||||
const debouncedSearchFilter = useDebounce(searchFilter);
|
const [debouncedSearchFilter, setDebouncedSearchFilter] = useDebounce(searchFilter);
|
||||||
const secretPath = (router.query?.secretPath as string) || "/";
|
const secretPath = (router.query?.secretPath as string) || "/";
|
||||||
|
|
||||||
const [filter, setFilter] = useState<Filter>({
|
const [filter, setFilter] = useState<Filter>(DEFAULT_FILTER_STATE);
|
||||||
[RowType.Folder]: true,
|
const [filterHistory, setFilterHistory] = useState<
|
||||||
[RowType.DynamicSecret]: true,
|
Map<string, { filter: Filter; searchFilter: string }>
|
||||||
[RowType.Secret]: true
|
>(new Map());
|
||||||
});
|
|
||||||
|
|
||||||
const [selectedEntries, setSelectedEntries] = useState<{
|
const [selectedEntries, setSelectedEntries] = useState<{
|
||||||
[EntryType.FOLDER]: Record<string, boolean>;
|
[EntryType.FOLDER]: Record<string, boolean>;
|
||||||
@@ -195,7 +199,7 @@ export const SecretOverviewPage = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setVisibleEnvs(userAvailableEnvs);
|
setVisibleEnvs(userAvailableEnvs);
|
||||||
}, [userAvailableEnvs, secretPath]);
|
}, [userAvailableEnvs]);
|
||||||
|
|
||||||
const { isImportedSecretPresentInEnv, getImportedSecretByKey, getEnvImportedSecretKeyCount } =
|
const { isImportedSecretPresentInEnv, getImportedSecretByKey, getEnvImportedSecretKeyCount } =
|
||||||
useGetImportedSecretsAllEnvs({
|
useGetImportedSecretsAllEnvs({
|
||||||
@@ -456,16 +460,35 @@ export const SecretOverviewPage = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleResetSearch = () => setSearchFilter("");
|
const handleResetSearch = (path: string) => {
|
||||||
|
const restore = filterHistory.get(path);
|
||||||
|
setFilter(restore?.filter ?? DEFAULT_FILTER_STATE);
|
||||||
|
const search = restore?.searchFilter ?? "";
|
||||||
|
setSearchFilter(search);
|
||||||
|
setDebouncedSearchFilter(search);
|
||||||
|
};
|
||||||
|
|
||||||
const handleFolderClick = (path: string) => {
|
const handleFolderClick = (path: string) => {
|
||||||
router.push({
|
// store for breadcrumb nav to restore previously used filters
|
||||||
pathname: router.pathname,
|
setFilterHistory((prev) => {
|
||||||
query: {
|
const curr = new Map(prev);
|
||||||
...router.query,
|
curr.set(secretPath, { filter, searchFilter });
|
||||||
secretPath: `${router.query?.secretPath || ""}/${path}`
|
return curr;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router
|
||||||
|
.push({
|
||||||
|
pathname: router.pathname,
|
||||||
|
query: {
|
||||||
|
...router.query,
|
||||||
|
secretPath: `${router.query?.secretPath || ""}/${path}`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
setFilter(DEFAULT_FILTER_STATE);
|
||||||
|
setSearchFilter("");
|
||||||
|
setDebouncedSearchFilter("");
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleExploreEnvClick = async (slug: string) => {
|
const handleExploreEnvClick = async (slug: string) => {
|
||||||
@@ -544,7 +567,9 @@ export const SecretOverviewPage = () => {
|
|||||||
|
|
||||||
const isTableEmpty = totalCount === 0;
|
const isTableEmpty = totalCount === 0;
|
||||||
|
|
||||||
const isTableFiltered = Boolean(Object.values(filter).filter((enabled) => !enabled).length);
|
const isTableFiltered =
|
||||||
|
Boolean(Object.values(filter).filter((enabled) => !enabled).length) ||
|
||||||
|
userAvailableEnvs.length !== visibleEnvs.length;
|
||||||
|
|
||||||
if (!isProjectV3)
|
if (!isProjectV3)
|
||||||
return (
|
return (
|
||||||
@@ -706,7 +731,12 @@ export const SecretOverviewPage = () => {
|
|||||||
placeholder="Search by secret/folder name..."
|
placeholder="Search by secret/folder name..."
|
||||||
value={searchFilter}
|
value={searchFilter}
|
||||||
onChange={(e) => setSearchFilter(e.target.value)}
|
onChange={(e) => setSearchFilter(e.target.value)}
|
||||||
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
|
leftIcon={
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={faMagnifyingGlass}
|
||||||
|
className={searchFilter ? "text-primary" : ""}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{userAvailableEnvs.length > 0 && (
|
{userAvailableEnvs.length > 0 && (
|
||||||
|
|||||||
@@ -4,16 +4,16 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
secretPath: string;
|
secretPath: string;
|
||||||
onResetSearch: () => void;
|
onResetSearch: (path: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FolderBreadCrumbs = ({ secretPath = "/", onResetSearch }: Props) => {
|
export const FolderBreadCrumbs = ({ secretPath = "/", onResetSearch }: Props) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const onFolderCrumbClick = (index: number) => {
|
const onFolderCrumbClick = (index: number) => {
|
||||||
const newSecPath = secretPath.split("/").filter(Boolean).slice(0, index).join("/");
|
const newSecPath = `/${secretPath.split("/").filter(Boolean).slice(0, index).join("/")}`;
|
||||||
if (secretPath === `/${newSecPath}`) return;
|
if (secretPath === newSecPath) return;
|
||||||
const query = { ...router.query, secretPath: `/${newSecPath}` } as Record<string, string>;
|
const query = { ...router.query, secretPath: newSecPath } as Record<string, string>;
|
||||||
// root condition
|
// root condition
|
||||||
if (index === 0) delete query.secretPath;
|
if (index === 0) delete query.secretPath;
|
||||||
router
|
router
|
||||||
@@ -21,7 +21,7 @@ export const FolderBreadCrumbs = ({ secretPath = "/", onResetSearch }: Props) =>
|
|||||||
pathname: router.pathname,
|
pathname: router.pathname,
|
||||||
query
|
query
|
||||||
})
|
})
|
||||||
.then(() => onResetSearch());
|
.then(() => onResetSearch(newSecPath));
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ const UserPanelTable = ({
|
|||||||
const [searchUserFilter, setSearchUserFilter] = useState("");
|
const [searchUserFilter, setSearchUserFilter] = useState("");
|
||||||
const { user } = useUser();
|
const { user } = useUser();
|
||||||
const userId = user?.id || "";
|
const userId = user?.id || "";
|
||||||
const debounedSearchTerm = useDebounce(searchUserFilter, 500);
|
const [debounedSearchTerm] = useDebounce(searchUserFilter, 500);
|
||||||
const { subscription } = useSubscription();
|
const { subscription } = useSubscription();
|
||||||
|
|
||||||
const { data, isLoading, isFetchingNextPage, hasNextPage, fetchNextPage } = useAdminGetUsers({
|
const { data, isLoading, isFetchingNextPage, hasNextPage, fetchNextPage } = useAdminGetUsers({
|
||||||
|
|||||||
Reference in New Issue
Block a user