Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 10 additions & 16 deletions frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ import {
setUserTablePreference
} from "@app/helpers/userTablePreferences";
import {
useDebounce,
useLocalStorageState,
usePagination,
usePopUp,
Expand Down Expand Up @@ -287,7 +286,6 @@ const OverviewPageContent = () => {
const isProjectV3 = currentProject?.version === ProjectVersion.V3;
const projectSlug = currentProject?.slug as string;
const [searchFilter, setSearchFilter] = useState("");
const [debouncedSearchFilter, setDebouncedSearchFilter] = useDebounce(searchFilter);
const secretPath = (routerSearch?.secretPath as string) || "/";
const { subscription } = useSubscription();
const { hasOrgRole } = useOrgPermission();
Expand Down Expand Up @@ -555,7 +553,7 @@ const OverviewPageContent = () => {
includeSecrets: activeTagSlugs.length > 0 || (isFilteredByResources ? filter.secret : true),
includeImports: isFilteredByResources ? (filter[RowType.SecretImport] ?? true) : true,
includeSecretRotations: isFilteredByResources ? filter.rotation : true,
search: debouncedSearchFilter,
search: searchFilter,
tags: tagFilter,
limit,
offset
Expand Down Expand Up @@ -795,7 +793,6 @@ const OverviewPageContent = () => {

if (search) {
setSearchFilter(search as string);
setDebouncedSearchFilter(search as string);
}
}
}, [routerSearch.search, routerSearch.filterBy]);
Expand Down Expand Up @@ -1753,7 +1750,7 @@ const OverviewPageContent = () => {
if (isFilteredByResources && !filter.secret && !activeTagSlugs.length) return secKeys;

const result = [...secKeys];
const searchLower = debouncedSearchFilter.toLowerCase();
const searchLower = searchFilter.toLowerCase();
pendingChanges.secrets.forEach((change) => {
if (change.type === PendingAction.Create && !result.includes(change.secretKey)) {
if (!searchLower || change.secretKey.toLowerCase().includes(searchLower)) {
Expand All @@ -1766,7 +1763,7 @@ const OverviewPageContent = () => {
secKeys,
isBatchModeActive,
pendingChanges.secrets,
debouncedSearchFilter,
searchFilter,
isFilteredByResources,
filter.secret
]);
Expand Down Expand Up @@ -1862,7 +1859,7 @@ const OverviewPageContent = () => {
// If resource filter is active and folders are excluded, skip pending folder creates
const includePendingFolderCreates = !isFilteredByResources || filter.folder;

const searchLower = debouncedSearchFilter.toLowerCase();
const searchLower = searchFilter.toLowerCase();
pendingChanges.folders.forEach((change) => {
if (change.type === PendingAction.Create) {
if (
Expand Down Expand Up @@ -1902,7 +1899,7 @@ const OverviewPageContent = () => {
folderNamesAndDescriptions,
isBatchModeActive,
pendingChanges.folders,
debouncedSearchFilter,
searchFilter,
isFilteredByResources,
filter.folder
]);
Expand Down Expand Up @@ -2032,7 +2029,6 @@ const OverviewPageContent = () => {
setFilter(restore?.filter ?? DEFAULT_FILTER_STATE);
const el = restore?.searchFilter ?? "";
setSearchFilter(el);
setDebouncedSearchFilter(el);
};

const handleFolderClick = (path: string) => {
Expand All @@ -2053,7 +2049,6 @@ const OverviewPageContent = () => {
}).then(() => {
setFilter(DEFAULT_FILTER_STATE);
setSearchFilter("");
setDebouncedSearchFilter("");
});
};

Expand Down Expand Up @@ -2321,7 +2316,7 @@ const OverviewPageContent = () => {
ProjectPermissionSecretActions.Create,
ProjectPermissionSub.Secrets
);
if (isTableFiltered || debouncedSearchFilter || cannotCreate) return "filter-empty" as const;
if (isTableFiltered || searchFilter || cannotCreate) return "filter-empty" as const;
return "add-first-secret" as const;
}
return "table" as const;
Expand Down Expand Up @@ -2437,6 +2432,7 @@ const OverviewPageContent = () => {
/>
)}
<ResourceSearchInput
key={secretPath}
value={searchFilter}
tags={tags}
onChange={setSearchFilter}
Expand Down Expand Up @@ -2543,9 +2539,7 @@ const OverviewPageContent = () => {
) : null)}
{tableView === "tag-filter-empty" && <EmptyResourceDisplay isFiltered />}
{tableView === "filter-empty" && (
<EmptyResourceDisplay
isFiltered={isTableFiltered || Boolean(debouncedSearchFilter)}
/>
<EmptyResourceDisplay isFiltered={isTableFiltered || Boolean(searchFilter)} />
)}
{tableView === "add-first-secret" && (
<div className="relative">
Expand Down Expand Up @@ -2905,7 +2899,7 @@ const OverviewPageContent = () => {
getSecretImportByEnv={getSecretImportByEnv}
tableWidth={tableWidth}
secretPath={secretPath}
searchFilter={debouncedSearchFilter}
searchFilter={searchFilter}
onDelete={(secretImport) =>
handlePopUpOpen("deleteSecretImport", secretImport)
}
Expand All @@ -2926,7 +2920,7 @@ const OverviewPageContent = () => {
getSecretImportByEnv={getSecretImportByEnv}
tableWidth={tableWidth}
secretPath={secretPath}
searchFilter={debouncedSearchFilter}
searchFilter={searchFilter}
onDelete={(secretImport) =>
handlePopUpOpen("deleteSecretImport", secretImport)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useRef, useState } from "react";
import { useEffect, useRef, useState } from "react";
import { GlobeIcon, SearchIcon, XIcon } from "lucide-react";

import {
Expand All @@ -14,6 +14,7 @@ import {
TooltipContent,
TooltipTrigger
} from "@app/components/v3";
import { useDebounce } from "@app/hooks";

import { QuickSearchModal, QuickSearchModalProps } from "../SecretSearchInput/components";

Expand All @@ -24,7 +25,7 @@ type Props = Omit<QuickSearchModalProps, "isOpen" | "onClose" | "onOpenChange" |
};

export const ResourceSearchInput = ({
value,
value: externalValue,
onChange,
className,
isSingleEnv,
Expand All @@ -35,7 +36,33 @@ export const ResourceSearchInput = ({
const [isOptionHighlighted, setIsOptionHighlighted] = useState(false);
const deepSearchBtnRef = useRef<HTMLButtonElement>(null);
const inputRef = useRef<HTMLInputElement>(null);
const hasSearch = Boolean(value.trim());

// local input state so typing doesn't re-render the whole table
const [inputValue, setInputValue] = useState(externalValue);
const [debouncedInputValue] = useDebounce(inputValue);
const lastEmittedValue = useRef(externalValue);

useEffect(() => {
if (externalValue !== lastEmittedValue.current) {
setInputValue(externalValue);
lastEmittedValue.current = externalValue;
Comment thread
varonix0 marked this conversation as resolved.
}
}, [externalValue]);

useEffect(() => {
if (debouncedInputValue !== lastEmittedValue.current) {
lastEmittedValue.current = debouncedInputValue;
onChange(debouncedInputValue);
}
}, [debouncedInputValue, onChange]);
Comment thread
varonix0 marked this conversation as resolved.

const handleClear = () => {
setInputValue("");
lastEmittedValue.current = "";
onChange("");
};

const hasSearch = Boolean(inputValue.trim());

return (
<>
Expand All @@ -60,9 +87,9 @@ export const ResourceSearchInput = ({
? "Search by secret, folder, tag or metadata..."
: "Search by secret or folder name..."
}
value={value}
value={inputValue}
onChange={(e) => {
onChange(e.target.value);
setInputValue(e.target.value);
setIsOptionHighlighted(false);
}}
onFocus={() => setIsFocused(true)}
Expand Down Expand Up @@ -90,7 +117,7 @@ export const ResourceSearchInput = ({
/>
{hasSearch && (
<InputGroupAddon align="inline-end">
<IconButton variant="ghost" size="xs" onClick={() => onChange("")}>
<IconButton variant="ghost" size="xs" onClick={handleClear}>
<XIcon />
</IconButton>
</InputGroupAddon>
Expand All @@ -115,7 +142,9 @@ export const ResourceSearchInput = ({
}}
>
<GlobeIcon className="size-4 shrink-0 text-muted" />
<span className="truncate">Search all folders for &quot;{value.trim()}&quot;</span>
<span className="truncate">
Search all folders for &quot;{inputValue.trim()}&quot;
</span>
</button>
</PopoverContent>
</Popover>
Expand All @@ -124,10 +153,10 @@ export const ResourceSearchInput = ({
isSingleEnv={isSingleEnv}
isOpen={isOpen}
onOpenChange={setIsOpen}
initialValue={value}
initialValue={inputValue}
onClose={() => {
setIsOpen(false);
onChange("");
handleClear();
}}
{...props}
/>
Expand Down
Loading