mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-24 13:15:40 +00:00
fixes: comments
This commit is contained in:
@@ -33,7 +33,7 @@ import WSRequestPane from 'components/RequestPane/WSRequestPane';
|
||||
import WSResponsePane from 'components/ResponsePane/WsResponsePane';
|
||||
import { useTabPaneBoundaries } from 'hooks/useTabPaneBoundaries/index';
|
||||
import ResponseExample from 'components/ResponseExample';
|
||||
import WorkspaceOverview from 'components/WorkspaceOverview/index';
|
||||
import WorkspaceHome from 'components/WorkspaceHome';
|
||||
|
||||
const MIN_LEFT_PANE_WIDTH = 300;
|
||||
const MIN_RIGHT_PANE_WIDTH = 350;
|
||||
@@ -137,7 +137,7 @@ const RequestTabPanel = () => {
|
||||
}, [dragging]);
|
||||
|
||||
if (!activeTabUid) {
|
||||
return <WorkspaceOverview />;
|
||||
return <WorkspaceHome />;
|
||||
}
|
||||
|
||||
if (!focusedTab || !focusedTab.uid || !focusedTab.collectionUid) {
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import { IconSearch, IconX } from '@tabler/icons';
|
||||
|
||||
const CollectionSearch = ({ searchText, setSearchText }) => {
|
||||
return (
|
||||
<div className="relative collection-filter px-2">
|
||||
<div className="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none">
|
||||
<span className="text-gray-500 sm:text-sm">
|
||||
<IconSearch size={16} strokeWidth={1.5} />
|
||||
</span>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
name="search"
|
||||
placeholder="Search requests …"
|
||||
id="search"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
className="block w-full pl-7 pr-8 py-1 sm:text-sm"
|
||||
value={searchText}
|
||||
onChange={(e) => setSearchText(e.target.value.toLowerCase())}
|
||||
/>
|
||||
{searchText !== '' && (
|
||||
<div className="absolute inset-y-0 right-0 pr-4 flex items-center">
|
||||
<span
|
||||
className="close-icon"
|
||||
onClick={() => {
|
||||
setSearchText('');
|
||||
}}
|
||||
>
|
||||
<IconX size={16} strokeWidth={1.5} className="cursor-pointer" />
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CollectionSearch;
|
||||
@@ -48,8 +48,6 @@ const CreateOrOpenCollection = () => {
|
||||
{createCollectionModalOpen ? (
|
||||
<CreateCollection
|
||||
onClose={() => setCreateCollectionModalOpen(false)}
|
||||
workspaceUid={activeWorkspaceUid}
|
||||
hideLocationInput={activeWorkspace && activeWorkspace.type !== 'default'}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { IconSearch, IconX } from '@tabler/icons';
|
||||
import Collection from '../Collections/Collection';
|
||||
import Collection from './Collection';
|
||||
import CreateCollection from '../CreateCollection';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import CreateOrOpenCollection from './CreateOrOpenCollection';
|
||||
import CollectionSearch from './CollectionSearch/index';
|
||||
|
||||
const Collections = ({ showSearch }) => {
|
||||
const [searchText, setSearchText] = useState('');
|
||||
@@ -14,27 +14,16 @@ const Collections = ({ showSearch }) => {
|
||||
|
||||
const activeWorkspace = workspaces.find((w) => w.uid === activeWorkspaceUid) || workspaces.find((w) => w.type === 'default');
|
||||
|
||||
let allCollections = [];
|
||||
let workspaceCollections = [];
|
||||
|
||||
if (!activeWorkspace || activeWorkspace.type === 'default') {
|
||||
if (activeWorkspace && activeWorkspace.collections && activeWorkspace.collections.length > 0) {
|
||||
allCollections = activeWorkspace.collections.map((wc) => {
|
||||
const loadedCollection = collections.find((c) => c.pathname === wc.path);
|
||||
return loadedCollection;
|
||||
}).filter(Boolean);
|
||||
} else {
|
||||
allCollections = [];
|
||||
}
|
||||
} else {
|
||||
if (activeWorkspace.collections && activeWorkspace.collections.length > 0) {
|
||||
allCollections = activeWorkspace.collections.map((wc) => {
|
||||
const loadedCollection = collections.find((c) => c.pathname === wc.path);
|
||||
return loadedCollection;
|
||||
}).filter(Boolean);
|
||||
}
|
||||
if (activeWorkspace?.collections?.length) {
|
||||
workspaceCollections = activeWorkspace.collections.map((wc) => {
|
||||
return collections.find((c) => c.pathname === wc.path);
|
||||
}).filter(Boolean);
|
||||
}
|
||||
|
||||
if (!allCollections || !allCollections.length) {
|
||||
|
||||
if (!workspaceCollections || !workspaceCollections.length) {
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<CreateOrOpenCollection />
|
||||
@@ -47,50 +36,16 @@ const Collections = ({ showSearch }) => {
|
||||
{createCollectionModalOpen ? (
|
||||
<CreateCollection
|
||||
onClose={() => setCreateCollectionModalOpen(false)}
|
||||
workspaceUid={activeWorkspace?.uid}
|
||||
defaultLocation={activeWorkspace?.pathname ? `${activeWorkspace.pathname}/collections` : ''}
|
||||
hideLocationInput={!!activeWorkspace?.pathname}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{showSearch && (
|
||||
<div className="relative collection-filter px-2">
|
||||
<div className="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none">
|
||||
<span className="text-gray-500 sm:text-sm">
|
||||
<IconSearch size={16} strokeWidth={1.5} />
|
||||
</span>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
name="search"
|
||||
placeholder="Search requests …"
|
||||
id="search"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
className="block w-full pl-7 pr-8 py-1 sm:text-sm"
|
||||
value={searchText}
|
||||
onChange={(e) => setSearchText(e.target.value.toLowerCase())}
|
||||
/>
|
||||
{searchText !== '' && (
|
||||
<div className="absolute inset-y-0 right-0 pr-4 flex items-center">
|
||||
<span
|
||||
className="close-icon"
|
||||
onClick={() => {
|
||||
setSearchText('');
|
||||
}}
|
||||
>
|
||||
<IconX size={16} strokeWidth={1.5} className="cursor-pointer" />
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<CollectionSearch searchText={searchText} setSearchText={setSearchText} />
|
||||
)}
|
||||
|
||||
<div className={`mt-4 flex flex-col overflow-hidden hover:overflow-y-auto absolute ${showSearch ? 'top-16' : 'top-8'} bottom-0 left-0 right-0`}>
|
||||
{allCollections && allCollections.length
|
||||
? allCollections.map((c) => {
|
||||
{workspaceCollections && workspaceCollections.length
|
||||
? workspaceCollections.map((c) => {
|
||||
return (
|
||||
<Collection searchText={searchText} collection={c} key={c.uid} />
|
||||
);
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useFormik } from 'formik';
|
||||
import * as Yup from 'yup';
|
||||
import path from 'path';
|
||||
import { browseDirectory, createCollection } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import { loadWorkspaceCollections } from 'providers/ReduxStore/slices/workspaces/actions';
|
||||
import toast from 'react-hot-toast';
|
||||
import Portal from 'components/Portal';
|
||||
import Modal from 'components/Modal';
|
||||
@@ -20,21 +19,27 @@ import Dropdown from 'components/Dropdown';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import get from 'lodash/get';
|
||||
|
||||
const CreateCollection = ({ onClose, workspaceUid, defaultLocation: propDefaultLocation, hideLocationInput = false }) => {
|
||||
const CreateCollection = ({ onClose, defaultLocation: propDefaultLocation }) => {
|
||||
const inputRef = useRef();
|
||||
const dispatch = useDispatch();
|
||||
const workspaces = useSelector((state) => state.workspaces?.workspaces || []);
|
||||
const workspaceUid = useSelector((state) => state.workspaces?.activeWorkspaceUid);
|
||||
const [isEditing, toggleEditing] = useState(false);
|
||||
const preferences = useSelector((state) => state.app.preferences);
|
||||
const [showExternalLocation, setShowExternalLocation] = useState(false);
|
||||
const [showAdvanced, setShowAdvanced] = useState(false);
|
||||
const defaultLocation = propDefaultLocation || get(preferences, 'general.defaultCollectionLocation', '');
|
||||
const dropdownTippyRef = useRef();
|
||||
const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref);
|
||||
|
||||
const activeWorkspace = workspaces.find((w) => w.uid === workspaceUid);
|
||||
const isDefaultWorkspace = activeWorkspace?.type === 'default';
|
||||
|
||||
const hideLocationInput = activeWorkspace && activeWorkspace.type !== 'default' && !!activeWorkspace?.pathname;
|
||||
|
||||
const defaultLocation = propDefaultLocation
|
||||
|| (activeWorkspace?.pathname ? `${activeWorkspace.pathname}/collections` : '')
|
||||
|| get(preferences, 'general.defaultCollectionLocation', '');
|
||||
|
||||
const shouldShowAccordion = workspaceUid && hideLocationInput && !isDefaultWorkspace;
|
||||
const actuallyHideLocationInput = hideLocationInput && !showExternalLocation && !isDefaultWorkspace;
|
||||
|
||||
@@ -87,7 +92,6 @@ const CreateCollection = ({ onClose, workspaceUid, defaultLocation: propDefaultL
|
||||
path: collectionPath
|
||||
};
|
||||
await ipcRenderer.invoke('renderer:add-collection-to-workspace', currentWorkspace.pathname, workspaceCollection);
|
||||
await dispatch(loadWorkspaceCollections(workspaceUid));
|
||||
}
|
||||
|
||||
toast.success('Collection created!');
|
||||
|
||||
@@ -6,32 +6,13 @@ const StyledWrapper = styled.div`
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.workspace-icon-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.workspace-letter-logo {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
background: white;
|
||||
color: #5d5d5d;
|
||||
}
|
||||
|
||||
.workspace-name-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 6px 10px;
|
||||
margin-left: 0px;
|
||||
border-radius: 6px;
|
||||
border-radius: ${(props) => props.theme.border.radius.base};
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
min-width: 0;
|
||||
@@ -43,7 +24,7 @@ const StyledWrapper = styled.div`
|
||||
}
|
||||
|
||||
.workspace-name {
|
||||
font-size: 13px;
|
||||
font-size: ${(props) => props.theme.font.size.base};
|
||||
font-weight: 600;
|
||||
color: ${(props) => props.theme.sidebar.color};
|
||||
white-space: nowrap;
|
||||
@@ -103,7 +84,7 @@ const StyledWrapper = styled.div`
|
||||
.workspace-name {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 13px;
|
||||
font-size: ${(props) => props.theme.font.size.base};
|
||||
font-weight: 400;
|
||||
color: ${(props) => props.theme.dropdown.color};
|
||||
white-space: nowrap;
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
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';
|
||||
|
||||
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 toTitleCase = (str) => {
|
||||
if (!str) return '';
|
||||
if (str === 'default') return 'Default';
|
||||
return str
|
||||
.split(/[\s-_]+/)
|
||||
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
||||
.join(' ');
|
||||
};
|
||||
|
||||
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,19 +1,18 @@
|
||||
import { useState, forwardRef, useRef, useMemo, useCallback } from 'react';
|
||||
import { useState, useRef } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import toast from 'react-hot-toast';
|
||||
import { IconPlus, IconChevronDown, IconCheck, IconFolder, IconDownload, IconPin, IconPinned, IconHome, IconSearch, IconDeviceDesktop } from '@tabler/icons';
|
||||
import { IconPlus, IconFolder, IconDownload, IconHome, IconSearch, IconDeviceDesktop } from '@tabler/icons';
|
||||
|
||||
import { showHomePage, savePreferences } from 'providers/ReduxStore/slices/app';
|
||||
import { showHomePage } from 'providers/ReduxStore/slices/app';
|
||||
import { openCollection, importCollection } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import { switchWorkspace, openWorkspaceDialog, importCollectionInWorkspace } from 'providers/ReduxStore/slices/workspaces/actions';
|
||||
import { sortWorkspaces, toggleWorkspacePin } from 'utils/workspaces';
|
||||
import { importCollectionInWorkspace } from 'providers/ReduxStore/slices/workspaces/actions';
|
||||
|
||||
import Dropdown from 'components/Dropdown';
|
||||
import ImportCollection from 'components/Sidebar/ImportCollection';
|
||||
import ImportCollectionLocation from 'components/Sidebar/ImportCollectionLocation';
|
||||
import CreateWorkspace from 'components/WorkspaceSidebar/CreateWorkspace';
|
||||
|
||||
import CreateCollection from '../CreateCollection';
|
||||
import WorkspaceSelector from './WorkspaceSelector';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const TitleBar = ({ showSearch, setShowSearch }) => {
|
||||
@@ -21,28 +20,15 @@ const TitleBar = ({ showSearch, setShowSearch }) => {
|
||||
const { ipcRenderer } = window;
|
||||
|
||||
const { workspaces, activeWorkspaceUid } = useSelector((state) => state.workspaces);
|
||||
const preferences = useSelector((state) => state.app.preferences);
|
||||
const activeWorkspace = workspaces.find((w) => w.uid === activeWorkspaceUid);
|
||||
|
||||
// Sort workspaces according to preferences
|
||||
const sortedWorkspaces = useMemo(() => {
|
||||
return sortWorkspaces(workspaces, preferences);
|
||||
}, [workspaces, preferences]);
|
||||
|
||||
const [importData, setImportData] = useState(null);
|
||||
const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false);
|
||||
const [importCollectionModalOpen, setImportCollectionModalOpen] = useState(false);
|
||||
const [importCollectionLocationModalOpen, setImportCollectionLocationModalOpen] = useState(false);
|
||||
const [createWorkspaceModalOpen, setCreateWorkspaceModalOpen] = useState(false);
|
||||
|
||||
const toTitleCase = (str) => {
|
||||
if (!str) return '';
|
||||
if (str === 'default') return 'Default';
|
||||
return str
|
||||
.split(/[\s-_]+/)
|
||||
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
||||
.join(' ');
|
||||
};
|
||||
const actionsDropdownTippyRef = useRef();
|
||||
const onActionsDropdownCreate = (ref) => (actionsDropdownTippyRef.current = ref);
|
||||
|
||||
const handleImportCollection = ({ rawData, type }) => {
|
||||
setImportCollectionModalOpen(false);
|
||||
@@ -71,56 +57,12 @@ const TitleBar = ({ showSearch, setShowSearch }) => {
|
||||
});
|
||||
};
|
||||
|
||||
const [showWorkspaceDropdown, setShowWorkspaceDropdown] = useState(false);
|
||||
const workspaceDropdownTippyRef = useRef();
|
||||
const onWorkspaceDropdownCreate = (ref) => (workspaceDropdownTippyRef.current = ref);
|
||||
|
||||
const actionsDropdownTippyRef = useRef();
|
||||
const onActionsDropdownCreate = (ref) => (actionsDropdownTippyRef.current = ref);
|
||||
|
||||
const WorkspaceName = forwardRef((props, ref) => {
|
||||
return (
|
||||
<div ref={ref} className="workspace-name-container" onClick={() => setShowWorkspaceDropdown(!showWorkspaceDropdown)}>
|
||||
<span className="workspace-name">{toTitleCase(activeWorkspace?.name) || 'Default Workspace'}</span>
|
||||
<IconChevronDown size={14} stroke={1.5} className="chevron-icon" />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
const handleToggleSearch = () => {
|
||||
if (setShowSearch) {
|
||||
setShowSearch((prev) => !prev);
|
||||
}
|
||||
};
|
||||
|
||||
const handleWorkspaceSwitch = (workspaceUid) => {
|
||||
dispatch(switchWorkspace(workspaceUid));
|
||||
setShowWorkspaceDropdown(false);
|
||||
toast.success(`Switched to ${workspaces.find((w) => w.uid === workspaceUid)?.name}`);
|
||||
};
|
||||
|
||||
const handleOpenWorkspace = async () => {
|
||||
setShowWorkspaceDropdown(false);
|
||||
try {
|
||||
await dispatch(openWorkspaceDialog());
|
||||
toast.success('Workspace opened successfully');
|
||||
} catch (error) {
|
||||
toast.error(error.message || 'Failed to open workspace');
|
||||
}
|
||||
};
|
||||
|
||||
const handleCreateWorkspace = () => {
|
||||
setShowWorkspaceDropdown(false);
|
||||
setCreateWorkspaceModalOpen(true);
|
||||
};
|
||||
|
||||
const handlePinWorkspace = useCallback((workspaceUid, e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const newPreferences = toggleWorkspacePin(workspaceUid, preferences);
|
||||
dispatch(savePreferences(newPreferences));
|
||||
}, [dispatch, preferences]);
|
||||
|
||||
const handleOpenCollection = () => {
|
||||
const options = {};
|
||||
if (activeWorkspace?.pathname) {
|
||||
@@ -141,9 +83,6 @@ const TitleBar = ({ showSearch, setShowSearch }) => {
|
||||
{createCollectionModalOpen && (
|
||||
<CreateCollection
|
||||
onClose={() => setCreateCollectionModalOpen(false)}
|
||||
workspaceUid={activeWorkspace?.uid}
|
||||
defaultLocation={activeWorkspace?.type !== 'default' && activeWorkspace?.pathname ? `${activeWorkspace.pathname}/collections` : undefined}
|
||||
hideLocationInput={activeWorkspace?.type !== 'default' && !!activeWorkspace?.pathname}
|
||||
/>
|
||||
)}
|
||||
{importCollectionModalOpen && (
|
||||
@@ -160,9 +99,6 @@ const TitleBar = ({ showSearch, setShowSearch }) => {
|
||||
handleSubmit={handleImportCollectionLocation}
|
||||
/>
|
||||
)}
|
||||
{createWorkspaceModalOpen && (
|
||||
<CreateWorkspace onClose={() => setCreateWorkspaceModalOpen(false)} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -170,60 +106,8 @@ const TitleBar = ({ showSearch, setShowSearch }) => {
|
||||
<StyledWrapper className="px-2 py-2">
|
||||
{renderModals()}
|
||||
<div className="titlebar-container">
|
||||
<WorkspaceSelector />
|
||||
|
||||
{/* Workspace Dropdown */}
|
||||
<Dropdown
|
||||
onCreate={onWorkspaceDropdownCreate}
|
||||
icon={<WorkspaceName />}
|
||||
placement="bottom-start"
|
||||
style="new"
|
||||
visible={showWorkspaceDropdown}
|
||||
onClickOutside={() => setShowWorkspaceDropdown(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>
|
||||
|
||||
{/* Search and Actions */}
|
||||
<div className="actions-container">
|
||||
<button className="home-icon-button" onClick={() => dispatch(showHomePage())} title="Home">
|
||||
<IconHome size={16} stroke={1.5} />
|
||||
|
||||
@@ -5,7 +5,7 @@ const StyledWrapper = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
font-size: 13px;
|
||||
font-size: ${(props) => props.theme.font.size.base};
|
||||
}
|
||||
|
||||
.collections-header {
|
||||
@@ -28,7 +28,7 @@ const StyledWrapper = styled.div`
|
||||
|
||||
.header-cell {
|
||||
font-weight: 600;
|
||||
font-size: 11px;
|
||||
font-size: ${(props) => props.theme.font.size.xs};
|
||||
color: ${(props) => props.theme.text.muted};
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
@@ -48,14 +48,7 @@ const StyledWrapper = styled.div`
|
||||
border-bottom: ${(props) => props.theme.workspace.collection.item.indentBorder};
|
||||
transition: background-color 0.15s ease;
|
||||
cursor: pointer;
|
||||
|
||||
&:has(.cell-git) {
|
||||
grid-template-columns: 1fr 3fr 1fr 1.5fr;
|
||||
}
|
||||
|
||||
&:not(:has(.cell-git)) {
|
||||
grid-template-columns: 1fr 3fr 1.5fr;
|
||||
}
|
||||
grid-template-columns: 1fr 3fr 1.5fr;
|
||||
|
||||
&:hover {
|
||||
background-color: ${(props) => props.theme.sidebar.bg};
|
||||
@@ -86,14 +79,14 @@ const StyledWrapper = styled.div`
|
||||
.collection-name {
|
||||
font-weight: 400;
|
||||
color: ${(props) => props.theme.text};
|
||||
font-size: 13px;
|
||||
font-size: ${(props) => props.theme.font.size.base};
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.collection-subtitle {
|
||||
font-size: 11px;
|
||||
font-size: ${(props) => props.theme.font.size.xs};
|
||||
color: ${(props) => props.theme.text.muted};
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
@@ -102,36 +95,9 @@ const StyledWrapper = styled.div`
|
||||
}
|
||||
}
|
||||
|
||||
.cell-type {
|
||||
.type-icon {
|
||||
flex-shrink: 0;
|
||||
|
||||
&.remote {
|
||||
color: #3B82F6;
|
||||
}
|
||||
|
||||
&.local {
|
||||
color: ${(props) => props.theme.workspace.accent};
|
||||
}
|
||||
}
|
||||
|
||||
.type-label {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
|
||||
&.remote {
|
||||
color: #3B82F6;
|
||||
}
|
||||
|
||||
&.local {
|
||||
color: ${(props) => props.theme.text.primary};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cell-location {
|
||||
.location-text {
|
||||
font-size: 12px;
|
||||
font-size: ${(props) => props.theme.font.size.sm};
|
||||
color: ${(props) => props.theme.text.muted};
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
@@ -140,77 +106,6 @@ const StyledWrapper = styled.div`
|
||||
}
|
||||
}
|
||||
|
||||
.cell-git {
|
||||
.git-badge {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 12px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
width: fit-content;
|
||||
|
||||
&.git-enabled {
|
||||
background-color: #10B98120;
|
||||
color: #10B981;
|
||||
}
|
||||
|
||||
&.git-disabled {
|
||||
background-color: ${(props) => props.theme.workspace.border}40;
|
||||
color: ${(props) => props.theme.text.muted};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cell-requests {
|
||||
.request-count {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.count-number {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
color: ${(props) => props.theme.text.primary};
|
||||
}
|
||||
|
||||
.count-label {
|
||||
font-size: 11px;
|
||||
color: ${(props) => props.theme.text.muted};
|
||||
}
|
||||
}
|
||||
|
||||
.cell-status {
|
||||
.status-badge {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 3px 8px;
|
||||
border-radius: 12px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
|
||||
&.status-ready {
|
||||
background-color: ${(props) => props.theme.workspace.accent}20;
|
||||
color: ${(props) => props.theme.workspace.accent};
|
||||
|
||||
.status-dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background-color: ${(props) => props.theme.workspace.accent};
|
||||
}
|
||||
}
|
||||
|
||||
&.status-not-loaded {
|
||||
background-color: ${(props) => props.theme.workspace.border}40;
|
||||
color: ${(props) => props.theme.text.muted};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cell-actions {
|
||||
justify-content: flex-end;
|
||||
|
||||
@@ -241,14 +136,6 @@ const StyledWrapper = styled.div`
|
||||
&:hover:not(:disabled) {
|
||||
background-color: ${(props) => props.theme.listItem.hoverBg};
|
||||
|
||||
&.action-git {
|
||||
color: #F97316;
|
||||
}
|
||||
|
||||
&.action-run {
|
||||
color: #10B981;
|
||||
}
|
||||
|
||||
&.action-edit {
|
||||
color: ${(props) => props.theme.text};
|
||||
}
|
||||
@@ -257,10 +144,6 @@ const StyledWrapper = styled.div`
|
||||
color: #3B82F6;
|
||||
}
|
||||
|
||||
&.action-settings {
|
||||
color: ${(props) => props.theme.text};
|
||||
}
|
||||
|
||||
&.action-delete {
|
||||
color: #EF4444;
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { IconBox, IconTrash, IconEdit, IconShare } from '@tabler/icons';
|
||||
import { loadWorkspaceCollections, removeCollectionFromWorkspaceAction, importCollectionInWorkspace } from 'providers/ReduxStore/slices/workspaces/actions';
|
||||
import { removeCollectionFromWorkspaceAction, importCollectionInWorkspace } from 'providers/ReduxStore/slices/workspaces/actions';
|
||||
import { addTab } from 'providers/ReduxStore/slices/tabs';
|
||||
import { hideHomePage } from 'providers/ReduxStore/slices/app';
|
||||
import { uuid } from 'utils/common';
|
||||
import toast from 'react-hot-toast';
|
||||
import Modal from 'components/Modal';
|
||||
import CreateCollection from 'components/Sidebar/CreateCollection';
|
||||
@@ -25,12 +24,6 @@ const WorkspaceCollections = ({ workspace, onImportCollection }) => {
|
||||
const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false);
|
||||
const [importCollectionModalOpen, setImportCollectionModalOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace && workspace.uid) {
|
||||
dispatch(loadWorkspaceCollections(workspace.uid));
|
||||
}
|
||||
}, [workspace?.uid, collections.length, dispatch]);
|
||||
|
||||
const handleImportCollection = ({ rawData, type }) => {
|
||||
if (onImportCollection) {
|
||||
onImportCollection();
|
||||
@@ -199,9 +192,6 @@ const WorkspaceCollections = ({ workspace, onImportCollection }) => {
|
||||
{createCollectionModalOpen && (
|
||||
<CreateCollection
|
||||
onClose={() => setCreateCollectionModalOpen(false)}
|
||||
workspaceUid={workspace.uid}
|
||||
defaultLocation={`${workspace.pathname}/collections`}
|
||||
hideLocationInput={true}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { IconCategory, IconPlus, IconFolders, IconFileImport, IconDots, IconEdit, IconX, IconCheck, IconFolder } from '@tabler/icons';
|
||||
import { loadWorkspaceCollections, importCollectionInWorkspace, renameWorkspaceAction } from 'providers/ReduxStore/slices/workspaces/actions';
|
||||
import { importCollectionInWorkspace, renameWorkspaceAction } from 'providers/ReduxStore/slices/workspaces/actions';
|
||||
import { showInFolder, openCollection } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import toast from 'react-hot-toast';
|
||||
import CreateCollection from 'components/Sidebar/CreateCollection';
|
||||
@@ -13,7 +13,7 @@ import WorkspaceEnvironments from './WorkspaceEnvironments';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import Dropdown from 'components/Dropdown';
|
||||
|
||||
const WorkspaceOverview = () => {
|
||||
const WorkspaceHome = () => {
|
||||
const dispatch = useDispatch();
|
||||
const { workspaces, activeWorkspaceUid } = useSelector((state) => state.workspaces);
|
||||
const [activeTab, setActiveTab] = useState('collections');
|
||||
@@ -32,12 +32,6 @@ const WorkspaceOverview = () => {
|
||||
|
||||
const activeWorkspace = workspaces.find((w) => w.uid === activeWorkspaceUid);
|
||||
|
||||
useEffect(() => {
|
||||
if (activeWorkspaceUid && activeWorkspace) {
|
||||
dispatch(loadWorkspaceCollections(activeWorkspaceUid));
|
||||
}
|
||||
}, [activeWorkspaceUid, dispatch, activeWorkspace]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isRenamingWorkspace) return;
|
||||
|
||||
@@ -214,9 +208,6 @@ const WorkspaceOverview = () => {
|
||||
{createCollectionModalOpen && (
|
||||
<CreateCollection
|
||||
onClose={() => setCreateCollectionModalOpen(false)}
|
||||
workspaceUid={activeWorkspace.uid}
|
||||
defaultLocation={`${activeWorkspace.pathname}/collections`}
|
||||
hideLocationInput={true}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -357,4 +348,4 @@ const WorkspaceOverview = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default WorkspaceOverview;
|
||||
export default WorkspaceHome;
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import WorkspaceOverview from 'components/WorkspaceOverview';
|
||||
import WorkspaceHome from 'components/WorkspaceHome';
|
||||
import RequestTabs from 'components/RequestTabs';
|
||||
import RequestTabPanel from 'components/RequestTabPanel';
|
||||
import Sidebar from 'components/Sidebar';
|
||||
@@ -112,7 +112,7 @@ export default function Main() {
|
||||
<Sidebar />
|
||||
<section className="flex flex-grow flex-col overflow-hidden">
|
||||
{showHomePage ? (
|
||||
<WorkspaceOverview />
|
||||
<WorkspaceHome />
|
||||
) : (
|
||||
<>
|
||||
<RequestTabs />
|
||||
|
||||
@@ -22,8 +22,7 @@ import {
|
||||
streamDataReceived
|
||||
} from 'providers/ReduxStore/slices/collections';
|
||||
import { collectionAddEnvFileEvent, openCollectionEvent, hydrateCollectionWithUiStateSnapshot, mergeAndPersistEnvironment } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import { workspaceOpenedEvent, workspaceConfigUpdatedEvent, loadLastOpenedWorkspaces, switchWorkspace, loadWorkspaceCollections } from 'providers/ReduxStore/slices/workspaces/actions';
|
||||
import { createWorkspace } from 'providers/ReduxStore/slices/workspaces';
|
||||
import { workspaceOpenedEvent, workspaceConfigUpdatedEvent } from 'providers/ReduxStore/slices/workspaces/actions';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { isElectron } from 'utils/common/platform';
|
||||
@@ -92,33 +91,6 @@ const useIpcEvents = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const initializeDefaultWorkspace = async () => {
|
||||
try {
|
||||
const defaultWorkspace = await ipcRenderer.invoke('renderer:get-default-workspace');
|
||||
|
||||
if (defaultWorkspace) {
|
||||
const { workspaceConfig, workspaceUid, workspacePath } = defaultWorkspace;
|
||||
|
||||
dispatch(createWorkspace({
|
||||
uid: workspaceUid,
|
||||
name: workspaceConfig.name || 'Default',
|
||||
type: 'default',
|
||||
pathname: workspacePath,
|
||||
collections: [],
|
||||
docs: workspaceConfig.docs || ''
|
||||
}));
|
||||
|
||||
await dispatch(loadWorkspaceCollections(workspaceUid));
|
||||
dispatch(switchWorkspace(workspaceUid));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading default workspace:', error);
|
||||
}
|
||||
};
|
||||
|
||||
initializeDefaultWorkspace();
|
||||
dispatch(loadLastOpenedWorkspaces());
|
||||
|
||||
ipcRenderer.invoke('renderer:ready');
|
||||
|
||||
const removeCollectionTreeUpdateListener = ipcRenderer.on('main:collection-tree-updated', _collectionTreeUpdated);
|
||||
|
||||
@@ -58,8 +58,7 @@ import {
|
||||
|
||||
import { each } from 'lodash';
|
||||
import { closeAllCollectionTabs, updateResponsePaneScrollPosition } from 'providers/ReduxStore/slices/tabs';
|
||||
import { addCollectionToWorkspace, removeCollectionFromWorkspace } from 'providers/ReduxStore/slices/workspaces';
|
||||
import { loadWorkspaceCollections } from 'providers/ReduxStore/slices/workspaces/actions';
|
||||
import { removeCollectionFromWorkspace } from 'providers/ReduxStore/slices/workspaces';
|
||||
import { resolveRequestFilename } from 'utils/common/platform';
|
||||
import { interpolateUrl, parsePathParams, splitOnFirst } from 'utils/url/index';
|
||||
import { sendCollectionOauth2Request as _sendCollectionOauth2Request } from 'utils/network/index';
|
||||
@@ -2252,21 +2251,14 @@ export const openCollectionEvent = (uid, pathname, brunoConfig) => (dispatch, ge
|
||||
path: pathname
|
||||
};
|
||||
|
||||
// The electron handler will automatically trigger workspace config update
|
||||
// which will cause the app to react and reload collections
|
||||
ipcRenderer
|
||||
.invoke('renderer:add-collection-to-workspace', activeWorkspace.pathname, workspaceCollection)
|
||||
.then(() => {
|
||||
dispatch(addCollectionToWorkspace({
|
||||
workspaceUid: activeWorkspace.uid,
|
||||
collection: workspaceCollection
|
||||
}));
|
||||
dispatch(loadWorkspaceCollections(activeWorkspace.uid, true));
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Failed to add collection to workspace', err);
|
||||
toast.error('Failed to add collection to workspace');
|
||||
});
|
||||
} else {
|
||||
dispatch(loadWorkspaceCollections(activeWorkspace.uid, true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2382,11 +2374,6 @@ export const importCollection = (collection, collectionLocation, options = {}) =
|
||||
};
|
||||
|
||||
await ipcRenderer.invoke('renderer:add-collection-to-workspace', activeWorkspace.pathname, workspaceCollection);
|
||||
|
||||
dispatch(addCollectionToWorkspace({
|
||||
workspaceUid: activeWorkspace.uid,
|
||||
collection: workspaceCollection
|
||||
}));
|
||||
}
|
||||
|
||||
resolve(collectionPath);
|
||||
|
||||
@@ -301,7 +301,7 @@ export const loadLastOpenedWorkspaces = () => {
|
||||
};
|
||||
|
||||
export const workspaceOpenedEvent = (workspacePath, workspaceUid, workspaceConfig) => {
|
||||
return async (dispatch) => {
|
||||
return async (dispatch, getState) => {
|
||||
dispatch(createWorkspace({
|
||||
uid: workspaceUid,
|
||||
pathname: workspacePath,
|
||||
@@ -312,6 +312,14 @@ export const workspaceOpenedEvent = (workspacePath, workspaceUid, workspaceConfi
|
||||
await dispatch(loadWorkspaceCollections(workspaceUid));
|
||||
} catch (error) {
|
||||
}
|
||||
|
||||
// If this is the default workspace or no workspace is active yet, switch to it
|
||||
const state = getState();
|
||||
const activeWorkspaceUid = state.workspaces.activeWorkspaceUid;
|
||||
|
||||
if (!activeWorkspaceUid || workspaceConfig.type === 'default') {
|
||||
dispatch(switchWorkspace(workspaceUid));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -478,11 +486,6 @@ export const importCollectionInWorkspace = (collection, workspaceUid, collection
|
||||
|
||||
await ipcRenderer.invoke('renderer:add-collection-to-workspace', currentWorkspace.pathname, workspaceCollection);
|
||||
|
||||
dispatch(addCollectionToWorkspace({
|
||||
workspaceUid,
|
||||
collection: workspaceCollection
|
||||
}));
|
||||
|
||||
return collectionPath;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -24,6 +24,8 @@ const registerPreferencesIpc = (mainWindow, watcher) => {
|
||||
console.error("Error occured while fetching global environements!");
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
ipcMain.emit('main:renderer-ready', mainWindow);
|
||||
});
|
||||
|
||||
ipcMain.on('main:open-preferences', () => {
|
||||
|
||||
@@ -318,7 +318,13 @@ const registerWorkspaceIpc = (mainWindow, workspaceWatcher) => {
|
||||
ipcMain.handle('renderer:add-collection-to-workspace', async (event, workspacePath, collection) => {
|
||||
try {
|
||||
const normalizedCollection = normalizeCollectionEntry(workspacePath, collection);
|
||||
return await addCollectionToWorkspace(workspacePath, normalizedCollection);
|
||||
const updatedCollections = await addCollectionToWorkspace(workspacePath, normalizedCollection);
|
||||
|
||||
const workspaceConfig = readWorkspaceConfig(workspacePath);
|
||||
const workspaceUid = generateUidBasedOnHash(workspacePath);
|
||||
mainWindow.webContents.send('main:workspace-config-updated', workspacePath, workspaceUid, workspaceConfig);
|
||||
|
||||
return updatedCollections;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
@@ -431,6 +437,66 @@ const registerWorkspaceIpc = (mainWindow, workspaceWatcher) => {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on('main:renderer-ready', async (win) => {
|
||||
try {
|
||||
const defaultResult = await defaultWorkspaceManager.ensureDefaultWorkspaceExists();
|
||||
if (defaultResult) {
|
||||
const { workspacePath, workspaceUid } = defaultResult;
|
||||
const workspaceFilePath = path.join(workspacePath, 'workspace.yml');
|
||||
|
||||
if (fs.existsSync(workspaceFilePath)) {
|
||||
const yamlContent = fs.readFileSync(workspaceFilePath, 'utf8');
|
||||
const workspaceConfig = yaml.load(yamlContent);
|
||||
|
||||
win.webContents.send('main:workspace-opened', workspacePath, workspaceUid, {
|
||||
...workspaceConfig,
|
||||
type: 'default'
|
||||
});
|
||||
|
||||
if (workspaceWatcher) {
|
||||
workspaceWatcher.addWatcher(win, workspacePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const workspaces = lastOpenedWorkspaces.getAll();
|
||||
const invalidWorkspaceUids = [];
|
||||
|
||||
for (const workspace of workspaces) {
|
||||
if (workspace.pathname) {
|
||||
const workspaceYmlPath = path.join(workspace.pathname, 'workspace.yml');
|
||||
|
||||
if (fs.existsSync(workspaceYmlPath)) {
|
||||
try {
|
||||
const workspaceConfig = readWorkspaceConfig(workspace.pathname);
|
||||
validateWorkspaceConfig(workspaceConfig);
|
||||
const workspaceUid = generateUidBasedOnHash(workspace.pathname);
|
||||
|
||||
win.webContents.send('main:workspace-opened', workspace.pathname, workspaceUid, workspaceConfig);
|
||||
|
||||
if (workspaceWatcher) {
|
||||
workspaceWatcher.addWatcher(win, workspace.pathname);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error loading workspace ${workspace.pathname}:`, error);
|
||||
invalidWorkspaceUids.push(workspace.uid);
|
||||
}
|
||||
} else {
|
||||
invalidWorkspaceUids.push(workspace.uid);
|
||||
}
|
||||
} else {
|
||||
invalidWorkspaceUids.push(workspace.uid);
|
||||
}
|
||||
}
|
||||
|
||||
for (const uid of invalidWorkspaceUids) {
|
||||
lastOpenedWorkspaces.remove(uid);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error initializing workspaces:', error);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = registerWorkspaceIpc;
|
||||
|
||||
Reference in New Issue
Block a user