diff --git a/frontend/src/components/v2/InfisicalSecretInput/InfisicalSecretInput.tsx b/frontend/src/components/v2/InfisicalSecretInput/InfisicalSecretInput.tsx index 07d07dd4d..98f42923a 100644 --- a/frontend/src/components/v2/InfisicalSecretInput/InfisicalSecretInput.tsx +++ b/frontend/src/components/v2/InfisicalSecretInput/InfisicalSecretInput.tsx @@ -2,6 +2,7 @@ import { forwardRef, TextareaHTMLAttributes, useCallback, useMemo, useRef, useSt import { faFolder, faKey, faLayerGroup, faSearch } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import * as Popover from "@radix-ui/react-popover"; +import { useNavigate } from "@tanstack/react-router"; import { ROUTE_PATHS } from "@app/const/routes"; import { useProject } from "@app/context"; @@ -81,6 +82,7 @@ export const InfisicalSecretInput = forwardRef( ) => { const { currentProject } = useProject(); const projectId = currentProject?.id || ""; + const navigate = useNavigate({ from: ROUTE_PATHS.SecretManager.SecretDashboardPage.path }); const [debouncedValue] = useDebounce(value, 100); @@ -310,37 +312,49 @@ export const InfisicalSecretInput = forwardRef( const handleClickSegment = useCallback( (segment: string, allSegments: string[]) => { - // Single segment: search in current environment and path if (allSegments.length === 1) { - const currentEnv = propEnvironment || ""; - const currentPath = propSecretPath || "/"; - const encodedPath = encodeURIComponent(currentPath); - const url = ROUTE_PATHS.SecretManager.SecretDashboardPage.path - .replace("$projectId", projectId) - .replace("$envSlug", currentEnv); - window.open( - `${url}?secretPath=${encodedPath}&search=${encodeURIComponent(segment)}&filterBy=secret`, - "_blank", - "noopener,noreferrer" - ); + navigate({ + search: (prev) => ({ + ...prev, + search: segment, + filterBy: "secret" + }) + }); return; } - // Multiple segments: first is env, last is secret, middle are folders const environmentSlug = allSegments[0]; const secretName = allSegments[allSegments.length - 1]; - const folderPath = allSegments.length > 2 ? `/${allSegments.slice(1, -1).join("/")}` : "/"; - const encodedPath = encodeURIComponent(folderPath); - const url = ROUTE_PATHS.SecretManager.SecretDashboardPage.path - .replace("$projectId", projectId) - .replace("$envSlug", environmentSlug); - window.open( - `${url}?secretPath=${encodedPath}&search=${encodeURIComponent(secretName)}&filterBy=secret`, - "_blank", - "noopener,noreferrer" - ); + let folderPath = "/"; + + if (allSegments.length > 2) { + const pathSegments = allSegments.slice(1, -1); + for (let i = 0; i < pathSegments.length; i += 1) { + const pathSegment = pathSegments[i]; + folderPath += `${pathSegment}`; + if (pathSegment === segment) { + folderPath += "/"; + break; + } + folderPath += "/"; + } + } + + navigate({ + to: ROUTE_PATHS.SecretManager.SecretDashboardPage.path, + params: { + projectId, + envSlug: environmentSlug + }, + search: (prev) => ({ + ...prev, + secretPath: segment === environmentSlug ? "/" : folderPath, + search: segment === secretName ? secretName : prev.search, + filterBy: segment === secretName ? "secret" : prev.filterBy + }) + }); }, - [projectId, propEnvironment, propSecretPath] + [navigate, projectId] ); return ( diff --git a/frontend/src/components/v2/SecretInput/SecretInput.tsx b/frontend/src/components/v2/SecretInput/SecretInput.tsx index ac5a4ff7c..758d1a225 100644 --- a/frontend/src/components/v2/SecretInput/SecretInput.tsx +++ b/frontend/src/components/v2/SecretInput/SecretInput.tsx @@ -53,10 +53,16 @@ const syntaxHighlight = ( } ${shouldShowHoverStyle ? "cursor-pointer underline decoration-yellow-400" : ""}`} onMouseEnter={() => onHoverPart?.(segmentKey)} onMouseLeave={() => onHoverPart?.("")} - onClick={(e) => { + onMouseDown={(e) => { if (isCmdOrCtrlPressed) { e.preventDefault(); e.stopPropagation(); + } + }} + onClick={(e) => { + e.stopPropagation(); + if (isCmdOrCtrlPressed) { + e.preventDefault(); onClickSegment?.(segment, parts); } }} diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/SecretDashboardPage.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/SecretDashboardPage.tsx index 74ad462e4..1bc06de4d 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/SecretDashboardPage.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/SecretDashboardPage.tsx @@ -475,34 +475,73 @@ const Page = () => { ); const handleTagToggle = useCallback( - (tagSlug: string) => + (tagSlug: string) => { setFilter((state) => { const isTagPresent = Boolean(state.tags?.[tagSlug]); const newTagFilter = { ...state.tags }; if (isTagPresent) delete newTagFilter[tagSlug]; else newTagFilter[tagSlug] = true; + + // Update URL to match filter state + const tagsList = Object.keys(newTagFilter).filter((tag) => newTagFilter[tag]); + navigate({ + search: (prev) => ({ + ...prev, + tags: tagsList.length > 0 ? tagsList.join(",") : "" + }) + }); + return { ...state, tags: newTagFilter }; - }), - [] + }); + }, + [navigate] ); const handleToggleRowType = useCallback( - (rowType: RowType) => + (rowType: RowType) => { setFilter((state) => { + const newInclude = { + ...state.include, + [rowType]: !state.include[rowType] + }; + + // Update URL to match filter state + const filterByList: string[] = []; + if (newInclude[RowType.Folder]) filterByList.push("folder"); + if (newInclude[RowType.Import]) filterByList.push("import"); + if (newInclude[RowType.DynamicSecret]) filterByList.push("dynamic"); + if (newInclude[RowType.Secret]) filterByList.push("secret"); + if (newInclude[RowType.SecretRotation]) filterByList.push("rotation"); + + navigate({ + search: (prev) => ({ + ...prev, + filterBy: filterByList.length > 0 ? filterByList.join(",") : "" + }) + }); + return { ...state, - include: { - ...state.include, - [rowType]: !state.include[rowType] - } + include: newInclude }; - }), - [] + }); + }, + [navigate] ); const handleSearchChange = useCallback( - (searchFilter: string) => setFilter((state) => ({ ...state, searchFilter })), - [] + (searchFilter: string) => { + setFilter((state) => ({ ...state, searchFilter })); + + // Update URL to match filter state + navigate({ + search: (prev) => ({ + ...prev, + search: searchFilter || "" + }) + }); + }, + [navigate] ); const handleToggleVisibility = useCallback(() => setIsVisible((state) => !state), []); @@ -564,13 +603,6 @@ const Page = () => { include: includeFilter })); setDebouncedSearchFilter(routerQueryParams.search as string); - // this is a temp workaround until we fully transition state to query params, - navigate({ - search: (state) => { - const { search, tags: qTags, filterBy: qFilterBy, ...query } = state; - return query; - } - }); }, [routerQueryParams.search, routerQueryParams.tags, routerQueryParams.filterBy]); const selectedSecrets = useSelectedSecrets();