diff --git a/packages/bruno-app/src/components/Environments/CollapsibleSection/StyledWrapper.js b/packages/bruno-app/src/components/Environments/CollapsibleSection/StyledWrapper.js
index a16375965..57bec15a3 100644
--- a/packages/bruno-app/src/components/Environments/CollapsibleSection/StyledWrapper.js
+++ b/packages/bruno-app/src/components/Environments/CollapsibleSection/StyledWrapper.js
@@ -55,6 +55,7 @@ const StyledWrapper = styled.div`
}
.section-title {
+ padding-right: 4px;
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js
index 2a7f5ea56..d6cca70c9 100644
--- a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js
+++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js
@@ -1,7 +1,6 @@
import { IconCopy, IconEdit, IconTrash, IconCheck, IconX, IconSearch } from '@tabler/icons';
import { useState, useRef } from 'react';
import { useDispatch } from 'react-redux';
-import useDebounce from 'hooks/useDebounce';
import { renameEnvironment, updateEnvironmentColor } from 'providers/ReduxStore/slices/collections/actions';
import { validateName, validateNameError } from 'utils/common/regex';
import toast from 'react-hot-toast';
@@ -11,7 +10,7 @@ import EnvironmentVariables from './EnvironmentVariables';
import ColorPicker from 'components/ColorPicker';
import StyledWrapper from './StyledWrapper';
-const EnvironmentDetails = ({ environment, setIsModified, collection }) => {
+const EnvironmentDetails = ({ environment, setIsModified, collection, searchQuery, setSearchQuery, isSearchExpanded, setIsSearchExpanded, debouncedSearchQuery, searchInputRef }) => {
const dispatch = useDispatch();
const environments = collection?.environments || [];
@@ -20,11 +19,7 @@ const EnvironmentDetails = ({ environment, setIsModified, collection }) => {
const [isRenaming, setIsRenaming] = useState(false);
const [newName, setNewName] = useState('');
const [nameError, setNameError] = useState('');
- const [searchQuery, setSearchQuery] = useState('');
- const [isSearchExpanded, setIsSearchExpanded] = useState(false);
- const debouncedSearchQuery = useDebounce(searchQuery, 300);
const inputRef = useRef(null);
- const searchInputRef = useRef(null);
const validateEnvironmentName = (name) => {
if (!name || name.trim() === '') {
diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/StyledWrapper.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/StyledWrapper.js
index 4dc305394..87ba75d63 100644
--- a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/StyledWrapper.js
+++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/StyledWrapper.js
@@ -32,19 +32,6 @@ const StyledWrapper = styled.div`
flex-direction: column;
}
- .sidebar-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 16px 16px 12px 16px;
-
- .title {
- font-size: ${(props) => props.theme.font.size.base};
- font-weight: 500;
- color: ${(props) => props.theme.text};
- margin: 0;
- }
-
.btn-action {
display: flex;
align-items: center;
@@ -66,35 +53,54 @@ const StyledWrapper = styled.div`
}
}
- .search-container {
+ .env-list-search {
position: relative;
- padding: 0 12px 12px 12px;
-
- .search-icon {
+ display: flex;
+ align-items: center;
+ margin: 0 4px 6px 4px;
+
+ .env-list-search-icon {
position: absolute;
- left: 20px;
- top: 50%;
- transform: translateY(-100%);
+ left: 8px;
color: ${(props) => props.theme.colors.text.muted};
pointer-events: none;
}
-
- .search-input {
+
+ .env-list-search-input {
width: 100%;
- padding: 6px 8px 6px 28px;
+ padding: 5px 24px 5px 26px;
font-size: 12px;
background: transparent;
border: 1px solid ${(props) => props.theme.border.border1};
border-radius: 5px;
color: ${(props) => props.theme.text};
- transition: all 0.15s ease;
-
+ transition: border-color 0.15s ease;
+
&::placeholder {
color: ${(props) => props.theme.colors.text.muted};
}
&:focus {
outline: none;
+ border-color: ${(props) => props.theme.colors.accent};
+ }
+ }
+
+ .env-list-search-clear {
+ position: absolute;
+ right: 4px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 2px;
+ background: transparent;
+ border: none;
+ cursor: pointer;
+ color: ${(props) => props.theme.colors.text.muted};
+ border-radius: 3px;
+
+ &:hover {
+ color: ${(props) => props.theme.text};
}
}
}
@@ -130,6 +136,10 @@ const StyledWrapper = styled.div`
background: ${(props) => props.theme.sidebar.collection.item.hoverBg};
color: ${(props) => props.theme.text};
}
+
+ &.active {
+ color: ${(props) => props.theme.colors.accent};
+ }
}
.environment-item {
diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js
index 4c2b2d07e..231ceee25 100644
--- a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js
+++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js
@@ -1,6 +1,7 @@
import React, { useEffect, useState, useRef, useCallback } from 'react';
import usePrevious from 'hooks/usePrevious';
import useOnClickOutside from 'hooks/useOnClickOutside';
+import useDebounce from 'hooks/useDebounce';
import EnvironmentDetails from './EnvironmentDetails';
import { IconDownload, IconUpload, IconSearch, IconPlus, IconCheck, IconX, IconFileAlert } from '@tabler/icons';
import Button from 'ui/Button';
@@ -23,6 +24,7 @@ import {
deleteDotEnvFile
} from 'providers/ReduxStore/slices/collections/actions';
import { setEnvironmentsDraft, clearEnvironmentsDraft } from 'providers/ReduxStore/slices/collections';
+import { setEnvVarSearchQuery, setEnvVarSearchExpanded } from 'providers/ReduxStore/slices/app';
import { validateName, validateNameError } from 'utils/common/regex';
import toast from 'react-hot-toast';
import classnames from 'classnames';
@@ -40,9 +42,15 @@ 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 [openImportModal, setOpenImportModal] = useState(false);
const [searchText, setSearchText] = useState('');
+ const [isEnvListSearchExpanded, setIsEnvListSearchExpanded] = useState(false);
+ const envListSearchInputRef = useRef(null);
const [isCreatingInline, setIsCreatingInline] = useState(false);
const [renamingEnvUid, setRenamingEnvUid] = useState(null);
const [newEnvName, setNewEnvName] = useState('');
@@ -65,6 +73,9 @@ const EnvironmentList = ({
const dotEnvInputRef = useRef(null);
const dotEnvCreateContainerRef = useRef(null);
+ const debouncedEnvSearchQuery = useDebounce(envSearchQuery, 300);
+ const envSearchInputRef = useRef(null);
+
const dotEnvFiles = useSelector((state) => {
const coll = state.collections.collections.find((c) => c.uid === collection?.uid);
return coll?.dotEnvFiles || EMPTY_ARRAY;
@@ -497,6 +508,12 @@ const EnvironmentList = ({
setIsModified={setIsModified}
originalEnvironmentVariables={originalEnvironmentVariables}
collection={collection}
+ searchQuery={envSearchQuery}
+ setSearchQuery={setEnvSearchQuery}
+ isSearchExpanded={isEnvSearchExpanded}
+ setIsSearchExpanded={setIsEnvSearchExpanded}
+ debouncedSearchQuery={debouncedEnvSearchQuery}
+ searchInputRef={envSearchInputRef}
/>
);
}
@@ -531,20 +548,6 @@ const EnvironmentList = ({
)}
-
-
Variables
-
-
-
-
- setSearchText(e.target.value)}
- className="search-input"
- />
-
setEnvironmentsExpanded(!environmentsExpanded)}
actions={(
<>
+
@@ -565,6 +581,28 @@ const EnvironmentList = ({
>
)}
>
+ {isEnvListSearchExpanded && (
+
+
+ setSearchText(e.target.value)}
+ className="env-list-search-input"
+ autoComplete="off"
+ autoCorrect="off"
+ autoCapitalize="off"
+ spellCheck="false"
+ />
+ {searchText && (
+
+ )}
+
+ )}
{filteredEnvironments.map((env) => (
{
+const EnvironmentDetails = ({ environment, setIsModified, collection, searchQuery, setSearchQuery, isSearchExpanded, setIsSearchExpanded, debouncedSearchQuery, searchInputRef }) => {
const dispatch = useDispatch();
const globalEnvs = useSelector((state) => state?.globalEnvironments?.globalEnvironments);
@@ -20,11 +19,7 @@ const EnvironmentDetails = ({ environment, setIsModified, collection }) => {
const [isRenaming, setIsRenaming] = useState(false);
const [newName, setNewName] = useState('');
const [nameError, setNameError] = useState('');
- const [searchQuery, setSearchQuery] = useState('');
- const [isSearchExpanded, setIsSearchExpanded] = useState(false);
- const debouncedSearchQuery = useDebounce(searchQuery, 300);
const inputRef = useRef(null);
- const searchInputRef = useRef(null);
const validateEnvironmentName = (name) => {
if (!name || name.trim() === '') {
diff --git a/packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/StyledWrapper.js b/packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/StyledWrapper.js
index c36d77868..52f9f2f60 100644
--- a/packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/StyledWrapper.js
+++ b/packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/StyledWrapper.js
@@ -32,19 +32,7 @@ const StyledWrapper = styled.div`
flex-direction: column;
}
- .sidebar-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 16px 16px 12px 16px;
-
- .title {
- font-size: ${(props) => props.theme.font.size.base};
- font-weight: 500;
- color: ${(props) => props.theme.text};
- margin: 0;
- }
-
+
.btn-action {
display: flex;
align-items: center;
@@ -66,35 +54,54 @@ const StyledWrapper = styled.div`
}
}
- .search-container {
+ .env-list-search {
position: relative;
- padding: 0 12px 12px 12px;
-
- .search-icon {
+ display: flex;
+ align-items: center;
+ margin: 0 4px 6px 4px;
+
+ .env-list-search-icon {
position: absolute;
- left: 20px;
- top: 50%;
- transform: translateY(-100%);
+ left: 8px;
color: ${(props) => props.theme.colors.text.muted};
pointer-events: none;
}
-
- .search-input {
+
+ .env-list-search-input {
width: 100%;
- padding: 6px 8px 6px 28px;
+ padding: 5px 24px 5px 26px;
font-size: 12px;
background: transparent;
border: 1px solid ${(props) => props.theme.border.border1};
border-radius: 5px;
color: ${(props) => props.theme.text};
- transition: all 0.15s ease;
-
+ transition: border-color 0.15s ease;
+
&::placeholder {
color: ${(props) => props.theme.colors.text.muted};
}
&:focus {
outline: none;
+ border-color: ${(props) => props.theme.colors.accent};
+ }
+ }
+
+ .env-list-search-clear {
+ position: absolute;
+ right: 4px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 2px;
+ background: transparent;
+ border: none;
+ cursor: pointer;
+ color: ${(props) => props.theme.colors.text.muted};
+ border-radius: 3px;
+
+ &:hover {
+ color: ${(props) => props.theme.text};
}
}
}
@@ -130,6 +137,10 @@ const StyledWrapper = styled.div`
background: ${(props) => props.theme.sidebar.collection.item.hoverBg};
color: ${(props) => props.theme.text};
}
+
+ &.active {
+ color: ${(props) => props.theme.colors.accent};
+ }
}
.environment-item {
diff --git a/packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/index.js b/packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/index.js
index d514aa1f5..47db76f4e 100644
--- a/packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/index.js
+++ b/packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/index.js
@@ -1,6 +1,7 @@
import React, { useEffect, useState, useRef, useCallback } from 'react';
import usePrevious from 'hooks/usePrevious';
import useOnClickOutside from 'hooks/useOnClickOutside';
+import useDebounce from 'hooks/useDebounce';
import EnvironmentDetails from './EnvironmentDetails';
import { IconDownload, IconUpload, IconSearch, IconPlus, IconCheck, IconX, IconFileAlert } from '@tabler/icons';
import Button from 'ui/Button';
@@ -20,6 +21,7 @@ import {
createWorkspaceDotEnvFile,
deleteWorkspaceDotEnvFile
} from 'providers/ReduxStore/slices/workspaces/actions';
+import { setEnvVarSearchQuery, setEnvVarSearchExpanded } from 'providers/ReduxStore/slices/app';
import { validateName, validateNameError } from 'utils/common/regex';
import toast from 'react-hot-toast';
import classnames from 'classnames';
@@ -39,9 +41,15 @@ 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 setEnvSearchQuery = (q) => dispatch(setEnvVarSearchQuery({ context: 'global', query: q }));
+ const setIsEnvSearchExpanded = (v) => dispatch(setEnvVarSearchExpanded({ context: 'global', expanded: v }));
const [openImportModal, setOpenImportModal] = useState(false);
const [searchText, setSearchText] = useState('');
+ const [isEnvListSearchExpanded, setIsEnvListSearchExpanded] = useState(false);
+ const envListSearchInputRef = useRef(null);
const [isCreatingInline, setIsCreatingInline] = useState(false);
const [renamingEnvUid, setRenamingEnvUid] = useState(null);
const [newEnvName, setNewEnvName] = useState('');
@@ -64,6 +72,9 @@ const EnvironmentList = ({
const dotEnvInputRef = useRef(null);
const dotEnvCreateContainerRef = useRef(null);
+ const debouncedEnvSearchQuery = useDebounce(envSearchQuery, 300);
+ const envSearchInputRef = useRef(null);
+
const dotEnvFiles = useSelector((state) => {
const ws = state.workspaces.workspaces.find((w) => w.uid === workspace?.uid);
return ws?.dotEnvFiles || EMPTY_ARRAY;
@@ -493,6 +504,12 @@ const EnvironmentList = ({
setIsModified={setIsModified}
originalEnvironmentVariables={originalEnvironmentVariables}
collection={collection}
+ searchQuery={envSearchQuery}
+ setSearchQuery={setEnvSearchQuery}
+ isSearchExpanded={isEnvSearchExpanded}
+ setIsSearchExpanded={setIsEnvSearchExpanded}
+ debouncedSearchQuery={debouncedEnvSearchQuery}
+ searchInputRef={envSearchInputRef}
/>
);
}
@@ -525,20 +542,6 @@ const EnvironmentList = ({
)}
-
-
Variables
-
-
-
-
- setSearchText(e.target.value)}
- className="search-input"
- />
-
setEnvironmentsExpanded(!environmentsExpanded)}
actions={(
<>
+
@@ -559,6 +575,28 @@ const EnvironmentList = ({
>
)}
>
+ {isEnvListSearchExpanded && (
+
+
+ setSearchText(e.target.value)}
+ className="env-list-search-input"
+ autoComplete="off"
+ autoCorrect="off"
+ autoCapitalize="off"
+ spellCheck="false"
+ />
+ {searchText && (
+
+ )}
+
+ )}
{filteredEnvironments.map((env) => (
{
// 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;
+ },
+ setEnvVarSearchExpanded: (state, { payload: { context, expanded } }) => {
+ if (!state.envVarSearch[context]) return;
+ state.envVarSearch[context].expanded = expanded;
}
},
extraReducers: (builder) => {
@@ -182,7 +194,9 @@ export const {
updateGitOperationProgress,
removeGitOperationProgress,
setGitVersion,
- setClipboard
+ setClipboard,
+ setEnvVarSearchQuery,
+ setEnvVarSearchExpanded
} = appSlice.actions;
export const savePreferences = (preferences) => (dispatch, getState) => {