fix(app): scope env variable/secret search per tab (#8491)

This commit is contained in:
Pooja
2026-07-07 15:05:29 +05:30
committed by GitHub
parent 6f8865e162
commit 4592d2c30e
7 changed files with 166 additions and 31 deletions

View File

@@ -1,5 +1,5 @@
import { IconCopy, IconEdit, IconTrash, IconCheck, IconX, IconSearch, IconDeviceFloppy } from '@tabler/icons';
import { useState, useRef } from 'react';
import { useState, useRef, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { renameEnvironment, updateEnvironmentColor } from 'providers/ReduxStore/slices/collections/actions';
import { validateName, validateNameError } from 'utils/common/regex';
@@ -30,6 +30,16 @@ const EnvironmentDetails = ({ environment, setIsModified, collection, searchQuer
const activeTabUid = useSelector((state) => state.tabs.activeTabUid);
const activeTab = useSelector((state) => state.tabs.tabs.find((t) => t.uid === activeTabUid)?.tabState?.envTab) || 'variables';
const setActiveTab = (tab) => dispatch(updateTabState({ uid: activeTabUid, tabState: { envTab: tab } }));
// Use the immediate query on a tab switch (debounced value lags and briefly
// flashes the unfiltered table).
const prevTabRef = useRef(activeTab);
const tabJustChanged = prevTabRef.current !== activeTab;
useEffect(() => {
prevTabRef.current = activeTab;
}, [activeTab]);
const tableSearchQuery = tabJustChanged ? searchQuery : debouncedSearchQuery;
const inputRef = useRef(null);
const rightContentRef = useRef(null);
@@ -270,7 +280,7 @@ const EnvironmentDetails = ({ environment, setIsModified, collection, searchQuer
environment={environment}
setIsModified={setIsModified}
collection={collection}
searchQuery={debouncedSearchQuery}
searchQuery={tableSearchQuery}
variableType={activeTab}
/>
</div>

View File

@@ -42,10 +42,12 @@ const EnvironmentList = ({
setShowExportModal
}) => {
const dispatch = useDispatch();
const envSearchQuery = useSelector((state) => state.app.envVarSearch?.collection?.query ?? '');
const isEnvSearchExpanded = useSelector((state) => state.app.envVarSearch?.collection?.expanded ?? false);
const setEnvSearchQuery = (q) => dispatch(setEnvVarSearchQuery({ context: 'collection', query: q }));
const setIsEnvSearchExpanded = (v) => dispatch(setEnvVarSearchExpanded({ context: 'collection', expanded: v }));
const activeTabUid = useSelector((state) => state.tabs.activeTabUid);
const activeEnvTab = useSelector((state) => state.tabs.tabs.find((t) => t.uid === activeTabUid)?.tabState?.envTab) || 'variables';
const envSearchQuery = useSelector((state) => state.app.envVarSearch?.collection?.[activeEnvTab]?.query ?? '');
const isEnvSearchExpanded = useSelector((state) => state.app.envVarSearch?.collection?.[activeEnvTab]?.expanded ?? false);
const setEnvSearchQuery = (q) => dispatch(setEnvVarSearchQuery({ context: 'collection', tab: activeEnvTab, query: q }));
const setIsEnvSearchExpanded = (v) => dispatch(setEnvVarSearchExpanded({ context: 'collection', tab: activeEnvTab, expanded: v }));
const [openImportModal, setOpenImportModal] = useState(false);
const [searchText, setSearchText] = useState('');

View File

@@ -1,5 +1,5 @@
import { IconCopy, IconEdit, IconTrash, IconCheck, IconX, IconSearch, IconDeviceFloppy } from '@tabler/icons';
import { useState, useRef } from 'react';
import { useState, useRef, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { renameGlobalEnvironment, updateGlobalEnvironmentColor } from 'providers/ReduxStore/slices/global-environments';
import { updateTabState } from 'providers/ReduxStore/slices/tabs';
@@ -30,6 +30,16 @@ const EnvironmentDetails = ({ environment, setIsModified, collection, searchQuer
const activeTabUid = useSelector((state) => state.tabs.activeTabUid);
const activeTab = useSelector((state) => state.tabs.tabs.find((t) => t.uid === activeTabUid)?.tabState?.envTab) || 'variables';
const setActiveTab = (tab) => dispatch(updateTabState({ uid: activeTabUid, tabState: { envTab: tab } }));
// Use the immediate query on a tab switch (debounced value lags and briefly
// flashes the unfiltered table).
const prevTabRef = useRef(activeTab);
const tabJustChanged = prevTabRef.current !== activeTab;
useEffect(() => {
prevTabRef.current = activeTab;
}, [activeTab]);
const tableSearchQuery = tabJustChanged ? searchQuery : debouncedSearchQuery;
const inputRef = useRef(null);
const rightContentRef = useRef(null);
@@ -205,6 +215,9 @@ const EnvironmentDetails = ({ environment, setIsModified, collection, searchQuer
</div>
{nameError && isRenaming && <div className="title-error">{nameError}</div>}
<div className="actions">
<ActionIcon label="Save All" onClick={handleSaveAll} data-testid="save-all-env">
<IconDeviceFloppy size={15} strokeWidth={1.5} />
</ActionIcon>
<ActionIcon label="Rename" onClick={handleRenameClick} data-testid="env-rename-action">
<IconEdit size={15} strokeWidth={1.5} />
</ActionIcon>
@@ -224,9 +237,6 @@ const EnvironmentDetails = ({ environment, setIsModified, collection, searchQuer
onTabSelect={setActiveTab}
rightContent={(
<div ref={rightContentRef} className="env-search-container">
<ActionIcon label="Save" onClick={handleSaveAll} data-testid="save-all-env">
<IconDeviceFloppy size={15} strokeWidth={1.5} />
</ActionIcon>
{isSearchExpanded ? (
<div className="search-input-wrapper">
<IconSearch size={14} strokeWidth={1.5} className="search-icon" />
@@ -272,7 +282,7 @@ const EnvironmentDetails = ({ environment, setIsModified, collection, searchQuer
environment={environment}
setIsModified={setIsModified}
collection={collection}
searchQuery={debouncedSearchQuery}
searchQuery={tableSearchQuery}
variableType={activeTab}
/>
</div>

View File

@@ -43,11 +43,12 @@ const EnvironmentList = ({
}) => {
const dispatch = useDispatch();
const globalEnvs = useSelector((state) => state?.globalEnvironments?.globalEnvironments);
const envSearchQuery = useSelector((state) => state.app.envVarSearch?.global?.query ?? '');
const isEnvSearchExpanded = useSelector((state) => state.app.envVarSearch?.global?.expanded ?? false);
const activeTabUid = useSelector((state) => state.tabs.activeTabUid);
const setEnvSearchQuery = (q) => dispatch(setEnvVarSearchQuery({ context: 'global', query: q }));
const setIsEnvSearchExpanded = (v) => dispatch(setEnvVarSearchExpanded({ context: 'global', expanded: v }));
const activeEnvTab = useSelector((state) => state.tabs.tabs.find((t) => t.uid === activeTabUid)?.tabState?.envTab) || 'variables';
const envSearchQuery = useSelector((state) => state.app.envVarSearch?.global?.[activeEnvTab]?.query ?? '');
const isEnvSearchExpanded = useSelector((state) => state.app.envVarSearch?.global?.[activeEnvTab]?.expanded ?? false);
const setEnvSearchQuery = (q) => dispatch(setEnvVarSearchQuery({ context: 'global', tab: activeEnvTab, query: q }));
const setIsEnvSearchExpanded = (v) => dispatch(setEnvVarSearchExpanded({ context: 'global', tab: activeEnvTab, expanded: v }));
const [openImportModal, setOpenImportModal] = useState(false);
const [searchText, setSearchText] = useState('');

View File

@@ -98,8 +98,14 @@ const initialState = {
},
systemProxyVariables: {},
envVarSearch: {
collection: { query: '', expanded: false },
global: { query: '', expanded: false }
collection: {
variables: { query: '', expanded: false },
secrets: { query: '', expanded: false }
},
global: {
variables: { query: '', expanded: false },
secrets: { query: '', expanded: false }
}
},
isCreatingCollection: false
};
@@ -236,13 +242,13 @@ export const appSlice = createSlice({
// Update clipboard UI state
state.clipboard.hasCopiedItems = action.payload.hasCopiedItems;
},
setEnvVarSearchQuery: (state, { payload: { context, query } }) => {
if (!state.envVarSearch[context]) return;
state.envVarSearch[context].query = query;
setEnvVarSearchQuery: (state, { payload: { context, tab = 'variables', query } }) => {
if (!state.envVarSearch[context]?.[tab]) return;
state.envVarSearch[context][tab].query = query;
},
setEnvVarSearchExpanded: (state, { payload: { context, expanded } }) => {
if (!state.envVarSearch[context]) return;
state.envVarSearch[context].expanded = expanded;
setEnvVarSearchExpanded: (state, { payload: { context, tab = 'variables', expanded } }) => {
if (!state.envVarSearch[context]?.[tab]) return;
state.envVarSearch[context][tab].expanded = expanded;
},
setIsCreatingCollection: (state, action) => {
state.isCreatingCollection = action.payload;