mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-11 09:51:30 +00:00
feat: enhance SaveTransientRequest component with folder navigation and input handling improvements (#7061)
This commit is contained in:
committed by
Bijin A B
parent
266e9ce230
commit
838e29682d
@@ -163,30 +163,17 @@ const StyledWrapper = styled.div`
|
||||
padding-top: 12px;
|
||||
}
|
||||
|
||||
.new-folder-content {
|
||||
.new-folder-header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.new-folder-inputs {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.new-folder-name-input-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.new-folder-name-label {
|
||||
font-size: 12px;
|
||||
.new-folder-header-label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: ${(props) => props.theme.colors.text.muted};
|
||||
color: ${(props) => props.theme.text};
|
||||
}
|
||||
|
||||
.new-folder-input-row {
|
||||
@@ -247,13 +234,12 @@ const StyledWrapper = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.new-folder-filesystem-label {
|
||||
font-size: 12px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: ${(props) => props.theme.colors.text.muted};
|
||||
color: ${(props) => props.theme.text};
|
||||
}
|
||||
|
||||
.new-folder-toggle-filesystem-btn {
|
||||
|
||||
@@ -45,6 +45,8 @@ const SaveTransientRequest = ({ item: itemProp, collection: collectionProp, isOp
|
||||
const [newFolderName, setNewFolderName] = useState('');
|
||||
const [newFolderDirectoryName, setNewFolderDirectoryName] = useState('');
|
||||
const [showFilesystemName, setShowFilesystemName] = useState(false);
|
||||
const [isEditingFolderFilename, setIsEditingFolderFilename] = useState(false);
|
||||
const [pendingFolderNavigation, setPendingFolderNavigation] = useState(null);
|
||||
const newFolderInputRef = useRef(null);
|
||||
|
||||
const {
|
||||
@@ -68,6 +70,8 @@ const SaveTransientRequest = ({ item: itemProp, collection: collectionProp, isOp
|
||||
setNewFolderName('');
|
||||
setNewFolderDirectoryName('');
|
||||
setShowFilesystemName(false);
|
||||
setIsEditingFolderFilename(false);
|
||||
setPendingFolderNavigation(null);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -80,6 +84,17 @@ const SaveTransientRequest = ({ item: itemProp, collection: collectionProp, isOp
|
||||
}
|
||||
}, [showNewFolderInput]);
|
||||
|
||||
// Auto-navigate into newly created folder when it appears in currentFolders
|
||||
useEffect(() => {
|
||||
if (pendingFolderNavigation) {
|
||||
const newFolder = currentFolders.find((f) => f.filename === pendingFolderNavigation);
|
||||
if (newFolder) {
|
||||
navigateIntoFolder(newFolder.uid);
|
||||
setPendingFolderNavigation(null);
|
||||
}
|
||||
}
|
||||
}, [currentFolders, pendingFolderNavigation, navigateIntoFolder]);
|
||||
|
||||
const filteredFolders = useMemo(() => {
|
||||
if (!searchText.trim()) {
|
||||
return currentFolders;
|
||||
@@ -165,6 +180,7 @@ const SaveTransientRequest = ({ item: itemProp, collection: collectionProp, isOp
|
||||
setNewFolderName('');
|
||||
setNewFolderDirectoryName('');
|
||||
setShowFilesystemName(false);
|
||||
setIsEditingFolderFilename(false);
|
||||
};
|
||||
|
||||
const handleCancelNewFolder = () => {
|
||||
@@ -172,26 +188,43 @@ const SaveTransientRequest = ({ item: itemProp, collection: collectionProp, isOp
|
||||
setNewFolderName('');
|
||||
setNewFolderDirectoryName('');
|
||||
setShowFilesystemName(false);
|
||||
setIsEditingFolderFilename(false);
|
||||
};
|
||||
|
||||
const handleNewFolderNameChange = (value) => {
|
||||
setNewFolderName(value);
|
||||
if (!showFilesystemName) {
|
||||
if (!isEditingFolderFilename) {
|
||||
setNewFolderDirectoryName(sanitizeName(value));
|
||||
}
|
||||
};
|
||||
|
||||
const handleDirectoryNameChange = (value) => {
|
||||
setNewFolderDirectoryName(value);
|
||||
setIsEditingFolderFilename(true);
|
||||
};
|
||||
|
||||
const handleCreateNewFolder = async () => {
|
||||
const directoryName = newFolderDirectoryName.trim() || sanitizeName(newFolderName.trim());
|
||||
const trimmedFolderName = newFolderName.trim();
|
||||
|
||||
if (!trimmedFolderName) {
|
||||
toast.error('Folder name is required');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validateName(trimmedFolderName)) {
|
||||
toast.error(validateNameError(trimmedFolderName));
|
||||
return;
|
||||
}
|
||||
|
||||
const directoryName = newFolderDirectoryName.trim() || sanitizeName(trimmedFolderName);
|
||||
const parentFolder = getCurrentParentFolder();
|
||||
|
||||
try {
|
||||
await dispatch(newFolder(newFolderName.trim(), directoryName, collection?.uid, parentFolder?.uid));
|
||||
await dispatch(newFolder(trimmedFolderName, directoryName, collection?.uid, parentFolder?.uid));
|
||||
toast.success('New folder created!');
|
||||
|
||||
// Set pending navigation - useEffect will navigate when folder appears in state
|
||||
setPendingFolderNavigation(directoryName);
|
||||
handleCancelNewFolder();
|
||||
} catch (err) {
|
||||
const errorMessage = err?.message || 'An error occurred while adding the folder';
|
||||
@@ -297,76 +330,80 @@ const SaveTransientRequest = ({ item: itemProp, collection: collectionProp, isOp
|
||||
))}
|
||||
{showNewFolderInput && (
|
||||
<li className="new-folder-item">
|
||||
<div className="new-folder-content">
|
||||
<div className="new-folder-header">
|
||||
<IconFolder size={16} strokeWidth={1.5} />
|
||||
<div className="new-folder-inputs">
|
||||
<div className="new-folder-name-input-wrapper">
|
||||
{showFilesystemName && (
|
||||
<label className="new-folder-name-label">New Folder name (in bruno)</label>
|
||||
)}
|
||||
<div className="new-folder-input-row">
|
||||
<input
|
||||
ref={newFolderInputRef}
|
||||
type="text"
|
||||
className="new-folder-input"
|
||||
placeholder="Untitled new folder"
|
||||
value={newFolderName}
|
||||
onChange={(e) => handleNewFolderNameChange(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
handleCreateNewFolder();
|
||||
} else if (e.key === 'Escape') {
|
||||
handleCancelNewFolder();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<div className="new-folder-actions">
|
||||
<button
|
||||
type="button"
|
||||
className="new-folder-action-btn"
|
||||
onClick={handleCancelNewFolder}
|
||||
title="Cancel"
|
||||
>
|
||||
<IconX size={16} strokeWidth={1.5} />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="new-folder-action-btn"
|
||||
onClick={handleCreateNewFolder}
|
||||
title="Create folder"
|
||||
>
|
||||
<IconCheck size={16} strokeWidth={1.5} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{showFilesystemName && (
|
||||
<div className="new-folder-filesystem-wrapper">
|
||||
<label className="new-folder-filesystem-label">Name on filesystem</label>
|
||||
<input
|
||||
type="text"
|
||||
className="new-folder-input"
|
||||
value={newFolderDirectoryName}
|
||||
onChange={(e) => handleDirectoryNameChange(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
handleCreateNewFolder();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<label className="new-folder-header-label">
|
||||
{showFilesystemName ? 'New Folder name (in bruno)' : 'New Folder name'}
|
||||
</label>
|
||||
</div>
|
||||
<div className="new-folder-input-row">
|
||||
<input
|
||||
ref={newFolderInputRef}
|
||||
type="text"
|
||||
className="new-folder-input"
|
||||
placeholder="Untitled new folder"
|
||||
value={newFolderName}
|
||||
onChange={(e) => handleNewFolderNameChange(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
handleCreateNewFolder();
|
||||
} else if (e.key === 'Escape') {
|
||||
e.stopPropagation();
|
||||
handleCancelNewFolder();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<div className="new-folder-actions">
|
||||
<button
|
||||
type="button"
|
||||
className="new-folder-action-btn"
|
||||
onClick={handleCancelNewFolder}
|
||||
title="Cancel"
|
||||
>
|
||||
<IconX size={16} strokeWidth={1.5} />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="new-folder-action-btn"
|
||||
onClick={handleCreateNewFolder}
|
||||
title="Create folder"
|
||||
>
|
||||
<IconCheck size={16} strokeWidth={1.5} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{showFilesystemName && (
|
||||
<div className="new-folder-filesystem-wrapper">
|
||||
<label className="new-folder-filesystem-label">Name on filesystem</label>
|
||||
<input
|
||||
type="text"
|
||||
className="new-folder-input"
|
||||
value={newFolderDirectoryName}
|
||||
onChange={(e) => handleDirectoryNameChange(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
handleCreateNewFolder();
|
||||
} else if (e.key === 'Escape') {
|
||||
e.stopPropagation();
|
||||
handleCancelNewFolder();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="new-folder-toggle-filesystem-btn"
|
||||
onClick={() => {
|
||||
setShowFilesystemName(!showFilesystemName);
|
||||
setNewFolderDirectoryName(sanitizeName(newFolderName));
|
||||
setIsEditingFolderFilename(false);
|
||||
}}
|
||||
>
|
||||
{showFilesystemName ? (
|
||||
|
||||
Reference in New Issue
Block a user