+
+
+ Documentation
-
- {isEditing ? (
- <>
-
-
-
-
+ {hasDocs && !isEditing && (
+
+
+
+ )}
+ {isEditing && (
+
+
+
+ )}
+
+
+
+ {isEditing ? (
+
+
+
+
Save
- >
- ) : (
-
-
- )}
-
-
- {isEditing ? (
-
- ) : (
-
-
- {
- localDocs?.length > 0
- ?
- :
- }
-
- )}
+ ) : hasDocs ? (
+
+
+
+ ) : (
+
+
+
+
+
+ Add documentation to help your team work smoothly.
+
+
You can include:
+
+ Project overview
+ Setup instructions
+ Key workflows
+ Resources & FAQs
+
+
+ Add Documentation
+
+
+ )}
+
);
};
export default WorkspaceDocs;
-
-const workspaceDocumentationPlaceholder = `
-# Welcome to your Workspace Documentation
-
-This is your workspace documentation area where you can document your entire project, team guidelines, and shared resources.
-
-## What to Document Here
-
-### Project Overview
-- Project goals and objectives
-- Architecture overview
-- Key stakeholders and team members
-- Project timeline and milestones
-
-### Development Guidelines
-- Coding standards and conventions
-- Git workflow and branching strategy
-- Code review process
-- Testing guidelines
-
-### API Documentation
-- Authentication methods
-- Base URLs and environments
-- Common headers and parameters
-- Error handling standards
-
-### Team Resources
-- Useful links and references
-- Development environment setup
-- Deployment procedures
-- Troubleshooting guides
-
-## Markdown Support
-
-This documentation supports full Markdown formatting:
-
-- **Bold** and *italic* text
-- \`inline code\` and code blocks
-- Lists and tables
-- [Links](https://usebruno.com) and images
-- Headers and sections
-
-**Tip:** Double-click anywhere in this area to start editing!
-`;
diff --git a/packages/bruno-app/src/components/WorkspaceHome/WorkspaceOverview/CollectionsList/StyledWrapper.js b/packages/bruno-app/src/components/WorkspaceHome/WorkspaceOverview/CollectionsList/StyledWrapper.js
new file mode 100644
index 000000000..f085487ae
--- /dev/null
+++ b/packages/bruno-app/src/components/WorkspaceHome/WorkspaceOverview/CollectionsList/StyledWrapper.js
@@ -0,0 +1,123 @@
+import styled from 'styled-components';
+
+const StyledWrapper = styled.div`
+ flex: 1;
+ overflow-y: auto;
+
+ .collections-list {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ }
+
+ .empty-state {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 32px 20px;
+ text-align: center;
+ }
+
+ .empty-icon {
+ color: ${(props) => props.theme.colors.text.muted};
+ margin-bottom: 12px;
+ }
+
+ .empty-title {
+ font-size: ${(props) => props.theme.font.size.md};
+ font-weight: 500;
+ color: ${(props) => props.theme.text};
+ margin-bottom: 6px;
+ }
+
+ .empty-description {
+ font-size: ${(props) => props.theme.font.size.sm};
+ color: ${(props) => props.theme.colors.text.muted};
+ }
+
+ .collection-card {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 10px 0;
+ background: ${(props) => props.theme.workspace.card.bg};
+ border-bottom: 1px solid ${(props) => props.theme.sidebar.collection.item.hoverBg};
+ cursor: pointer;
+
+ &:last-child {
+ border-bottom: none;
+ }
+ }
+
+ .collection-icon-wrapper {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: ${(props) => props.theme.workspace.accent};
+ flex-shrink: 0;
+ }
+
+ .collection-info {
+ flex: 1;
+ min-width: 0;
+ }
+
+ .collection-header {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ margin-bottom: 1px;
+ }
+
+ .collection-name {
+ font-size: ${(props) => props.theme.font.size.base};
+ color: ${(props) => props.theme.text};
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .collection-path {
+ font-size: ${(props) => props.theme.font.size.xs};
+ color: ${(props) => props.theme.colors.text.muted};
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .collection-menu {
+ flex-shrink: 0;
+ color: ${(props) => props.theme.colors.text.muted};
+ cursor: pointer;
+
+ &:hover {
+ color: ${(props) => props.theme.text};
+ }
+ }
+
+ .collection-dropdown {
+ min-width: 120px;
+ }
+
+ .dropdown-item {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 6px 10px;
+ cursor: pointer;
+ transition: background 0.15s ease;
+ color: ${(props) => props.theme.text};
+ font-size: ${(props) => props.theme.font.size.sm};
+
+ &:hover {
+ background: ${(props) => props.theme.listItem.hoverBg};
+ }
+
+ &.dropdown-item-danger {
+ color: ${(props) => props.theme.colors.text.danger};
+ }
+ }
+`;
+
+export default StyledWrapper;
diff --git a/packages/bruno-app/src/components/WorkspaceHome/WorkspaceOverview/CollectionsList/index.js b/packages/bruno-app/src/components/WorkspaceHome/WorkspaceOverview/CollectionsList/index.js
new file mode 100644
index 000000000..0d228df93
--- /dev/null
+++ b/packages/bruno-app/src/components/WorkspaceHome/WorkspaceOverview/CollectionsList/index.js
@@ -0,0 +1,314 @@
+import React, { useState, useMemo, useRef } from 'react';
+import { useSelector, useDispatch } from 'react-redux';
+import { IconBox, IconTrash, IconEdit, IconShare, IconDots } from '@tabler/icons';
+import { removeCollectionFromWorkspaceAction } from 'providers/ReduxStore/slices/workspaces/actions';
+import { addTab } from 'providers/ReduxStore/slices/tabs';
+import { hideHomePage } from 'providers/ReduxStore/slices/app';
+import { mountCollection } from 'providers/ReduxStore/slices/collections/actions';
+import { normalizePath } from 'utils/common/path';
+import toast from 'react-hot-toast';
+import Modal from 'components/Modal';
+import RenameCollection from 'components/Sidebar/Collections/Collection/RenameCollection';
+import ShareCollection from 'components/ShareCollection';
+import Dropdown from 'components/Dropdown';
+import StyledWrapper from './StyledWrapper';
+
+const CollectionsList = ({ workspace }) => {
+ const dispatch = useDispatch();
+ const { collections } = useSelector((state) => state.collections);
+ const dropdownRefs = useRef({});
+
+ const [collectionToRemove, setCollectionToRemove] = useState(null);
+ const [renameCollectionModalOpen, setRenameCollectionModalOpen] = useState(false);
+ const [shareCollectionModalOpen, setShareCollectionModalOpen] = useState(false);
+ const [selectedCollectionUid, setSelectedCollectionUid] = useState(null);
+
+ const workspaceCollections = useMemo(() => {
+ if (!workspace.collections || workspace.collections.length === 0) {
+ return [];
+ }
+
+ return workspace.collections.map((wc) => {
+ const loadedCollection = collections.find(
+ (c) => normalizePath(c.pathname) === normalizePath(wc.path)
+ );
+
+ if (loadedCollection) {
+ return {
+ ...loadedCollection,
+ isGitBacked: !!wc.remote,
+ gitRemoteUrl: wc.remote
+ };
+ }
+
+ return {
+ uid: `unloaded-${wc.path}`,
+ name: wc.name,
+ pathname: wc.path,
+ items: [],
+ environments: [],
+ isGitBacked: !!wc.remote,
+ isLoaded: false,
+ gitRemoteUrl: wc.remote,
+ git: { gitRootPath: null },
+ brunoConfig: {},
+ root: {
+ request: {
+ headers: [],
+ auth: { mode: 'none' },
+ vars: { req: [], res: [] },
+ script: { req: '', res: '' },
+ tests: ''
+ },
+ docs: ''
+ }
+ };
+ });
+ }, [workspace.collections, collections]);
+
+ const isInternalCollection = (collection) => {
+ if (!workspace.pathname || !collection.pathname) return false;
+ const workspaceCollectionsFolder = normalizePath(`${workspace.pathname}/collections`);
+ const collectionPath = normalizePath(collection.pathname);
+ return collectionPath.startsWith(workspaceCollectionsFolder);
+ };
+
+ const getCollectionWorkspaceInfo = (collection) => {
+ if (Object.prototype.hasOwnProperty.call(collection, 'isGitBacked')) {
+ return {
+ isGitBacked: collection.isGitBacked,
+ gitRemoteUrl: collection.gitRemoteUrl,
+ isLoaded: collection.isLoaded !== false,
+ isInternal: isInternalCollection(collection)
+ };
+ }
+
+ const workspaceCollection = workspace.collections?.find(
+ (wc) => normalizePath(collection.pathname) === normalizePath(wc.path)
+ );
+
+ return {
+ isGitBacked: !!workspaceCollection?.remote,
+ gitRemoteUrl: workspaceCollection?.remote,
+ isLoaded: true,
+ isInternal: isInternalCollection(collection)
+ };
+ };
+
+ const handleOpenCollectionClick = (collection, event) => {
+ if (event.target.closest('.collection-menu')) {
+ return;
+ }
+
+ if (collection.isLoaded === false) {
+ if (collection.isGitBacked) {
+ toast.error(`Collection "${collection.name}" needs to be cloned first`);
+ } else {
+ toast.error(`Collection "${collection.name}" does not exist on disk`);
+ }
+ return;
+ }
+
+ dispatch(
+ mountCollection({
+ collectionUid: collection.uid,
+ collectionPathname: collection.pathname,
+ brunoConfig: collection.brunoConfig
+ })
+ );
+
+ dispatch(hideHomePage());
+
+ dispatch(
+ addTab({
+ uid: collection.uid,
+ collectionUid: collection.uid,
+ type: 'collection-settings'
+ })
+ );
+ };
+
+ const handleRenameCollection = (collection) => {
+ dropdownRefs.current[collection.uid]?.hide();
+ if (collection.isLoaded === false) {
+ toast.error('Cannot rename collections that are not cloned yet');
+ return;
+ }
+ setSelectedCollectionUid(collection.uid);
+ setRenameCollectionModalOpen(true);
+ };
+
+ const handleShareCollection = (collection) => {
+ dropdownRefs.current[collection.uid]?.hide();
+ if (collection.isLoaded === false) {
+ toast.error('Please clone this collection first before sharing it');
+ return;
+ }
+
+ dispatch(
+ mountCollection({
+ collectionUid: collection.uid,
+ collectionPathname: collection.pathname,
+ brunoConfig: collection.brunoConfig
+ })
+ );
+
+ setSelectedCollectionUid(collection.uid);
+ setShareCollectionModalOpen(true);
+ };
+
+ const handleRemoveCollection = (collection) => {
+ dropdownRefs.current[collection.uid]?.hide();
+ setCollectionToRemove(collection);
+ };
+
+ const confirmRemoveCollection = async () => {
+ if (!collectionToRemove) return;
+
+ try {
+ const collectionInfo = getCollectionWorkspaceInfo(collectionToRemove);
+ const isDelete = collectionInfo.isInternal && !collectionInfo.isGitBacked;
+
+ await dispatch(removeCollectionFromWorkspaceAction(workspace.uid, collectionToRemove.pathname));
+
+ if (isDelete) {
+ toast.success(`Deleted "${collectionToRemove.name}" collection`);
+ } else {
+ toast.success(`Removed "${collectionToRemove.name}" from workspace`);
+ }
+
+ setCollectionToRemove(null);
+ } catch (error) {
+ console.error('Error removing collection:', error);
+ toast.error(error.message || 'Failed to remove collection from workspace');
+ }
+ };
+
+ const renderRemoveModal = () => {
+ if (!collectionToRemove) return null;
+
+ const collectionInfo = getCollectionWorkspaceInfo(collectionToRemove);
+ const isDelete = collectionInfo.isInternal && !collectionInfo.isGitBacked;
+
+ return (
+
setCollectionToRemove(null)}
+ handleConfirm={confirmRemoveCollection}
+ confirmText={isDelete ? 'Delete' : 'Remove'}
+ cancelText="Cancel"
+ style="new"
+ >
+
+ Are you sure you want to {isDelete ? 'delete' : 'remove'}{' '}
+ "{collectionToRemove.name}" ?
+
+
+ {isDelete
+ ? 'This will permanently delete the collection files from the workspace collections folder.'
+ : 'This will remove the collection from the workspace. The collection files will not be deleted.'}
+
+
+ );
+ };
+
+ return (
+
+ {renameCollectionModalOpen && selectedCollectionUid && (
+ {
+ setRenameCollectionModalOpen(false);
+ setSelectedCollectionUid(null);
+ }}
+ />
+ )}
+
+ {shareCollectionModalOpen && selectedCollectionUid && (
+ {
+ setShareCollectionModalOpen(false);
+ setSelectedCollectionUid(null);
+ }}
+ />
+ )}
+
+ {renderRemoveModal()}
+
+
+ {workspaceCollections.length === 0 ? (
+
+
+
No collections yet
+
+ Create your first collection or open an existing one to get started.
+
+
+ ) : (
+ workspaceCollections.map((collection, index) => (
+
handleOpenCollectionClick(collection, e)}
+ >
+
+
+
+
+
+
{collection.name}
+
+
{collection.pathname}
+
+
+
(dropdownRefs.current[collection.uid] = ref)}
+ icon={ }
+ >
+
+
{
+ e.stopPropagation();
+ handleRenameCollection(collection);
+ }}
+ >
+
+ Rename
+
+
{
+ e.stopPropagation();
+ handleShareCollection(collection);
+ }}
+ >
+
+ Share
+
+
{
+ e.stopPropagation();
+ handleRemoveCollection(collection);
+ }}
+ >
+
+ Remove
+
+
+
+
+
+ ))
+ )}
+
+
+ );
+};
+
+export default CollectionsList;
diff --git a/packages/bruno-app/src/components/WorkspaceHome/WorkspaceOverview/StyledWrapper.js b/packages/bruno-app/src/components/WorkspaceHome/WorkspaceOverview/StyledWrapper.js
new file mode 100644
index 000000000..f1b1dff6d
--- /dev/null
+++ b/packages/bruno-app/src/components/WorkspaceHome/WorkspaceOverview/StyledWrapper.js
@@ -0,0 +1,92 @@
+import styled from 'styled-components';
+
+const StyledWrapper = styled.div`
+ height: 100%;
+
+ .overview-layout {
+ display: flex;
+ height: 100%;
+ }
+
+ .overview-main {
+ flex: 3;
+ padding: 20px 16px 16px;
+ overflow-y: auto;
+ border-right: 1px solid ${(props) => props.theme.workspace.border};
+ }
+
+ .overview-docs {
+ display: flex;
+ flex: 2;
+ flex-direction: column;
+ overflow: hidden;
+ }
+
+ .stats-row {
+ display: flex;
+ gap: 24px;
+ margin-bottom: 16px;
+ }
+
+ .stat-item {
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ }
+
+ .stat-value {
+ font-size: 22px;
+ font-weight: 600;
+ color: ${(props) => props.theme.text};
+ line-height: 1;
+ }
+
+ .stat-label {
+ font-size: ${(props) => props.theme.font.size.xs};
+ color: ${(props) => props.theme.colors.text.muted};
+ }
+
+ .quick-actions-section {
+ margin-bottom: 16px;
+ }
+
+ .section-title {
+ font-size: ${(props) => props.theme.font.size.sm};
+ font-weight: 500;
+ color: ${(props) => props.theme.colors.text.muted};
+ margin-bottom: 8px;
+ }
+
+ .quick-actions-buttons {
+ display: flex;
+ gap: 8px;
+ }
+
+ .quick-action-btn {
+ display: flex;
+ align-items: center;
+ gap: 5px;
+ padding: 4px 8px;
+ border: 1px solid ${(props) => props.theme.workspace.accent};
+ border-radius: ${(props) => props.theme.border.radius.base};
+ background: transparent;
+ color: ${(props) => props.theme.workspace.accent};
+ font-size: ${(props) => props.theme.font.size.sm};
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.15s ease;
+
+ &:hover {
+ background: ${(props) => props.theme.workspace.accent}14;
+ }
+ }
+
+ .collections-section {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ }
+`;
+
+export default StyledWrapper;
diff --git a/packages/bruno-app/src/components/WorkspaceHome/WorkspaceOverview/index.js b/packages/bruno-app/src/components/WorkspaceHome/WorkspaceOverview/index.js
new file mode 100644
index 000000000..d426f7f97
--- /dev/null
+++ b/packages/bruno-app/src/components/WorkspaceHome/WorkspaceOverview/index.js
@@ -0,0 +1,127 @@
+import React, { useState, useMemo } from 'react';
+import { useSelector, useDispatch } from 'react-redux';
+import { IconPlus, IconFolder, IconFileImport } from '@tabler/icons';
+import { importCollectionInWorkspace } from 'providers/ReduxStore/slices/workspaces/actions';
+import { openCollection } from 'providers/ReduxStore/slices/collections/actions';
+import toast from 'react-hot-toast';
+import CreateCollection from 'components/Sidebar/CreateCollection';
+import ImportCollection from 'components/Sidebar/ImportCollection';
+import CollectionsList from './CollectionsList';
+import WorkspaceDocs from '../WorkspaceDocs';
+import StyledWrapper from './StyledWrapper';
+
+const WorkspaceOverview = ({ workspace }) => {
+ const dispatch = useDispatch();
+ const { collections } = useSelector((state) => state.collections);
+
+ const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false);
+ const [importCollectionModalOpen, setImportCollectionModalOpen] = useState(false);
+
+ const workspaceCollectionsCount = workspace?.collections?.length || 0;
+
+ const workspaceEnvironmentsCount = useMemo(() => {
+ if (!workspace?.collections || !collections) return 0;
+ let count = 0;
+ workspace.collections.forEach((wc) => {
+ const loadedCollection = collections.find((c) => c.pathname === wc.path);
+ if (loadedCollection?.environments) {
+ count += loadedCollection.environments.length;
+ }
+ });
+ return count;
+ }, [workspace?.collections, collections]);
+
+ const handleCreateCollection = async () => {
+ if (!workspace?.pathname) {
+ toast.error('Workspace path not found');
+ return;
+ }
+
+ try {
+ const { ipcRenderer } = window;
+ await ipcRenderer.invoke('renderer:ensure-collections-folder', workspace.pathname);
+ setCreateCollectionModalOpen(true);
+ } catch (error) {
+ console.error('Error ensuring collections folder exists:', error);
+ toast.error('Error preparing workspace for collection creation');
+ }
+ };
+
+ const handleOpenCollection = () => {
+ dispatch(openCollection()).catch((err) => {
+ console.error(err);
+ toast.error('An error occurred while opening the collection');
+ });
+ };
+
+ const handleImportCollection = () => {
+ setImportCollectionModalOpen(true);
+ };
+
+ const handleImportCollectionSubmit = ({ rawData, type }) => {
+ setImportCollectionModalOpen(false);
+ dispatch(importCollectionInWorkspace(rawData, workspace.uid, undefined, type)).catch((err) => {
+ console.error(err);
+ toast.error('An error occurred while importing the collection');
+ });
+ };
+
+ return (
+
+ {createCollectionModalOpen && (
+ setCreateCollectionModalOpen(false)} />
+ )}
+
+ {importCollectionModalOpen && (
+ setImportCollectionModalOpen(false)}
+ handleSubmit={handleImportCollectionSubmit}
+ />
+ )}
+
+
+
+
+
+ {workspaceCollectionsCount}
+ Collections
+
+
+ {workspaceEnvironmentsCount}
+ Environments
+
+
+
+
+
Quick Actions
+
+
+
+ Create Collection
+
+
+
+ Open Collection
+
+
+
+ Import Collection
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default WorkspaceOverview;
diff --git a/packages/bruno-app/src/components/WorkspaceHome/index.js b/packages/bruno-app/src/components/WorkspaceHome/index.js
index 0901f3d8b..ed7340901 100644
--- a/packages/bruno-app/src/components/WorkspaceHome/index.js
+++ b/packages/bruno-app/src/components/WorkspaceHome/index.js
@@ -1,14 +1,11 @@
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 { importCollectionInWorkspace, renameWorkspaceAction } from 'providers/ReduxStore/slices/workspaces/actions';
-import { showInFolder, openCollection } from 'providers/ReduxStore/slices/collections/actions';
+import { IconCategory, IconDots, IconEdit, IconX, IconCheck, IconFolder } from '@tabler/icons';
+import { renameWorkspaceAction } from 'providers/ReduxStore/slices/workspaces/actions';
+import { showInFolder } from 'providers/ReduxStore/slices/collections/actions';
import toast from 'react-hot-toast';
-import CreateCollection from 'components/Sidebar/CreateCollection';
-import ImportCollection from 'components/Sidebar/ImportCollection';
import CloseWorkspace from 'components/Sidebar/SidebarHeader/CloseWorkspace';
-import WorkspaceCollections from './WorkspaceCollections';
-import WorkspaceDocs from './WorkspaceDocs';
+import WorkspaceOverview from './WorkspaceOverview';
import WorkspaceEnvironments from './WorkspaceEnvironments';
import StyledWrapper from './StyledWrapper';
import Dropdown from 'components/Dropdown';
@@ -16,10 +13,7 @@ import Dropdown from 'components/Dropdown';
const WorkspaceHome = () => {
const dispatch = useDispatch();
const { workspaces, activeWorkspaceUid } = useSelector((state) => state.workspaces);
- const [activeTab, setActiveTab] = useState('collections');
-
- const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false);
- const [importCollectionModalOpen, setImportCollectionModalOpen] = useState(false);
+ const [activeTab, setActiveTab] = useState('overview');
const [isRenamingWorkspace, setIsRenamingWorkspace] = useState(false);
const [workspaceNameInput, setWorkspaceNameInput] = useState('');
@@ -51,40 +45,8 @@ const WorkspaceHome = () => {
return null;
}
- const handleCreateCollection = async () => {
- try {
- const { ipcRenderer } = window;
- await ipcRenderer.invoke('renderer:ensure-collections-folder', activeWorkspace.pathname);
- setCreateCollectionModalOpen(true);
- } catch (error) {
- console.error('Error ensuring collections folder exists:', error);
- toast.error('Error preparing workspace for collection creation');
- }
- };
-
- const handleOpenCollection = () => {
- dispatch(openCollection())
- .catch((err) => {
- console.error(err);
- toast.error('An error occurred while opening the collection');
- });
- };
-
- const handleImportCollection = () => {
- setImportCollectionModalOpen(true);
- };
-
- const handleImportCollectionSubmit = ({ rawData, type, environment, repositoryUrl }) => {
- setImportCollectionModalOpen(false);
- dispatch(importCollectionInWorkspace(rawData, activeWorkspace.uid, undefined, type))
- .catch((err) => {
- console.error(err);
- toast.error('An error occurred while importing the collection');
- });
- };
-
- // Workspace menu handlers
const handleRenameWorkspaceClick = () => {
+ dropdownTippyRef.current?.hide();
setIsRenamingWorkspace(true);
setWorkspaceNameInput(activeWorkspace.name);
setWorkspaceNameError('');
@@ -106,11 +68,9 @@ const WorkspaceHome = () => {
const handleShowInFolder = () => {
dropdownTippyRef.current?.hide();
if (activeWorkspace.pathname) {
- dispatch(showInFolder(activeWorkspace.pathname))
- .catch((error) => {
- console.error('Error opening the folder', error);
- toast.error('Error opening the folder');
- });
+ dispatch(showInFolder(activeWorkspace.pathname)).catch((error) => {
+ toast.error('Error opening the folder');
+ });
}
};
@@ -118,15 +78,12 @@ const WorkspaceHome = () => {
if (!name || name.trim() === '') {
return 'Name is required';
}
-
if (name.length < 1) {
return 'Must be at least 1 character';
}
-
if (name.length > 255) {
return 'Must be 255 characters or less';
}
-
return null;
};
@@ -157,9 +114,7 @@ const WorkspaceHome = () => {
};
const handleWorkspaceNameChange = (e) => {
- const value = e.target.value;
- setWorkspaceNameInput(value);
-
+ setWorkspaceNameInput(e.target.value);
if (workspaceNameError) {
setWorkspaceNameError('');
}
@@ -175,119 +130,25 @@ const WorkspaceHome = () => {
}
};
- if (!activeWorkspace) {
- return null;
- }
-
const tabs = [
- {
- id: 'collections',
- label: 'Collections',
- component: (
-
- )
- },
- {
- id: 'environments',
- label: 'Environments',
- component:
- },
- {
- id: 'documentation',
- label: 'Documentation',
- component:
- }
+ { id: 'overview', label: 'Overview' },
+ { id: 'environments', label: 'Environments' }
];
+ const renderTabContent = () => {
+ switch (activeTab) {
+ case 'overview':
+ return
;
+ case 'environments':
+ return
;
+ default:
+ return null;
+ }
+ };
+
return (
-
- {createCollectionModalOpen && (
-
setCreateCollectionModalOpen(false)}
- />
- )}
-
- {importCollectionModalOpen && (
- setImportCollectionModalOpen(false)}
- handleSubmit={handleImportCollectionSubmit}
- />
- )}
-
-
-
-
- {isRenamingWorkspace ? (
-
-
-
- e.preventDefault()}
- title="Save"
- >
-
-
- e.preventDefault()}
- title="Cancel"
- >
-
-
-
-
- ) : (
-
{activeWorkspace.name}
- )}
-
-
- {!isRenamingWorkspace && activeWorkspace.type !== 'default' && (
-
}
- >
-
-
-
- Rename
-
-
-
- Show in Folder
-
-
-
- Close
-
-
-
- )}
-
- {workspaceNameError && isRenamingWorkspace && (
-
{workspaceNameError}
- )}
-
-
+
{closeWorkspaceModalOpen && (
{
/>
)}
-
-
- {tabs.map((tab) => {
- return (
-
setActiveTab(tab.id)}
- className={`flex items-center gap-2 py-2 text-sm border-b-2 transition-colors tab-item ${activeTab === tab.id ? 'active' : ''}`}
- >
- {tab.label}
-
- );
- })}
+
+
+
+
+ {isRenamingWorkspace ? (
+
+
+
+ e.preventDefault()}
+ title="Save"
+ >
+
+
+ e.preventDefault()}
+ title="Cancel"
+ >
+
+
+
+
+ ) : (
+
{activeWorkspace.name}
+ )}
+
+
+ {!isRenamingWorkspace && activeWorkspace.type !== 'default' && (
+
}
+ >
+
+
+
+ Rename
+
+
+
+ Show in Folder
+
+
+
+ Close
+
+
+
+ )}
+
+ {workspaceNameError && isRenamingWorkspace && (
+
{workspaceNameError}
+ )}
- {activeTab === 'collections' && (
-
+
+ {tabs.map((tab) => (
setActiveTab(tab.id)}
>
-
- Create
+ {tab.label}
-
-
- Add
-
-
-
- Import
-
-
- )}
-
+ ))}
+
-
- {tabs.find((tab) => tab.id === activeTab)?.component}
+
{renderTabContent()}
diff --git a/tests/devtools/performance/performance-tab.spec.ts b/tests/devtools/performance/performance-tab.spec.ts
index 8e71f4b17..75719c640 100644
--- a/tests/devtools/performance/performance-tab.spec.ts
+++ b/tests/devtools/performance/performance-tab.spec.ts
@@ -121,7 +121,7 @@ test.describe('DevTools Performance Tab', () => {
await expect(performanceTab).not.toHaveClass(/active/);
// Verify Console tab content is shown
- await expect(page.locator('.tab-content')).toBeVisible();
+ await expect(page.locator('.console-empty')).toBeVisible();
// Switch back to Performance tab
await performanceTab.click();