mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-11 09:51:30 +00:00
fix: export/import icons and styles (#6462)
This commit is contained in:
@@ -237,6 +237,12 @@ const Wrapper = styled.div`
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-item-active {
|
||||
font-weight: 400 !important;
|
||||
background-color: ${(props) => props.theme.dropdown.selectedBg} !important;
|
||||
color: ${(props) => props.theme.dropdown.selectedColor} !important;
|
||||
}
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { IconCheck, IconChevronDown, IconFolder, IconHome, IconPin, IconPinned, IconPlus, IconUpload, IconSettings, IconMinus, IconSquare, IconX, IconCopy } from '@tabler/icons';
|
||||
import { IconCheck, IconChevronDown, IconFolder, IconHome, IconPin, IconPinned, IconPlus, IconDownload, IconSettings, IconMinus, IconSquare, IconX, IconCopy } from '@tabler/icons';
|
||||
import { forwardRef, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
@@ -221,7 +221,7 @@ const AppTitleBar = () => {
|
||||
},
|
||||
{
|
||||
id: 'import-workspace',
|
||||
leftSection: IconUpload,
|
||||
leftSection: IconDownload,
|
||||
label: 'Import workspace',
|
||||
onClick: handleImportWorkspace
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import Modal from 'components/Modal';
|
||||
import { IconDownload, IconLoader2, IconAlertTriangle } from '@tabler/icons';
|
||||
import { IconUpload, IconLoader2, IconAlertTriangle } from '@tabler/icons';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import Bruno from 'components/Bruno';
|
||||
import exportBrunoCollection from 'utils/collections/export';
|
||||
@@ -100,7 +100,7 @@ const ShareCollection = ({ onClose, collectionUid }) => {
|
||||
{isCollectionLoading ? (
|
||||
<IconLoader2 size={28} className="animate-spin" />
|
||||
) : (
|
||||
<IconDownload size={28} strokeWidth={1} className="" />
|
||||
<IconUpload size={28} strokeWidth={1} className="" />
|
||||
)}
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
|
||||
@@ -142,14 +142,6 @@ const CollectionsSection = () => {
|
||||
setCreateCollectionModalOpen(true);
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'import',
|
||||
leftSection: IconDownload,
|
||||
label: 'Import collection',
|
||||
onClick: () => {
|
||||
setImportCollectionModalOpen(true);
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'open',
|
||||
leftSection: IconFolder,
|
||||
@@ -157,6 +149,14 @@ const CollectionsSection = () => {
|
||||
onClick: () => {
|
||||
handleOpenCollection();
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'import',
|
||||
leftSection: IconDownload,
|
||||
label: 'Import collection',
|
||||
onClick: () => {
|
||||
setImportCollectionModalOpen(true);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
import { useState, forwardRef, useRef, useMemo, useCallback } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import toast from 'react-hot-toast';
|
||||
import { IconPlus, IconChevronDown, IconCheck, IconFolder, IconPin, IconPinned } from '@tabler/icons';
|
||||
|
||||
import { savePreferences } from 'providers/ReduxStore/slices/app';
|
||||
import { switchWorkspace, openWorkspaceDialog } from 'providers/ReduxStore/slices/workspaces/actions';
|
||||
import { sortWorkspaces, toggleWorkspacePin } from 'utils/workspaces';
|
||||
|
||||
import Dropdown from 'components/Dropdown';
|
||||
import CreateWorkspace from 'components/WorkspaceSidebar/CreateWorkspace';
|
||||
import { toTitleCase } from 'utils/common/index';
|
||||
|
||||
const WorkspaceSelector = () => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const { workspaces, activeWorkspaceUid } = useSelector((state) => state.workspaces);
|
||||
const preferences = useSelector((state) => state.app.preferences);
|
||||
const activeWorkspace = workspaces.find((w) => w.uid === activeWorkspaceUid);
|
||||
|
||||
const sortedWorkspaces = useMemo(() => {
|
||||
return sortWorkspaces(workspaces, preferences);
|
||||
}, [workspaces, preferences]);
|
||||
|
||||
const [showDropdown, setShowDropdown] = useState(false);
|
||||
const [createWorkspaceModalOpen, setCreateWorkspaceModalOpen] = useState(false);
|
||||
|
||||
const dropdownTippyRef = useRef();
|
||||
const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref);
|
||||
|
||||
const WorkspaceName = forwardRef((props, ref) => {
|
||||
return (
|
||||
<div ref={ref} className="workspace-name-container" onClick={() => setShowDropdown(!showDropdown)}>
|
||||
<span className="workspace-name">{toTitleCase(activeWorkspace?.name) || 'Default Workspace'}</span>
|
||||
<IconChevronDown size={14} stroke={1.5} className="chevron-icon" />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
const handleWorkspaceSwitch = (workspaceUid) => {
|
||||
dispatch(switchWorkspace(workspaceUid));
|
||||
setShowDropdown(false);
|
||||
toast.success(`Switched to ${workspaces.find((w) => w.uid === workspaceUid)?.name}`);
|
||||
};
|
||||
|
||||
const handleOpenWorkspace = async () => {
|
||||
setShowDropdown(false);
|
||||
try {
|
||||
await dispatch(openWorkspaceDialog());
|
||||
toast.success('Workspace opened successfully');
|
||||
} catch (error) {
|
||||
toast.error(error.message || 'Failed to open workspace');
|
||||
}
|
||||
};
|
||||
|
||||
const handleCreateWorkspace = () => {
|
||||
setShowDropdown(false);
|
||||
setCreateWorkspaceModalOpen(true);
|
||||
};
|
||||
|
||||
const handlePinWorkspace = useCallback((workspaceUid, e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const newPreferences = toggleWorkspacePin(workspaceUid, preferences);
|
||||
dispatch(savePreferences(newPreferences));
|
||||
}, [dispatch, preferences]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{createWorkspaceModalOpen && (
|
||||
<CreateWorkspace onClose={() => setCreateWorkspaceModalOpen(false)} />
|
||||
)}
|
||||
|
||||
<Dropdown
|
||||
onCreate={onDropdownCreate}
|
||||
icon={<WorkspaceName />}
|
||||
placement="bottom-start"
|
||||
style="new"
|
||||
visible={showDropdown}
|
||||
onClickOutside={() => setShowDropdown(false)}
|
||||
>
|
||||
{sortedWorkspaces.map((workspace) => {
|
||||
const isActive = workspace.uid === activeWorkspaceUid;
|
||||
const isPinned = preferences?.workspaces?.pinnedWorkspaceUids?.includes(workspace.uid);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={workspace.uid}
|
||||
className={`dropdown-item workspace-item ${isActive ? 'active' : ''}`}
|
||||
onClick={() => handleWorkspaceSwitch(workspace.uid)}
|
||||
>
|
||||
<span className="workspace-name">{toTitleCase(workspace.name)}</span>
|
||||
<div className="workspace-actions">
|
||||
{workspace.type !== 'default' && (
|
||||
<button
|
||||
className={`pin-btn ${isPinned ? 'pinned' : ''}`}
|
||||
onClick={(e) => handlePinWorkspace(workspace.uid, e)}
|
||||
title={isPinned ? 'Unpin workspace' : 'Pin workspace'}
|
||||
>
|
||||
{isPinned ? (
|
||||
<IconPinned size={14} stroke={1.5} />
|
||||
) : (
|
||||
<IconPin size={14} stroke={1.5} />
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
{isActive && <IconCheck size={16} stroke={1.5} className="check-icon" />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
<div className="label-item border-top">Workspaces</div>
|
||||
|
||||
<div className="dropdown-item" onClick={handleCreateWorkspace}>
|
||||
<IconPlus size={16} stroke={1.5} className="icon" />
|
||||
Create workspace
|
||||
</div>
|
||||
<div className="dropdown-item" onClick={handleOpenWorkspace}>
|
||||
<IconFolder size={16} stroke={1.5} className="icon" />
|
||||
Open workspace
|
||||
</div>
|
||||
</Dropdown>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default WorkspaceSelector;
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { IconPlus, IconFolder, IconFileImport } from '@tabler/icons';
|
||||
import { IconPlus, IconFolder, IconDownload } from '@tabler/icons';
|
||||
import { importCollection, openCollection } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import toast from 'react-hot-toast';
|
||||
import CreateCollection from 'components/Sidebar/CreateCollection';
|
||||
@@ -116,7 +116,7 @@ const WorkspaceOverview = ({ workspace }) => {
|
||||
<span>Open Collection</span>
|
||||
</button>
|
||||
<button className="quick-action-btn" onClick={handleImportCollection}>
|
||||
<IconFileImport size={14} strokeWidth={1.5} />
|
||||
<IconDownload size={14} strokeWidth={1.5} />
|
||||
<span>Import Collection</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { IconCategory, IconDots, IconEdit, IconX, IconCheck, IconFolder, IconDownload } from '@tabler/icons';
|
||||
import { IconCategory, IconDots, IconEdit, IconX, IconCheck, IconFolder, IconUpload } from '@tabler/icons';
|
||||
import { renameWorkspaceAction, exportWorkspaceAction } from 'providers/ReduxStore/slices/workspaces/actions';
|
||||
import { showInFolder } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import toast from 'react-hot-toast';
|
||||
@@ -228,7 +228,7 @@ const WorkspaceHome = () => {
|
||||
<span>Show in Folder</span>
|
||||
</div>
|
||||
<div className="dropdown-item" onClick={handleExportWorkspace}>
|
||||
<IconDownload size={16} strokeWidth={1.5} />
|
||||
<IconUpload size={16} strokeWidth={1.5} />
|
||||
<span>Export</span>
|
||||
</div>
|
||||
<div className="dropdown-item" onClick={handleCloseWorkspaceClick}>
|
||||
|
||||
Reference in New Issue
Block a user