diff --git a/packages/bruno-app/src/components/Sidebar/Sections/CollectionsSection/index.js b/packages/bruno-app/src/components/Sidebar/Sections/CollectionsSection/index.js index f7d8754a8..43271f249 100644 --- a/packages/bruno-app/src/components/Sidebar/Sections/CollectionsSection/index.js +++ b/packages/bruno-app/src/components/Sidebar/Sections/CollectionsSection/index.js @@ -16,11 +16,13 @@ import { IconTerminal2 } from '@tabler/icons'; -import { importCollection, openCollection, importCollectionFromZip } from 'providers/ReduxStore/slices/collections/actions'; +import { importCollection, openCollection, importCollectionFromZip, newHttpRequest } from 'providers/ReduxStore/slices/collections/actions'; import { sortCollections } from 'providers/ReduxStore/slices/collections/index'; import { savePreferences } from 'providers/ReduxStore/slices/app'; import { normalizePath } from 'utils/common/path'; -import { isScratchCollection } from 'utils/collections'; +import { isScratchCollection, flattenItems, isItemTransientRequest } from 'utils/collections'; +import { sanitizeName } from 'utils/common/regex'; +import filter from 'lodash/filter'; import MenuDropdown from 'ui/MenuDropdown'; import ActionIcon from 'ui/ActionIcon'; @@ -179,6 +181,50 @@ const CollectionsSection = () => { }); }; + const handleStartRequest = () => { + const scratchCollectionUid = activeWorkspace?.scratchCollectionUid; + if (!scratchCollectionUid) { + toast.error('Unable to create request'); + return; + } + + const scratchCollection = collections.find((c) => c.uid === scratchCollectionUid); + if (!scratchCollection) { + toast.error('Unable to create request'); + return; + } + + const allItems = flattenItems(scratchCollection.items || []); + const transientRequests = filter(allItems, (item) => isItemTransientRequest(item)); + let maxNumber = 0; + transientRequests.forEach((item) => { + const match = item.name?.match(/^Untitled (\d+)$/); + if (match) { + const number = parseInt(match[1], 10); + if (number > maxNumber) { + maxNumber = number; + } + } + }); + const requestName = `Untitled ${maxNumber + 1}`; + const filename = sanitizeName(requestName); + + dispatch( + newHttpRequest({ + requestName, + filename, + requestType: 'http-request', + requestUrl: '', + requestMethod: 'GET', + collectionUid: scratchCollectionUid, + itemUid: null, + isTransient: true + }) + ).catch((err) => { + toast.error('An error occurred while creating the request'); + }); + }; + const addDropdownItems = [ { id: 'create', @@ -289,6 +335,10 @@ const CollectionsSection = () => { handleDismissWelcomeModal(); handleOpenCollection(); }} + onStartRequest={() => { + handleDismissWelcomeModal(); + handleStartRequest(); + }} /> )} {createCollectionModalOpen && ( diff --git a/packages/bruno-app/src/components/WelcomeModal/GetStartedStep/StyledWrapper.js b/packages/bruno-app/src/components/WelcomeModal/GetStartedStep/StyledWrapper.js index 955c1f254..c5ad8396b 100644 --- a/packages/bruno-app/src/components/WelcomeModal/GetStartedStep/StyledWrapper.js +++ b/packages/bruno-app/src/components/WelcomeModal/GetStartedStep/StyledWrapper.js @@ -76,8 +76,12 @@ const StyledWrapper = styled.div` transition: all 0.15s ease; &:hover { - background: ${(props) => props.theme.sidebar.collection.item.hoverBg}; - border-color: ${(props) => props.theme.border.border1}; + border-color: ${(props) => props.theme.primary.subtle}; + background: ${(props) => rgba(props.theme.primary.solid, 0.06)}; + } + + &:active { + transform: scale(0.98); } .secondary-icon { diff --git a/packages/bruno-app/src/components/WelcomeModal/GetStartedStep/index.js b/packages/bruno-app/src/components/WelcomeModal/GetStartedStep/index.js index 2209ba076..d96438a9e 100644 --- a/packages/bruno-app/src/components/WelcomeModal/GetStartedStep/index.js +++ b/packages/bruno-app/src/components/WelcomeModal/GetStartedStep/index.js @@ -1,8 +1,8 @@ import React from 'react'; -import { IconPlus, IconDownload, IconFileImport } from '@tabler/icons'; +import { IconPlus, IconDownload, IconFileImport, IconSend } from '@tabler/icons'; import StyledWrapper from './StyledWrapper'; -const GetStartedStep = ({ onCreateCollection, onImportCollection, onOpenCollection }) => ( +const GetStartedStep = ({ onCreateCollection, onImportCollection, onOpenCollection, onStartRequest }) => (
Your first collection
You're all set! What's next?
@@ -38,6 +38,15 @@ const GetStartedStep = ({ onCreateCollection, onImportCollection, onOpenCollecti
Open a Bruno collection from your filesystem
+
); diff --git a/packages/bruno-app/src/components/WelcomeModal/StorageStep/index.js b/packages/bruno-app/src/components/WelcomeModal/StorageStep/index.js index 70d905144..877d7024e 100644 --- a/packages/bruno-app/src/components/WelcomeModal/StorageStep/index.js +++ b/packages/bruno-app/src/components/WelcomeModal/StorageStep/index.js @@ -6,7 +6,7 @@ const StorageStep = ({ collectionLocation, onBrowse }) => (
Storage
Where should we store your collections?
- Bruno saves collections as plain files on your filesystem — perfect for version control with Git. + Bruno saves collections as plain files on your filesystem, perfect for version control with Git.
@@ -31,7 +31,7 @@ const StorageStep = ({ collectionLocation, onBrowse }) => (
- Each collection gets its own folder inside this directory. You can change this per-collection later. + Each collection and workspace gets its own folder inside this directory. You can change this later.
); diff --git a/packages/bruno-app/src/components/WelcomeModal/WelcomeStep/index.js b/packages/bruno-app/src/components/WelcomeModal/WelcomeStep/index.js index aee966c7b..5edcc11a1 100644 --- a/packages/bruno-app/src/components/WelcomeModal/WelcomeStep/index.js +++ b/packages/bruno-app/src/components/WelcomeModal/WelcomeStep/index.js @@ -10,8 +10,8 @@ import StyledWrapper from './StyledWrapper'; const highlights = [ { icon: IconFolderTabler, - title: 'Filesystem-first', - desc: 'Collections are plain files on your disk. No cloud sync, no proprietary lock-in. Your data stays yours.' + title: 'Filesystem only', + desc: 'Collections are plain files on your disk. No cloud sync, no proprietary lock-in.' }, { icon: IconGitFork, @@ -21,12 +21,12 @@ const highlights = [ { icon: IconLock, title: 'Privacy-focused', - desc: 'No accounts required. No telemetry. Bruno works entirely offline — your API keys never leave your machine.' + desc: 'No account, no login. Bruno works entirely offline, your API keys never leave your machine.' }, { icon: IconRocket, title: 'Fast and lightweight', - desc: 'Built to be snappy. No bloated runtimes — just a fast, focused tool for exploring and testing APIs.' + desc: 'Built to be snappy. No bloated runtimes, just a fast, focused tool for exploring and testing APIs.' } ]; diff --git a/packages/bruno-app/src/components/WelcomeModal/index.js b/packages/bruno-app/src/components/WelcomeModal/index.js index a880688bb..7feedc509 100644 --- a/packages/bruno-app/src/components/WelcomeModal/index.js +++ b/packages/bruno-app/src/components/WelcomeModal/index.js @@ -15,7 +15,7 @@ import StyledWrapper from './StyledWrapper'; const TOTAL_STEPS = 4; -const WelcomeModal = ({ onDismiss, onImportCollection, onCreateCollection, onOpenCollection }) => { +const WelcomeModal = ({ onDismiss, onImportCollection, onCreateCollection, onOpenCollection, onStartRequest }) => { const dispatch = useDispatch(); const preferences = useSelector((state) => state.app.preferences); const defaultLocation = get(preferences, 'general.defaultLocation', ''); @@ -93,6 +93,7 @@ const WelcomeModal = ({ onDismiss, onImportCollection, onCreateCollection, onOpe onCreateCollection={handleActionAndDismiss(onCreateCollection)} onImportCollection={handleActionAndDismiss(onImportCollection)} onOpenCollection={handleActionAndDismiss(onOpenCollection)} + onStartRequest={handleActionAndDismiss(onStartRequest)} /> ];