mirror of
https://github.com/usebruno/bruno.git
synced 2026-07-08 06:28:33 +00:00
fix(app): scope env variable/secret search per tab (#8491)
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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('');
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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('');
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user