Files
bruno/packages/bruno-app/src/components/Sidebar/SidebarHeader/index.js
naman-bruno 6cc114100f fix (#6409)
2025-12-15 18:17:11 +05:30

304 lines
8.2 KiB
JavaScript

import {
IconArrowsSort,
IconBox,
IconDeviceDesktop,
IconDotsVertical,
IconDownload,
IconFileCode,
IconFolder,
IconPlus,
IconSearch,
IconSortAscendingLetters,
IconSortDescendingLetters,
IconSquareX,
IconTrash
} from '@tabler/icons';
import { useState } from 'react';
import toast from 'react-hot-toast';
import { useDispatch, useSelector } from 'react-redux';
import { importCollection, openCollection } from 'providers/ReduxStore/slices/collections/actions';
import { sortCollections } from 'providers/ReduxStore/slices/collections/index';
import { openApiSpec } from 'providers/ReduxStore/slices/apiSpec';
import MenuDropdown from 'ui/MenuDropdown';
import ActionIcon from 'ui/ActionIcon';
import ImportCollection from 'components/Sidebar/ImportCollection';
import ImportCollectionLocation from 'components/Sidebar/ImportCollectionLocation';
import CreateApiSpec from 'components/Sidebar/ApiSpecs/CreateApiSpec';
import RemoveCollectionsModal from '../Collections/RemoveCollectionsModal/index';
import CreateCollection from '../CreateCollection';
import StyledWrapper from './StyledWrapper';
const SidebarHeader = ({ setShowSearch }) => {
const dispatch = useDispatch();
const { workspaces, activeWorkspaceUid } = useSelector((state) => state.workspaces);
const activeWorkspace = workspaces.find((w) => w.uid === activeWorkspaceUid);
// Get collection sort order
const { collections } = useSelector((state) => state.collections);
const { collectionSortOrder } = useSelector((state) => state.collections);
const [collectionsToClose, setCollectionsToClose] = useState([]);
const [importData, setImportData] = useState(null);
const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false);
const [importCollectionModalOpen, setImportCollectionModalOpen] = useState(false);
const [importCollectionLocationModalOpen, setImportCollectionLocationModalOpen] = useState(false);
const [createApiSpecModalOpen, setCreateApiSpecModalOpen] = useState(false);
const handleImportCollection = ({ rawData, type }) => {
setImportCollectionModalOpen(false);
setImportData({ rawData, type });
setImportCollectionLocationModalOpen(true);
};
const handleImportCollectionLocation = (convertedCollection, collectionLocation) => {
dispatch(importCollection(convertedCollection, collectionLocation))
.then(() => {
setImportCollectionLocationModalOpen(false);
setImportData(null);
toast.success('Collection imported successfully');
})
.catch((err) => {
console.error(err);
toast.error('An error occurred while importing the collection');
});
};
const handleToggleSearch = () => {
if (setShowSearch) {
setShowSearch((prev) => !prev);
}
};
const handleSortCollections = () => {
let order;
switch (collectionSortOrder) {
case 'default':
order = 'alphabetical';
break;
case 'alphabetical':
order = 'reverseAlphabetical';
break;
case 'reverseAlphabetical':
order = 'default';
break;
default:
order = 'default';
break;
}
dispatch(sortCollections({ order }));
};
const getSortIcon = () => {
switch (collectionSortOrder) {
case 'alphabetical':
return IconSortDescendingLetters;
case 'reverseAlphabetical':
return IconArrowsSort;
default:
return IconSortAscendingLetters;
}
};
const getSortLabel = () => {
switch (collectionSortOrder) {
case 'alphabetical':
return 'Sort Z-A';
case 'reverseAlphabetical':
return 'Clear sort';
default:
return 'Sort A-Z';
}
};
const selectAllCollectionsToClose = () => {
setCollectionsToClose(collections.map((c) => c.uid));
};
const clearCollectionsToClose = () => {
setCollectionsToClose([]);
};
const handleOpenCollection = () => {
const options = {};
if (activeWorkspace?.pathname) {
options.workspaceId = activeWorkspace.pathname;
}
dispatch(openCollection(options)).catch((err) => {
toast.error('An error occurred while opening the collection');
});
};
const handleOpenApiSpec = () => {
dispatch(openApiSpec()).catch((err) => {
console.error(err);
toast.error('An error occurred while opening the API spec');
});
};
const renderModals = () => (
<>
{createCollectionModalOpen && (
<CreateCollection
onClose={() => setCreateCollectionModalOpen(false)}
/>
)}
{importCollectionModalOpen && (
<ImportCollection
onClose={() => setImportCollectionModalOpen(false)}
handleSubmit={handleImportCollection}
/>
)}
{importCollectionLocationModalOpen && importData && (
<ImportCollectionLocation
rawData={importData.rawData}
format={importData.type}
onClose={() => setImportCollectionLocationModalOpen(false)}
handleSubmit={handleImportCollectionLocation}
/>
)}
{createApiSpecModalOpen && (
<CreateApiSpec
onClose={() => setCreateApiSpecModalOpen(false)}
/>
)}
</>
);
// Configuration for Add/Create dropdown items
const addDropdownItems = [
{
id: 'create',
leftSection: IconPlus,
label: 'Create collection',
onClick: () => {
setCreateCollectionModalOpen(true);
}
},
{
id: 'import',
leftSection: IconDownload,
label: 'Import collection',
onClick: () => {
setImportCollectionModalOpen(true);
}
},
{
id: 'open',
leftSection: IconFolder,
label: 'Open collection',
onClick: () => {
handleOpenCollection();
}
},
{
type: 'label',
label: 'API Specs'
},
{
id: 'create-api-spec',
leftSection: IconPlus,
label: 'Create API Spec',
onClick: () => {
setCreateApiSpecModalOpen(true);
}
},
{
id: 'open-api-spec',
leftSection: IconFileCode,
label: 'Open API Spec',
onClick: () => {
handleOpenApiSpec();
}
}
];
// Configuration for Actions dropdown items
const actionsDropdownItems = [
{
id: 'sort',
leftSection: getSortIcon(),
label: getSortLabel(),
onClick: () => {
handleSortCollections();
}
},
{
id: 'close-all',
leftSection: IconSquareX,
label: 'Close all',
onClick: () => {
selectAllCollectionsToClose();
}
}
];
// Render Collections-specific actions
const renderCollectionsActions = () => (
<>
<ActionIcon
onClick={handleToggleSearch}
label="Search requests"
>
<IconSearch size={14} stroke={1.5} aria-hidden="true" />
</ActionIcon>
{/* Add Collection dropdown */}
<MenuDropdown
data-testid="collections-header-add-menu"
items={[
{ type: 'label', label: 'Collections' },
...addDropdownItems
]}
placement="bottom-end"
>
<ActionIcon
label="Add new collection"
>
<IconPlus size={14} stroke={1.5} aria-hidden="true" />
</ActionIcon>
</MenuDropdown>
{/* More Actions dropdown (sort, close all, etc.) */}
<MenuDropdown
data-testid="collections-header-actions-menu"
items={actionsDropdownItems}
placement="bottom-end"
>
<ActionIcon
label="More actions"
>
<IconDotsVertical size={14} stroke={1.5} aria-hidden="true" />
</ActionIcon>
</MenuDropdown>
{collectionsToClose.length > 0 && (
<RemoveCollectionsModal collectionUids={collectionsToClose} onClose={clearCollectionsToClose} />
)}
</>
);
return (
<StyledWrapper>
{renderModals()}
<div className="sidebar-header">
<div className="section-title">
<IconBox size={14} stroke={1.5} />
<span>Collections</span>
</div>
{/* Action Buttons - Context Sensitive */}
<div className="header-actions">
{renderCollectionsActions()}
</div>
</div>
</StyledWrapper>
);
};
export default SidebarHeader;