mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-25 05:35:41 +00:00
Merge pull request #5662 from Kwaadpepper/main
Closes #5460 Close multiple projects at once
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import { useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import {
|
||||
IconArrowsSort,
|
||||
IconFolders,
|
||||
IconSortAscendingLetters,
|
||||
IconSortDescendingLetters,
|
||||
IconX,
|
||||
} from '@tabler/icons';
|
||||
import { sortCollections } from 'providers/ReduxStore/slices/collections/index';
|
||||
import RemoveCollections from '../RemoveCollections/index';
|
||||
|
||||
const CollectionsBadge = () => {
|
||||
const dispatch = useDispatch();
|
||||
const { collections } = useSelector(state => state.collections);
|
||||
const { collectionSortOrder } = useSelector(state => state.collections);
|
||||
const sortCollectionOrder = () => {
|
||||
let order;
|
||||
switch (collectionSortOrder) {
|
||||
case 'default':
|
||||
order = 'alphabetical';
|
||||
break;
|
||||
case 'alphabetical':
|
||||
order = 'reverseAlphabetical';
|
||||
break;
|
||||
case 'reverseAlphabetical':
|
||||
order = 'default';
|
||||
break;
|
||||
}
|
||||
dispatch(sortCollections({ order }));
|
||||
};
|
||||
|
||||
let sortIcon;
|
||||
if (collectionSortOrder === 'default') {
|
||||
sortIcon = <IconArrowsSort size={18} strokeWidth={1.5} />;
|
||||
} else if (collectionSortOrder === 'alphabetical') {
|
||||
sortIcon = <IconSortAscendingLetters size={18} strokeWidth={1.5} />;
|
||||
} else {
|
||||
sortIcon = <IconSortDescendingLetters size={18} strokeWidth={1.5} />;
|
||||
}
|
||||
|
||||
const [collectionsToClose, setCollectionsToClose] = useState([]);
|
||||
const addAllCollectionsToClose = () => {
|
||||
setCollectionsToClose(collections.map(c => c.uid));
|
||||
};
|
||||
const emptyCollections = () => {
|
||||
setCollectionsToClose([]);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="items-center mt-2 relative">
|
||||
<div className="collections-badge flex items-center justify-between px-2">
|
||||
<div className="flex items-center py-1 select-none">
|
||||
<span className="mr-2">
|
||||
<IconFolders size={18} strokeWidth={1.5} />
|
||||
</span>
|
||||
<span>Collections</span>
|
||||
</div>
|
||||
{collections.length >= 1 && (
|
||||
<div className="flex items-center">
|
||||
<button onClick={() => sortCollectionOrder()}>
|
||||
{sortIcon}
|
||||
</button>
|
||||
<button className="ml-1" onClick={addAllCollectionsToClose}>
|
||||
<IconX
|
||||
size={16}
|
||||
strokeWidth={1.5}
|
||||
className="cursor-pointer"
|
||||
/>
|
||||
</button>
|
||||
{collectionsToClose.length > 0 && (
|
||||
<RemoveCollections collectionUids={collectionsToClose} onClose={emptyCollections} />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CollectionsBadge;
|
||||
@@ -0,0 +1,73 @@
|
||||
import React from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import { IconFiles } from '@tabler/icons';
|
||||
import Modal from 'components/Modal';
|
||||
import { removeCollection } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import { findCollectionByUid } from 'utils/collections/index';
|
||||
|
||||
const RemoveCollections = ({ collectionUids, onClose }) => {
|
||||
const dispatch = useDispatch();
|
||||
const allCollections = useSelector(state => state.collections.collections || []);
|
||||
|
||||
const selectedCollections = collectionUids
|
||||
.map(uid => findCollectionByUid(allCollections, uid))
|
||||
.filter(Boolean);
|
||||
|
||||
const collectionsNames = selectedCollections.map(c => c.name).join(', ');
|
||||
const collectionsPathnames = selectedCollections.map(c => c.pathname).join(', ');
|
||||
|
||||
const onConfirm = () => {
|
||||
const removalPromises = selectedCollections.map(collection => {
|
||||
return dispatch(removeCollection(collection.uid));
|
||||
});
|
||||
|
||||
Promise.all(removalPromises)
|
||||
.then(() => {
|
||||
toast.success('Collections are closed');
|
||||
})
|
||||
.catch(() => {
|
||||
toast.error('An error occurred while closing collections');
|
||||
})
|
||||
.finally(() => {
|
||||
if (onClose) onClose();
|
||||
});
|
||||
};
|
||||
|
||||
const getConfirmationText = () => {
|
||||
if (collectionUids.length > 1) {
|
||||
return `Are you sure you want to close all ${collectionUids.length} collections in Bruno?`;
|
||||
}
|
||||
return (
|
||||
<span>
|
||||
Are you sure you want to close the collection
|
||||
{' '}
|
||||
<span className="font-semibold">{collectionsNames}</span>
|
||||
{' '}
|
||||
in Bruno?
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal size="sm" title="Close Collections" confirmText="Close" handleConfirm={onConfirm} handleCancel={onClose}>
|
||||
<div className="flex items-center">
|
||||
<IconFiles size={18} strokeWidth={1.5} />
|
||||
<span className="ml-2 mr-4 font-semibold">{collectionsNames}</span>
|
||||
</div>
|
||||
<div className="break-words text-xs mt-1">{collectionsPathnames}</div>
|
||||
<div className="mt-4">{getConfirmationText()}</div>
|
||||
<div className="mt-4">
|
||||
It will still be available in the file system at the above locations and can be re-opened later.
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
RemoveCollections.propTypes = {
|
||||
collectionUids: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
onClose: PropTypes.func,
|
||||
};
|
||||
|
||||
export default RemoveCollections;
|
||||
@@ -1,64 +1,14 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import {
|
||||
IconSearch,
|
||||
IconFolders,
|
||||
IconArrowsSort,
|
||||
IconSortAscendingLetters,
|
||||
IconSortDescendingLetters,
|
||||
IconX
|
||||
IconX,
|
||||
} from '@tabler/icons';
|
||||
import Collection from './Collection';
|
||||
import React, { useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import CreateCollection from '../CreateCollection';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import Collection from './Collection';
|
||||
import CollectionsBadge from './CollectionsBadge/index';
|
||||
import CreateOrOpenCollection from './CreateOrOpenCollection';
|
||||
import { sortCollections } from 'providers/ReduxStore/slices/collections/actions';
|
||||
|
||||
// todo: move this to a separate folder
|
||||
// the coding convention is to keep all the components in a folder named after the component
|
||||
const CollectionsBadge = () => {
|
||||
const dispatch = useDispatch();
|
||||
const { collections } = useSelector((state) => state.collections);
|
||||
const { collectionSortOrder } = useSelector((state) => state.collections);
|
||||
const sortCollectionOrder = () => {
|
||||
let order;
|
||||
switch (collectionSortOrder) {
|
||||
case 'default':
|
||||
order = 'alphabetical';
|
||||
break;
|
||||
case 'alphabetical':
|
||||
order = 'reverseAlphabetical';
|
||||
break;
|
||||
case 'reverseAlphabetical':
|
||||
order = 'default';
|
||||
break;
|
||||
}
|
||||
dispatch(sortCollections({ order }));
|
||||
};
|
||||
return (
|
||||
<div className="items-center mt-2 relative">
|
||||
<div className="collections-badge flex items-center justify-between px-2">
|
||||
<div className="flex items-center py-1 select-none">
|
||||
<span className="mr-2">
|
||||
<IconFolders size={18} strokeWidth={1.5} />
|
||||
</span>
|
||||
<span>Collections</span>
|
||||
</div>
|
||||
{collections.length >= 1 && (
|
||||
<button onClick={() => sortCollectionOrder()}>
|
||||
{collectionSortOrder == 'default' ? (
|
||||
<IconArrowsSort size={18} strokeWidth={1.5} />
|
||||
) : collectionSortOrder == 'alphabetical' ? (
|
||||
<IconSortAscendingLetters size={18} strokeWidth={1.5} />
|
||||
) : (
|
||||
<IconSortDescendingLetters size={18} strokeWidth={1.5} />
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const Collections = () => {
|
||||
const [searchText, setSearchText] = useState('');
|
||||
|
||||
Reference in New Issue
Block a user