-
+
Report Issues
diff --git a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/AddWorkspace/index.js b/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/AddWorkspace/index.js
deleted file mode 100644
index 02934b1f..00000000
--- a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/AddWorkspace/index.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import React, { useEffect, useRef } from 'react';
-import Portal from 'components/Portal/index';
-import Modal from 'components/Modal/index';
-import { useFormik } from 'formik';
-import { addWorkspace } from 'providers/ReduxStore/slices/workspaces/actions';
-import * as Yup from 'yup';
-import { useDispatch } from 'react-redux';
-import toast from 'react-hot-toast';
-
-const AddWorkspace = ({ onClose }) => {
- const dispatch = useDispatch();
- const inputRef = useRef();
- const formik = useFormik({
- enableReinitialize: true,
- initialValues: {
- name: ''
- },
- validationSchema: Yup.object({
- name: Yup.string().min(1, 'must be atleast 1 characters').max(30, 'must be 30 characters or less').required('name is required')
- }),
- onSubmit: (values) => {
- dispatch(addWorkspace(values.name))
- .then(() => {
- toast.success('Workspace created!');
- onClose();
- })
- .catch(() => toast.error('An error occured while creating the workspace'));
- }
- });
-
- useEffect(() => {
- if (inputRef && inputRef.current) {
- inputRef.current.focus();
- }
- }, [inputRef]);
-
- const onSubmit = () => {
- formik.handleSubmit();
- };
-
- return (
-
-
-
-
-
- );
-};
-
-export default AddWorkspace;
diff --git a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/DeleteWorkspace/StyledWrapper.js b/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/DeleteWorkspace/StyledWrapper.js
deleted file mode 100644
index 48b87421..00000000
--- a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/DeleteWorkspace/StyledWrapper.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import styled from 'styled-components';
-
-const Wrapper = styled.div`
- button.submit {
- color: white;
- background-color: var(--color-background-danger) !important;
- border: inherit !important;
-
- &:hover {
- border: inherit !important;
- }
- }
-`;
-
-export default Wrapper;
diff --git a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/DeleteWorkspace/index.js b/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/DeleteWorkspace/index.js
deleted file mode 100644
index 3e696dbc..00000000
--- a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/DeleteWorkspace/index.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import React from 'react';
-import Portal from 'components/Portal/index';
-import Modal from 'components/Modal/index';
-import { deleteWorkspace } from 'providers/ReduxStore/slices/workspaces/actions';
-import { useDispatch } from 'react-redux';
-import toast from 'react-hot-toast';
-import { toastError } from 'utils/common/error';
-import StyledWrapper from './StyledWrapper';
-
-const DeleteWorkspace = ({ onClose, workspace }) => {
- const dispatch = useDispatch();
- const onConfirm = () => {
- dispatch(deleteWorkspace(workspace.uid))
- .then(() => {
- toast.success('Workspace deleted!');
- onClose();
- })
- .catch(toastError);
- };
-
- return (
-
-
-
- Are you sure you want to delete {workspace.name} ?
-
-
-
- );
-};
-
-export default DeleteWorkspace;
diff --git a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/EditWorkspace/index.js b/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/EditWorkspace/index.js
deleted file mode 100644
index 9e0a07a1..00000000
--- a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/EditWorkspace/index.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import React, { useEffect, useRef } from 'react';
-import Portal from 'components/Portal/index';
-import Modal from 'components/Modal/index';
-import { useFormik } from 'formik';
-import { renameWorkspace } from 'providers/ReduxStore/slices/workspaces/actions';
-import * as Yup from 'yup';
-import { useDispatch } from 'react-redux';
-import toast from 'react-hot-toast';
-
-const EditWorkspace = ({ onClose, workspace }) => {
- const dispatch = useDispatch();
- const inputRef = useRef();
- const formik = useFormik({
- enableReinitialize: true,
- initialValues: {
- name: workspace.name
- },
- validationSchema: Yup.object({
- name: Yup.string().min(1, 'must be atleast 1 characters').max(30, 'must be 30 characters or less').required('name is required')
- }),
- onSubmit: (values) => {
- dispatch(renameWorkspace(values.name, workspace.uid))
- .then(() => {
- toast.success('Workspace renamed!');
- onClose();
- })
- .catch(() => toast.error('An error occured while renaming the workspace'));
- }
- });
-
- useEffect(() => {
- if (inputRef && inputRef.current) {
- inputRef.current.focus();
- }
- }, [inputRef]);
-
- const onSubmit = () => {
- formik.handleSubmit();
- };
-
- return (
-
-
-
-
-
- );
-};
-
-export default EditWorkspace;
diff --git a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/WorkspaceItem/StyledWrapper.js b/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/WorkspaceItem/StyledWrapper.js
deleted file mode 100644
index 2c99eeb5..00000000
--- a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/WorkspaceItem/StyledWrapper.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import styled from 'styled-components';
-
-const Wrapper = styled.div`
- div {
- padding: 4px 6px;
- padding-left: 8px;
- display: flex;
- align-items: center;
- border-radius: 3px;
- }
-
- div:hover {
- background-color: ${(props) => props.theme.plainGrid.hoverBg};
- }
-`;
-
-export default Wrapper;
diff --git a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/WorkspaceItem/index.js b/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/WorkspaceItem/index.js
deleted file mode 100644
index 25728bd7..00000000
--- a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/WorkspaceItem/index.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import React, { useState } from 'react';
-import EditWorkspace from '../EditWorkspace';
-import DeleteWorkspace from '../DeleteWorkspace';
-import { IconEdit, IconTrash } from '@tabler/icons';
-import StyledWrapper from './StyledWrapper';
-
-const WorkspaceItem = ({ workspace }) => {
- const [openEditModal, setOpenEditModal] = useState(false);
- const [openDeleteModal, setOpenDeleteModal] = useState(false);
-
- return (
-
-
-
{workspace.name}
-
- setOpenEditModal(true)} />
- setOpenDeleteModal(true)} />
-
- {openEditModal &&
setOpenEditModal(false)} workspace={workspace} />}
- {openDeleteModal && setOpenDeleteModal(false)} workspace={workspace} />}
-
-
- );
-};
-
-export default WorkspaceItem;
diff --git a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/index.js b/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/index.js
deleted file mode 100644
index 17452d08..00000000
--- a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/index.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import Modal from 'components/Modal/index';
-import React, { useState } from 'react';
-import { useSelector } from 'react-redux';
-import WorkspaceItem from './WorkspaceItem/index';
-import AddWorkspace from './AddWorkspace';
-
-const WorkspaceConfigurer = ({ onClose }) => {
- const { workspaces } = useSelector((state) => state.workspaces);
- const [openAddModal, setOpenAddModal] = useState(false);
-
- return (
-
setOpenAddModal(true)} handleCancel={onClose} hideCancel={true}>
- {workspaces && workspaces.length && workspaces.map((workspace) => )}
- {openAddModal && setOpenAddModal(false)} />}
-
- );
-};
-
-export default WorkspaceConfigurer;
diff --git a/packages/bruno-app/src/components/Workspaces/WorkspaceSelectModal/StyledWrapper.js b/packages/bruno-app/src/components/Workspaces/WorkspaceSelectModal/StyledWrapper.js
deleted file mode 100644
index b776b1ee..00000000
--- a/packages/bruno-app/src/components/Workspaces/WorkspaceSelectModal/StyledWrapper.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import styled from 'styled-components';
-
-const StyledWrapper = styled.div`
- div.workspace {
- padding: 4px 6px;
- padding-left: 8px;
- display: flex;
- align-items: center;
- border-radius: 3px;
- cursor: pointer;
-
- &:hover {
- background-color: #f4f4f4;
- }
- }
-`;
-
-export default StyledWrapper;
diff --git a/packages/bruno-app/src/components/Workspaces/WorkspaceSelectModal/index.js b/packages/bruno-app/src/components/Workspaces/WorkspaceSelectModal/index.js
deleted file mode 100644
index 42e427c3..00000000
--- a/packages/bruno-app/src/components/Workspaces/WorkspaceSelectModal/index.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import React from 'react';
-import Modal from 'components/Modal/index';
-import { IconBox } from '@tabler/icons';
-import { useSelector } from 'react-redux';
-import StyledWrapper from './StyledWrapper';
-
-const WorkspaceSelectModal = ({ onClose, onSelect, title }) => {
- const { workspaces } = useSelector((state) => state.workspaces);
-
- return (
-
-
-
-
-
- );
-};
-
-export default WorkspaceSelectModal;
diff --git a/packages/bruno-app/src/components/Workspaces/WorkspaceSelector/index.js b/packages/bruno-app/src/components/Workspaces/WorkspaceSelector/index.js
deleted file mode 100644
index a5262466..00000000
--- a/packages/bruno-app/src/components/Workspaces/WorkspaceSelector/index.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import React, { useRef, forwardRef, useState, useEffect } from 'react';
-import Dropdown from 'components/Dropdown';
-import { IconCaretDown, IconBox, IconSwitch3, IconSettings } from '@tabler/icons';
-import WorkspaceConfigurer from '../WorkspaceConfigurer';
-import WorkspaceSelectModal from '../WorkspaceSelectModal';
-import { useDispatch, useSelector } from 'react-redux';
-import { selectWorkspace } from 'providers/ReduxStore/slices/workspaces';
-import StyledWrapper from './StyledWrapper';
-
-const WorkspaceSelector = () => {
- const dropdownTippyRef = useRef();
- const [openWorkspacesModal, setOpenWorkspacesModal] = useState(false);
- const [openSwitchWorkspaceModal, setOpenSwitchWorkspaceModal] = useState(false);
- const [activeWorkspace, setActiveWorkspace] = useState({});
- const dispatch = useDispatch();
-
- const { workspaces, activeWorkspaceUid } = useSelector((state) => state.workspaces);
-
- useEffect(() => {
- setActiveWorkspace(workspaces.find((workspace) => workspace.uid === activeWorkspaceUid));
- }, [activeWorkspaceUid, workspaces]);
-
- const Icon = forwardRef((props, ref) => {
- return (
-
-
-
-
-
- {activeWorkspace ? activeWorkspace.name : ''}
-
-
-
- );
- });
-
- const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref);
-
- const handleSelectWorkspace = (workspaceUid) => {
- dispatch(selectWorkspace({ workspaceUid: workspaceUid }));
- setOpenSwitchWorkspaceModal(false);
- };
-
- return (
-
- {openWorkspacesModal && setOpenWorkspacesModal(false)} />}
- {openSwitchWorkspaceModal && setOpenSwitchWorkspaceModal(false)} />}
-
-
-
} placement="bottom-end">
-
setOpenSwitchWorkspaceModal(true)}>
-
-
-
-
Switch Workspace
-
-
-
setOpenWorkspacesModal(true)}>
-
-
-
-
Configure Workspaces
-
-
-
-
- );
-};
-
-export default WorkspaceSelector;
diff --git a/packages/bruno-app/src/pageComponents/Collections/CollectionItem/index.js b/packages/bruno-app/src/pageComponents/Collections/CollectionItem/index.js
deleted file mode 100644
index f6b54b20..00000000
--- a/packages/bruno-app/src/pageComponents/Collections/CollectionItem/index.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import React, { useState } from 'react';
-import { IconEdit, IconTrash } from '@tabler/icons';
-import RenameCollection from 'components/Sidebar/Collections/Collection/RenameCollection';
-import DeleteCollection from 'components/Sidebar/Collections/Collection/DeleteCollection';
-
-export default function CollectionItem({ collection }) {
- const [showRenameCollectionModal, setShowRenameCollectionModal] = useState(false);
- const [showDeleteCollectionModal, setShowDeleteCollectionModal] = useState(false);
-
- return (
- <>
- {showRenameCollectionModal &&
setShowRenameCollectionModal(false)} />}
- {showDeleteCollectionModal && setShowDeleteCollectionModal(false)} />}
-
-
- {collection.name}
-
-
- setShowRenameCollectionModal(true)} />
- setShowDeleteCollectionModal(true)} />
-
-
- >
- );
-}
diff --git a/packages/bruno-app/src/pageComponents/Collections/StyledWrapper.js b/packages/bruno-app/src/pageComponents/Collections/StyledWrapper.js
deleted file mode 100644
index 0238fb7c..00000000
--- a/packages/bruno-app/src/pageComponents/Collections/StyledWrapper.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import styled from 'styled-components';
-
-const Wrapper = styled.div`
- .heading {
- display: inline-flex;
- font-weight: 600;
- margin-top: 1.5rem;
- padding: 6px 0px;
- border-bottom: 2px solid !important;
- }
-
- .collection-list {
- min-width: 500px;
-
- .collection-list-item {
- padding: 4px 0px;
- border-radius: 3px;
-
- &:hover {
- background-color: ${(props) => props.theme.plainGrid.hoverBg};
- margin-left: -8px;
- margin-right: -8px;
- padding-left: 8px;
- padding-right: 8px;
- }
- }
- }
-`;
-
-export default Wrapper;
diff --git a/packages/bruno-app/src/pageComponents/Collections/index.js b/packages/bruno-app/src/pageComponents/Collections/index.js
deleted file mode 100644
index 68463c5e..00000000
--- a/packages/bruno-app/src/pageComponents/Collections/index.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import React from 'react';
-import filter from 'lodash/filter';
-import { useSelector } from 'react-redux';
-import CollectionItem from './CollectionItem';
-import StyledWrapper from './StyledWrapper';
-import { isLocalCollection } from 'utils/collections';
-
-export default function Collections() {
- const collections = useSelector((state) => state.collections.collections);
- const collectionsToDisplay = filter(collections, (c) => !isLocalCollection(c));
-
- return (
-
- Collections
-
-
- {collectionsToDisplay && collectionsToDisplay.length ? (
- collectionsToDisplay.map((collection) => {
- return
;
- })
- ) : (
-
No collections found
- )}
-
-
- );
-}
diff --git a/packages/bruno-app/src/pageComponents/Login/StyledWrapper.js b/packages/bruno-app/src/pageComponents/Login/StyledWrapper.js
deleted file mode 100644
index 140e8237..00000000
--- a/packages/bruno-app/src/pageComponents/Login/StyledWrapper.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import styled from 'styled-components';
-
-const Wrapper = styled.div`
- display: flex;
- flex-direction: column;
- width: 100%;
- height: 100%;
- min-height: 100vh;
-
- .form-container {
- max-width: 350px;
- border-radius: 4px;
- border: 1px #ddd solid;
-
- button.continue-btn {
- font-size: 16px;
- padding-top: 8x;
- padding-bottom: 8px;
- min-height: 38px;
- align-items: center;
- color: #212529;
- background: #e2e6ea;
- border: solid 1px #dae0e5;
- }
-
- .field-error {
- font-size: 0.875rem;
- }
-
- a {
- color: ${(props) => props.theme.textLink};
- }
-
- .error-msg {
- font-size: 15px;
- color: rgb(192 69 8);
- }
- }
-`;
-
-export default Wrapper;
diff --git a/packages/bruno-app/src/pageComponents/Login/index.js b/packages/bruno-app/src/pageComponents/Login/index.js
deleted file mode 100644
index 2b56a7bd..00000000
--- a/packages/bruno-app/src/pageComponents/Login/index.js
+++ /dev/null
@@ -1,243 +0,0 @@
-import React, { useState } from 'react';
-import * as Yup from 'yup';
-import Link from 'next/link';
-import { useRouter } from 'next/router';
-import { useAuth } from 'providers/Auth';
-import AuthApi from 'api/auth';
-import { useFormik } from 'formik';
-import StyledWrapper from './StyledWrapper';
-
-const Login = () => {
- const router = useRouter();
- const [authState, authDispatch] = useAuth();
-
- const { currentUser } = authState;
-
- const [loggingIn, setLoggingIn] = useState(false);
- const [loginError, setLoginError] = useState(false);
-
- const formik = useFormik({
- initialValues: {
- email: '',
- password: ''
- },
- validationSchema: Yup.object({
- email: Yup.string().required('Email is required'),
- password: Yup.string().required('Password is required')
- }),
- onSubmit: (values, { resetForm }) => {
- setLoggingIn(true);
- AuthApi.login({
- email: values.email,
- password: values.password
- })
- .then((response) => {
- authDispatch({
- type: 'LOGIN_SUCCESS',
- user: response.data
- });
- })
- .catch((error) => {
- setLoggingIn(false);
- setLoginError(true);
- });
- }
- });
-
- if (authState.isLoading) {
- return null;
- }
-
- if (currentUser) {
- router.push('/');
- return null;
- }
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- bruno
-
-
Opensource IDE for exploring and testing api's.
-
-
-
- );
-};
-
-export default Login;
diff --git a/packages/bruno-app/src/pageComponents/SignUp/StyledWrapper.js b/packages/bruno-app/src/pageComponents/SignUp/StyledWrapper.js
deleted file mode 100644
index 36d1cb2b..00000000
--- a/packages/bruno-app/src/pageComponents/SignUp/StyledWrapper.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import styled from 'styled-components';
-
-const Wrapper = styled.div`
- display: flex;
- flex-direction: column;
- width: 100%;
- height: 100%;
- min-height: 100vh;
-
- .form-container {
- max-width: 350px;
- border-radius: 4px;
- border: 1px #ddd solid;
-
- button.continue-btn {
- font-size: 16px;
- padding-top: 8px;
- padding-bottom: 8px;
- min-height: 38px;
- align-items: center;
- color: #212529;
- background: #e2e6ea;
- border: solid 1px #dae0e5;
- }
-
- .field-error {
- font-size: 0.875rem;
- }
-
- a {
- color: ${(props) => props.theme.textLink};
- }
-
- .or {
- display: inline-block;
- position: relative;
- top: -14px;
- background: white;
- padding-inline: 10px;
- }
-
- .error-msg {
- font-size: 15px;
- color: rgb(192 69 8);
- }
- }
-`;
-
-export default Wrapper;
diff --git a/packages/bruno-app/src/pageComponents/SignUp/index.js b/packages/bruno-app/src/pageComponents/SignUp/index.js
deleted file mode 100644
index a054725c..00000000
--- a/packages/bruno-app/src/pageComponents/SignUp/index.js
+++ /dev/null
@@ -1,273 +0,0 @@
-import React, { useState } from 'react';
-import Link from 'next/link';
-import StyledWrapper from './StyledWrapper';
-import AuthApi from 'api/auth';
-import { useFormik } from 'formik';
-import * as Yup from 'yup';
-import { useRouter } from 'next/router';
-import { useAuth } from 'providers/Auth';
-
-const SignUp = () => {
- const router = useRouter();
- const [authState, authDispatch] = useAuth();
- const [errorSigningUp, setErrorSigningUp] = useState(false);
- const [errorMsg, setErrorMsg] = useState('');
- const [signingUp, setSigningUp] = useState(false);
-
- const { currentUser } = authState;
-
- const formik = useFormik({
- initialValues: {
- name: '',
- email: '',
- password: ''
- },
- validationSchema: Yup.object({
- name: Yup.string().min(3, 'Must be atleast 3 characters').max(50, 'Must be 50 characters or less').required('Required'),
- email: Yup.string().email('Invalid email address').required('Required'),
- password: Yup.string().min(8, 'Must be atleast 8 characters').max(50, 'Must be 50 characters or less').required('Required')
- }),
- onSubmit: (values, { resetForm }) => {
- setSigningUp(true);
- AuthApi.signup({
- name: values.name,
- email: values.email,
- password: values.password
- })
- .then((response) => {
- authDispatch({
- type: 'LOGIN_SUCCESS',
- user: response.data
- });
- })
- .catch((error) => {
- setSigningUp(false);
- setErrorSigningUp(true);
- setErrorMsg(error.message || 'An error occured during signup');
- });
- setSigningUp(false);
- }
- });
-
- if (authState.isLoading) {
- return null;
- }
-
- if (currentUser) {
- router.push('/');
- return null;
- }
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- bruno
-
-
Opensource IDE for exploring and testing api's.
-
-
-
-
- );
-};
-
-export default SignUp;
diff --git a/packages/bruno-app/src/providers/App/index.js b/packages/bruno-app/src/providers/App/index.js
index e7cf91a5..99e4badb 100644
--- a/packages/bruno-app/src/providers/App/index.js
+++ b/packages/bruno-app/src/providers/App/index.js
@@ -1,7 +1,6 @@
import React, { useEffect } from 'react';
-import useIdb from './useIdb';
import useTelemetry from './useTelemetry';
-import useLocalCollectionTreeSync from './useLocalCollectionTreeSync';
+import useCollectionTreeSync from './useCollectionTreeSync';
import { useDispatch } from 'react-redux';
import { refreshScreenWidth } from 'providers/ReduxStore/slices/app';
import StyledWrapper from './StyledWrapper';
@@ -9,9 +8,8 @@ import StyledWrapper from './StyledWrapper';
export const AppContext = React.createContext();
export const AppProvider = (props) => {
- useIdb();
useTelemetry();
- useLocalCollectionTreeSync();
+ useCollectionTreeSync();
const dispatch = useDispatch();
diff --git a/packages/bruno-app/src/providers/App/useLocalCollectionTreeSync.js b/packages/bruno-app/src/providers/App/useCollectionTreeSync.js
similarity index 67%
rename from packages/bruno-app/src/providers/App/useLocalCollectionTreeSync.js
rename to packages/bruno-app/src/providers/App/useCollectionTreeSync.js
index 86407b3b..93b29aaa 100644
--- a/packages/bruno-app/src/providers/App/useLocalCollectionTreeSync.js
+++ b/packages/bruno-app/src/providers/App/useCollectionTreeSync.js
@@ -1,17 +1,18 @@
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import {
- localCollectionAddDirectoryEvent,
- localCollectionAddFileEvent,
- localCollectionChangeFileEvent,
- localCollectionUnlinkFileEvent,
- localCollectionUnlinkDirectoryEvent
+ collectionAddDirectoryEvent,
+ collectionAddFileEvent,
+ collectionChangeFileEvent,
+ collectionUnlinkFileEvent,
+ collectionUnlinkDirectoryEvent,
+ collectionUnlinkEnvFileEvent
} from 'providers/ReduxStore/slices/collections';
import toast from 'react-hot-toast';
-import { openLocalCollectionEvent, localCollectionLoadEnvironmentsEvent } from 'providers/ReduxStore/slices/collections/actions';
+import { openCollectionEvent, collectionAddEnvFileEvent } from 'providers/ReduxStore/slices/collections/actions';
import { isElectron } from 'utils/common/platform';
-const useLocalCollectionTreeSync = () => {
+const useCollectionTreeSync = () => {
const dispatch = useDispatch();
useEffect(() => {
@@ -23,27 +24,27 @@ const useLocalCollectionTreeSync = () => {
const _openCollection = (pathname, uid, name) => {
console.log(`collection uid: ${uid}, pathname: ${pathname}, name: ${name}`);
- dispatch(openLocalCollectionEvent(uid, pathname, name));
+ dispatch(openCollectionEvent(uid, pathname, name));
};
const _collectionTreeUpdated = (type, val) => {
if (type === 'addDir') {
dispatch(
- localCollectionAddDirectoryEvent({
+ collectionAddDirectoryEvent({
dir: val
})
);
}
if (type === 'addFile') {
dispatch(
- localCollectionAddFileEvent({
+ collectionAddFileEvent({
file: val
})
);
}
if (type === 'change') {
dispatch(
- localCollectionChangeFileEvent({
+ collectionChangeFileEvent({
file: val
})
);
@@ -51,7 +52,7 @@ const useLocalCollectionTreeSync = () => {
if (type === 'unlink') {
setTimeout(() => {
dispatch(
- localCollectionUnlinkFileEvent({
+ collectionUnlinkFileEvent({
file: val
})
);
@@ -59,21 +60,21 @@ const useLocalCollectionTreeSync = () => {
}
if (type === 'unlinkDir') {
dispatch(
- localCollectionUnlinkDirectoryEvent({
+ collectionUnlinkDirectoryEvent({
directory: val
})
);
}
if (type === 'addEnvironmentFile') {
- dispatch(localCollectionLoadEnvironmentsEvent(val));
+ dispatch(collectionAddEnvFileEvent(val));
}
- if (type === 'changeEnvironmentFile') {
- dispatch(localCollectionLoadEnvironmentsEvent(val));
+ if (type === 'unlinkEnvironmentFile') {
+ dispatch(collectionUnlinkEnvFileEvent(val));
}
};
const _collectionAlreadyOpened = (pathname) => {
- toast.success('Collection is already opened under local collections');
+ toast.success('Collection is already opened');
};
const _displayError = (message) => {
@@ -96,4 +97,4 @@ const useLocalCollectionTreeSync = () => {
}, [isElectron]);
};
-export default useLocalCollectionTreeSync;
+export default useCollectionTreeSync;
diff --git a/packages/bruno-app/src/providers/App/useIdb.js b/packages/bruno-app/src/providers/App/useIdb.js
deleted file mode 100644
index 42ead12e..00000000
--- a/packages/bruno-app/src/providers/App/useIdb.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import { useEffect } from 'react';
-import { openDB } from 'idb';
-import { idbConnectionReady } from 'providers/ReduxStore/slices/app';
-import { loadCollectionsFromIdb } from 'providers/ReduxStore/slices/collections/actions';
-import { loadWorkspacesFromIdb } from 'providers/ReduxStore/slices/workspaces/actions';
-import { useDispatch } from 'react-redux';
-
-const useIdb = () => {
- const dispatch = useDispatch();
-
- useEffect(() => {
- let dbName = `bruno`;
- let connection = openDB(dbName, 1, {
- upgrade(db, oldVersion, newVersion, transaction) {
- switch (oldVersion) {
- case 0:
- const collectionStore = db.createObjectStore('collection', { keyPath: 'uid' });
- const workspaceStore = db.createObjectStore('workspace', { keyPath: 'uid' });
- }
- }
- });
-
- connection
- .then(() => {
- window.__idb = connection;
- dispatch(idbConnectionReady());
- dispatch(loadCollectionsFromIdb());
- dispatch(loadWorkspacesFromIdb());
- })
- .catch((err) => console.log(err));
- }, []);
-};
-
-export default useIdb;
diff --git a/packages/bruno-app/src/providers/ReduxStore/index.js b/packages/bruno-app/src/providers/ReduxStore/index.js
index f0bdebf7..d86b18fc 100644
--- a/packages/bruno-app/src/providers/ReduxStore/index.js
+++ b/packages/bruno-app/src/providers/ReduxStore/index.js
@@ -2,14 +2,12 @@ import { configureStore } from '@reduxjs/toolkit';
import appReducer from './slices/app';
import collectionsReducer from './slices/collections';
import tabsReducer from './slices/tabs';
-import workspacesReducer from './slices/workspaces';
export const store = configureStore({
reducer: {
app: appReducer,
collections: collectionsReducer,
- tabs: tabsReducer,
- workspaces: workspacesReducer
+ tabs: tabsReducer
}
});
diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js
index 46996f6a..8a055179 100644
--- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js
+++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js
@@ -1,8 +1,6 @@
import path from 'path';
import filter from 'lodash/filter';
-import each from 'lodash/each';
import trim from 'lodash/trim';
-import toast from 'react-hot-toast';
import { uuid } from 'utils/common';
import cloneDeep from 'lodash/cloneDeep';
import {
@@ -13,21 +11,18 @@ import {
recursivelyGetAllItemUids,
transformCollectionToSaveToIdb,
transformRequestToSaveToFilesystem,
- deleteItemInCollection,
findParentItemInCollection,
findEnvironmentInCollection,
isItemAFolder,
refreshUidsInItem,
- interpolateEnvironmentVars,
- getDefaultRequestPaneTab
+ interpolateEnvironmentVars
} from 'utils/collections';
-import { collectionSchema, itemSchema, environmentsSchema } from '@usebruno/schema';
+import { collectionSchema, itemSchema, environmentSchema, environmentsSchema } from '@usebruno/schema';
import { waitForNextTick } from 'utils/common';
-import { getCollectionsFromIdb, saveCollectionToIdb, deleteCollectionInIdb } from 'utils/idb';
+import { saveCollectionToIdb } from 'utils/idb';
import { sendNetworkRequest, cancelNetworkRequest } from 'utils/network';
import {
- loadCollections,
requestSent,
requestCancelled,
responseReceived,
@@ -38,91 +33,18 @@ import {
moveItem as _moveItem,
moveItemToRootOfCollection as _moveItemToRootOfCollection,
saveRequest as _saveRequest,
- addEnvironment as _addEnvironment,
- renameEnvironment as _renameEnvironment,
- deleteEnvironment as _deleteEnvironment,
- saveEnvironment as _saveEnvironment,
selectEnvironment as _selectEnvironment,
createCollection as _createCollection,
renameCollection as _renameCollection,
- deleteCollection as _deleteCollection,
- localCollectionLoadEnvironmentsEvent as _localCollectionLoadEnvironmentsEvent
+ removeCollection as _removeCollection,
+ collectionAddEnvFileEvent as _collectionAddEnvFileEvent
} from './index';
-import { closeTabs, addTab } from 'providers/ReduxStore/slices/tabs';
-import { addCollectionToWorkspace } from 'providers/ReduxStore/slices/workspaces/actions';
+import { closeTabs } from 'providers/ReduxStore/slices/tabs';
import { isLocalCollection, resolveRequestFilename } from 'utils/common/platform';
const PATH_SEPARATOR = path.sep;
-export const loadCollectionsFromIdb = () => (dispatch) => {
- getCollectionsFromIdb(window.__idb)
- .then((collections) =>
- dispatch(
- loadCollections({
- collections: collections
- })
- )
- )
- .catch(() => toast.error('Error occured while loading collections from IndexedDB'));
-};
-
-export const createCollection = (collectionName) => (dispatch, getState) => {
- const newCollection = {
- version: '1',
- uid: uuid(),
- name: collectionName,
- items: [],
- environments: []
- };
-
- const requestItem = {
- uid: uuid(),
- type: 'http-request',
- name: 'Untitled',
- request: {
- method: 'GET',
- url: '',
- headers: [],
- params: [],
- body: {
- mode: 'none',
- json: null,
- text: null,
- xml: null,
- multipartForm: null,
- formUrlEncoded: null
- }
- }
- };
-
- newCollection.items.push(requestItem);
-
- const state = getState();
- const { activeWorkspaceUid } = state.workspaces;
-
- return new Promise((resolve, reject) => {
- collectionSchema
- .validate(newCollection)
- .then(() => saveCollectionToIdb(window.__idb, newCollection))
- .then(() => dispatch(_createCollection(newCollection)))
- .then(waitForNextTick)
- .then(() => dispatch(addCollectionToWorkspace(activeWorkspaceUid, newCollection.uid)))
- .then(waitForNextTick)
- .then(() =>
- dispatch(
- addTab({
- uid: requestItem.uid,
- collectionUid: newCollection.uid,
- requestPaneTab: getDefaultRequestPaneTab(requestItem)
- })
- )
- )
- .then(resolve)
- .catch(reject);
- });
-};
-
export const renameCollection = (newName, collectionUid) => (dispatch, getState) => {
const state = getState();
const collection = findCollectionByUid(state.collections.collections, collectionUid);
@@ -149,33 +71,6 @@ export const renameCollection = (newName, collectionUid) => (dispatch, getState)
}
};
-export const deleteCollection = (collectionUid) => (dispatch, getState) => {
- const state = getState();
- const collection = findCollectionByUid(state.collections.collections, collectionUid);
-
- return new Promise((resolve, reject) => {
- if (!collection) {
- return reject('collection not found');
- }
-
- deleteCollectionInIdb(window.__idb, collection.uid)
- .then(() => {
- dispatch(
- closeTabs({
- tabUids: recursivelyGetAllItemUids(collection.items)
- })
- );
- dispatch(
- _deleteCollection({
- collectionUid: collectionUid
- })
- );
- })
- .then(resolve)
- .catch(reject);
- });
-};
-
export const saveRequest = (itemUid, collectionUid) => (dispatch, getState) => {
const state = getState();
const collection = findCollectionByUid(state.collections.collections, collectionUid);
@@ -186,39 +81,19 @@ export const saveRequest = (itemUid, collectionUid) => (dispatch, getState) => {
}
const collectionCopy = cloneDeep(collection);
-
- if (isLocalCollection(collection)) {
- const item = findItemInCollection(collectionCopy, itemUid);
- if (item) {
- const itemToSave = transformRequestToSaveToFilesystem(item);
- const { ipcRenderer } = window;
-
- itemSchema
- .validate(itemToSave)
- .then(() => ipcRenderer.invoke('renderer:save-request', item.pathname, itemToSave))
- .then(resolve)
- .catch(reject);
- } else {
- reject(new Error('Not able to locate item'));
- }
- return;
+ const item = findItemInCollection(collectionCopy, itemUid);
+ if (!item) {
+ return reject(new Error('Not able to locate item'));
}
- const collectionToSave = transformCollectionToSaveToIdb(collectionCopy);
+ const itemToSave = transformRequestToSaveToFilesystem(item);
+ const { ipcRenderer } = window;
- collectionSchema
- .validate(collectionToSave)
- .then(() => saveCollectionToIdb(window.__idb, collectionToSave))
- .then(() => {
- dispatch(
- _saveRequest({
- itemUid: itemUid,
- collectionUid: collectionUid
- })
- );
- })
- .then(() => resolve())
- .catch((error) => reject(error));
+ itemSchema
+ .validate(itemToSave)
+ .then(() => ipcRenderer.invoke('renderer:save-request', item.pathname, itemToSave))
+ .then(resolve)
+ .catch(reject);
});
};
@@ -298,11 +173,25 @@ export const newFolder = (folderName, collectionUid, itemUid) => (dispatch, getS
return reject(new Error('Collection not found'));
}
- if (isLocalCollection(collection)) {
- if (!itemUid) {
- const folderWithSameNameExists = find(collection.items, (i) => i.type === 'folder' && trim(i.name) === trim(folderName));
+ if (!itemUid) {
+ const folderWithSameNameExists = find(collection.items, (i) => i.type === 'folder' && trim(i.name) === trim(folderName));
+ if (!folderWithSameNameExists) {
+ const fullName = `${collection.pathname}${PATH_SEPARATOR}${folderName}`;
+ const { ipcRenderer } = window;
+
+ ipcRenderer
+ .invoke('renderer:new-folder', fullName)
+ .then(() => resolve())
+ .catch((error) => reject(error));
+ } else {
+ return reject(new Error('folder with same name already exists'));
+ }
+ } else {
+ const currentItem = findItemInCollection(collection, itemUid);
+ if (currentItem) {
+ const folderWithSameNameExists = find(currentItem.items, (i) => i.type === 'folder' && trim(i.name) === trim(folderName));
if (!folderWithSameNameExists) {
- const fullName = `${collection.pathname}${PATH_SEPARATOR}${folderName}`;
+ const fullName = `${currentItem.pathname}${PATH_SEPARATOR}${folderName}`;
const { ipcRenderer } = window;
ipcRenderer
@@ -313,59 +202,9 @@ export const newFolder = (folderName, collectionUid, itemUid) => (dispatch, getS
return reject(new Error('folder with same name already exists'));
}
} else {
- const currentItem = findItemInCollection(collection, itemUid);
- if (currentItem) {
- const folderWithSameNameExists = find(currentItem.items, (i) => i.type === 'folder' && trim(i.name) === trim(folderName));
- if (!folderWithSameNameExists) {
- const fullName = `${currentItem.pathname}${PATH_SEPARATOR}${folderName}`;
- const { ipcRenderer } = window;
-
- ipcRenderer
- .invoke('renderer:new-folder', fullName)
- .then(() => resolve())
- .catch((error) => reject(error));
- } else {
- return reject(new Error('folder with same name already exists'));
- }
- } else {
- return reject(new Error('unable to find parent folder'));
- }
- }
- return;
- }
-
- const collectionCopy = cloneDeep(collection);
- const item = {
- uid: uuid(),
- name: folderName,
- type: 'folder',
- items: []
- };
- if (!itemUid) {
- collectionCopy.items.push(item);
- } else {
- const currentItem = findItemInCollection(collectionCopy, itemUid);
- if (currentItem && currentItem.type === 'folder') {
- currentItem.items = currentItem.items || [];
- currentItem.items.push(item);
+ return reject(new Error('unable to find parent folder'));
}
}
- const collectionToSave = transformCollectionToSaveToIdb(collectionCopy);
-
- collectionSchema
- .validate(collectionToSave)
- .then(() => saveCollectionToIdb(window.__idb, collectionToSave))
- .then(() => {
- dispatch(
- _newItem({
- item: item,
- currentItemUid: itemUid,
- collectionUid: collectionUid
- })
- );
- })
- .then(() => resolve())
- .catch((error) => reject(error));
});
};
@@ -384,42 +223,21 @@ export const renameItem = (newName, itemUid, collectionUid) => (dispatch, getSta
return reject(new Error('Unable to locate item'));
}
- if (isLocalCollection(collection)) {
- const dirname = path.dirname(item.pathname);
+ const dirname = path.dirname(item.pathname);
- let newPathname = '';
- if (item.type === 'folder') {
- newPathname = `${dirname}${PATH_SEPARATOR}${trim(newName)}`;
- } else {
- const filename = resolveRequestFilename(newName);
- newPathname = `${dirname}${PATH_SEPARATOR}${filename}`;
- }
- const { ipcRenderer } = window;
-
- ipcRenderer.invoke('renderer:rename-item', item.pathname, newPathname, newName).then(resolve).catch(reject);
-
- return;
+ let newPathname = '';
+ if (item.type === 'folder') {
+ newPathname = `${dirname}${PATH_SEPARATOR}${trim(newName)}`;
+ } else {
+ const filename = resolveRequestFilename(newName);
+ newPathname = `${dirname}${PATH_SEPARATOR}${filename}`;
}
+ const { ipcRenderer } = window;
- item.name = newName;
- const collectionToSave = transformCollectionToSaveToIdb(collectionCopy, {
- ignoreDraft: true
- });
-
- collectionSchema
- .validate(collectionToSave)
- .then(() => saveCollectionToIdb(window.__idb, collectionToSave))
- .then(() => {
- dispatch(
- _renameItem({
- newName: newName,
- itemUid: itemUid,
- collectionUid: collectionUid
- })
- );
- })
- .then(() => resolve())
- .catch((error) => reject(error));
+ ipcRenderer
+ .invoke('renderer:rename-item', item.pathname, newPathname, newName)
+ .then(resolve)
+ .catch(reject);
});
};
@@ -441,74 +259,40 @@ export const cloneItem = (newName, itemUid, collectionUid) => (dispatch, getStat
throw new Error('Cloning folders is not supported yet');
}
- if (isLocalCollection(collection)) {
- const parentItem = findParentItemInCollection(collectionCopy, itemUid);
- const filename = resolveRequestFilename(newName);
- const itemToSave = refreshUidsInItem(transformRequestToSaveToFilesystem(item));
- itemToSave.name = trim(newName);
- if (!parentItem) {
- const reqWithSameNameExists = find(collection.items, (i) => i.type !== 'folder' && trim(i.filename) === trim(filename));
- if (!reqWithSameNameExists) {
- const fullName = `${collection.pathname}${PATH_SEPARATOR}${filename}`;
- const { ipcRenderer } = window;
-
- itemSchema
- .validate(itemToSave)
- .then(() => ipcRenderer.invoke('renderer:new-request', fullName, itemToSave))
- .then(resolve)
- .catch(reject);
- } else {
- return reject(new Error(`${requestName} already exists in collection`));
- }
- } else {
- const reqWithSameNameExists = find(parentItem.items, (i) => i.type !== 'folder' && trim(i.filename) === trim(filename));
- if (!reqWithSameNameExists) {
- const dirname = path.dirname(item.pathname);
- const fullName = `${dirname}${PATH_SEPARATOR}${filename}`;
- const { ipcRenderer } = window;
-
- itemSchema
- .validate(itemToSave)
- .then(() => ipcRenderer.invoke('renderer:new-request', fullName, itemToSave))
- .then(resolve)
- .catch(reject);
- } else {
- return reject(new Error(`${requestName} already exists in the folder`));
- }
- }
- return;
- }
-
- // todo: clone query params
- const clonedItem = cloneDeep(item);
- clonedItem.name = newName;
- clonedItem.uid = uuid();
- each(clonedItem.headers, (h) => (h.uid = uuid()));
-
const parentItem = findParentItemInCollection(collectionCopy, itemUid);
-
+ const filename = resolveRequestFilename(newName);
+ const itemToSave = refreshUidsInItem(transformRequestToSaveToFilesystem(item));
+ itemToSave.name = trim(newName);
if (!parentItem) {
- collectionCopy.items.push(clonedItem);
+ const reqWithSameNameExists = find(collection.items, (i) => i.type !== 'folder' && trim(i.filename) === trim(filename));
+ if (!reqWithSameNameExists) {
+ const fullName = `${collection.pathname}${PATH_SEPARATOR}${filename}`;
+ const { ipcRenderer } = window;
+
+ itemSchema
+ .validate(itemToSave)
+ .then(() => ipcRenderer.invoke('renderer:new-request', fullName, itemToSave))
+ .then(resolve)
+ .catch(reject);
+ } else {
+ return reject(new Error(`${requestName} already exists in collection`));
+ }
} else {
- parentItem.items.push(clonedItem);
+ const reqWithSameNameExists = find(parentItem.items, (i) => i.type !== 'folder' && trim(i.filename) === trim(filename));
+ if (!reqWithSameNameExists) {
+ const dirname = path.dirname(item.pathname);
+ const fullName = `${dirname}${PATH_SEPARATOR}${filename}`;
+ const { ipcRenderer } = window;
+
+ itemSchema
+ .validate(itemToSave)
+ .then(() => ipcRenderer.invoke('renderer:new-request', fullName, itemToSave))
+ .then(resolve)
+ .catch(reject);
+ } else {
+ return reject(new Error(`${requestName} already exists in the folder`));
+ }
}
-
- const collectionToSave = transformCollectionToSaveToIdb(collectionCopy);
-
- collectionSchema
- .validate(collectionToSave)
- .then(() => saveCollectionToIdb(window.__idb, collectionToSave))
- .then(() => {
- dispatch(
- _cloneItem({
- parentItemUid: parentItem ? parentItem.uid : null,
- clonedItem: clonedItem,
- collectionUid: collectionUid
- })
- );
- })
- .then(() => resolve())
- .catch((error) => reject(error));
});
};
@@ -521,36 +305,16 @@ export const deleteItem = (itemUid, collectionUid) => (dispatch, getState) => {
return reject(new Error('Collection not found'));
}
- if (isLocalCollection(collection)) {
- const item = findItemInCollection(collection, itemUid);
- if (item) {
- const { ipcRenderer } = window;
+ const item = findItemInCollection(collection, itemUid);
+ if (item) {
+ const { ipcRenderer } = window;
- ipcRenderer
- .invoke('renderer:delete-item', item.pathname, item.type)
- .then(() => resolve())
- .catch((error) => reject(error));
- }
- return;
+ ipcRenderer
+ .invoke('renderer:delete-item', item.pathname, item.type)
+ .then(() => resolve())
+ .catch((error) => reject(error));
}
-
- const collectionCopy = cloneDeep(collection);
- deleteItemInCollection(itemUid, collectionCopy);
- const collectionToSave = transformCollectionToSaveToIdb(collectionCopy);
-
- collectionSchema
- .validate(collectionToSave)
- .then(() => saveCollectionToIdb(window.__idb, collectionToSave))
- .then(() => {
- dispatch(
- _deleteItem({
- itemUid: itemUid,
- collectionUid: collectionUid
- })
- );
- })
- .then(() => resolve())
- .catch((error) => reject(error));
+ return;
});
};
@@ -699,70 +463,31 @@ export const newHttpRequest = (params) => (dispatch, getState) => {
}
};
- if (isLocalCollection(collection)) {
- const filename = resolveRequestFilename(requestName);
- if (!itemUid) {
- const reqWithSameNameExists = find(collection.items, (i) => i.type !== 'folder' && trim(i.filename) === trim(filename));
+ const filename = resolveRequestFilename(requestName);
+ if (!itemUid) {
+ const reqWithSameNameExists = find(collection.items, (i) => i.type !== 'folder' && trim(i.filename) === trim(filename));
+ if (!reqWithSameNameExists) {
+ const fullName = `${collection.pathname}${PATH_SEPARATOR}${filename}`;
+ const { ipcRenderer } = window;
+
+ ipcRenderer.invoke('renderer:new-request', fullName, item).then(resolve).catch(reject);
+ } else {
+ return reject(new Error(`${requestName} already exists in collection`));
+ }
+ } else {
+ const currentItem = findItemInCollection(collection, itemUid);
+ if (currentItem) {
+ const reqWithSameNameExists = find(currentItem.items, (i) => i.type !== 'folder' && trim(i.filename) === trim(filename));
if (!reqWithSameNameExists) {
- const fullName = `${collection.pathname}${PATH_SEPARATOR}${filename}`;
+ const fullName = `${currentItem.pathname}${PATH_SEPARATOR}${filename}`;
const { ipcRenderer } = window;
ipcRenderer.invoke('renderer:new-request', fullName, item).then(resolve).catch(reject);
} else {
- return reject(new Error(`${requestName} already exists in collection`));
- }
- } else {
- const currentItem = findItemInCollection(collection, itemUid);
- if (currentItem) {
- const reqWithSameNameExists = find(currentItem.items, (i) => i.type !== 'folder' && trim(i.filename) === trim(filename));
- if (!reqWithSameNameExists) {
- const fullName = `${currentItem.pathname}${PATH_SEPARATOR}${filename}`;
- const { ipcRenderer } = window;
-
- ipcRenderer.invoke('renderer:new-request', fullName, item).then(resolve).catch(reject);
- } else {
- return reject(new Error(`${requestName} already exists in the folder`));
- }
+ return reject(new Error(`${requestName} already exists in the folder`));
}
}
- return;
}
-
- if (!itemUid) {
- collectionCopy.items.push(item);
- } else {
- const currentItem = findItemInCollection(collectionCopy, itemUid);
- if (currentItem && currentItem.type === 'folder') {
- currentItem.items = currentItem.items || [];
- currentItem.items.push(item);
- }
- }
- const collectionToSave = transformCollectionToSaveToIdb(collectionCopy);
-
- collectionSchema
- .validate(collectionToSave)
- .then(() => saveCollectionToIdb(window.__idb, collectionToSave))
- .then(() => {
- dispatch(
- _newItem({
- item: item,
- currentItemUid: itemUid,
- collectionUid: collectionUid
- })
- );
- })
- .then(waitForNextTick)
- .then(() => {
- dispatch(
- addTab({
- uid: item.uid,
- collectionUid: collection.uid,
- requestPaneTab: getDefaultRequestPaneTab(item)
- })
- );
- })
- .then(() => resolve())
- .catch(reject);
});
};
@@ -774,30 +499,8 @@ export const addEnvironment = (name, collectionUid) => (dispatch, getState) => {
return reject(new Error('Collection not found'));
}
- const environment = {
- uid: uuid(),
- name: name,
- variables: []
- };
-
- const collectionCopy = cloneDeep(collection);
- const collectionToSave = transformCollectionToSaveToIdb(collectionCopy);
- collectionToSave.environments = collectionToSave.environments || [];
- collectionToSave.environments.push(environment);
-
- if (isLocalCollection(collection)) {
- environmentsSchema
- .validate(collectionToSave.environments)
- .then(() => ipcRenderer.invoke('renderer:save-environment', collection.pathname, collectionToSave.environments))
- .then(resolve)
- .catch(reject);
- return;
- }
-
- collectionSchema
- .validate(collectionToSave)
- .then(() => saveCollectionToIdb(window.__idb, collectionToSave))
- .then(() => dispatch(_addEnvironment({ environment, collectionUid })))
+ ipcRenderer
+ .invoke('renderer:create-environment', collection.pathname, name)
.then(resolve)
.catch(reject);
});
@@ -817,23 +520,12 @@ export const renameEnvironment = (newName, environmentUid, collectionUid) => (di
return reject(new Error('Environment not found'));
}
+ const oldName = environment.name;
environment.name = newName;
- const collectionToSave = transformCollectionToSaveToIdb(collectionCopy);
- if (isLocalCollection(collection)) {
- const environments = collectionToSave.environments;
- environmentsSchema
- .validate(environments)
- .then(() => ipcRenderer.invoke('renderer:save-environment', collection.pathname, environments))
- .then(resolve)
- .catch(reject);
- return;
- }
-
- collectionSchema
- .validate(collectionToSave)
- .then(() => saveCollectionToIdb(window.__idb, collectionToSave))
- .then(() => dispatch(_renameEnvironment({ newName, environmentUid, collectionUid })))
+ environmentSchema
+ .validate(environment)
+ .then(() => ipcRenderer.invoke('renderer:rename-environment', collection.pathname, oldName, newName))
.then(resolve)
.catch(reject);
});
@@ -854,23 +546,8 @@ export const deleteEnvironment = (environmentUid, collectionUid) => (dispatch, g
return reject(new Error('Environment not found'));
}
- collectionCopy.environments = filter(collectionCopy.environments, (e) => e.uid !== environmentUid);
- const collectionToSave = transformCollectionToSaveToIdb(collectionCopy);
-
- if (isLocalCollection(collection)) {
- const environments = collectionToSave.environments;
- environmentsSchema
- .validate(environments)
- .then(() => ipcRenderer.invoke('renderer:save-environment', collection.pathname, environments))
- .then(resolve)
- .catch(reject);
- return;
- }
-
- collectionSchema
- .validate(collectionToSave)
- .then(() => saveCollectionToIdb(window.__idb, collectionToSave))
- .then(() => dispatch(_deleteEnvironment({ environmentUid, collectionUid })))
+ ipcRenderer
+ .invoke('renderer:delete-environment', collection.pathname, environment.name)
.then(resolve)
.catch(reject);
});
@@ -892,21 +569,9 @@ export const saveEnvironment = (variables, environmentUid, collectionUid) => (di
environment.variables = variables;
- const collectionToSave = transformCollectionToSaveToIdb(collectionCopy);
- if (isLocalCollection(collection)) {
- const environments = collectionToSave.environments;
- environmentsSchema
- .validate(environments)
- .then(() => ipcRenderer.invoke('renderer:save-environment', collection.pathname, environments))
- .then(resolve)
- .catch(reject);
- return;
- }
-
- collectionSchema
- .validate(collectionToSave)
- .then(() => saveCollectionToIdb(window.__idb, collectionToSave))
- .then(() => dispatch(_saveEnvironment({ variables, environmentUid, collectionUid })))
+ environmentSchema
+ .validate(environment)
+ .then(() => ipcRenderer.invoke('renderer:save-environment', collection.pathname, environment))
.then(resolve)
.catch(reject);
});
@@ -928,19 +593,12 @@ export const selectEnvironment = (environmentUid, collectionUid) => (dispatch, g
}
}
- collectionCopy.activeEnvironmentUid = environmentUid;
- const collectionToSave = transformCollectionToSaveToIdb(collectionCopy);
-
- collectionSchema
- .validate(collectionToSave)
- .then(() => saveCollectionToIdb(window.__idb, collectionToSave))
- .then(() => dispatch(_selectEnvironment({ environmentUid, collectionUid })))
- .then(resolve)
- .catch(reject);
+ dispatch(_selectEnvironment({ environmentUid, collectionUid }));
+ resolve();
});
};
-export const removeLocalCollection = (collectionUid) => (dispatch, getState) => {
+export const removeCollection = (collectionUid) => (dispatch, getState) => {
return new Promise((resolve, reject) => {
const state = getState();
const collection = findCollectionByUid(state.collections.collections, collectionUid);
@@ -960,7 +618,7 @@ export const removeLocalCollection = (collectionUid) => (dispatch, getState) =>
.then(waitForNextTick)
.then(() => {
dispatch(
- _deleteCollection({
+ _removeCollection({
collectionUid: collectionUid
})
);
@@ -970,7 +628,7 @@ export const removeLocalCollection = (collectionUid) => (dispatch, getState) =>
});
};
-export const browserLocalDirectory = () => (dispatch, getState) => {
+export const browseDirectory = () => (dispatch, getState) => {
const { ipcRenderer } = window;
return new Promise((resolve, reject) => {
@@ -978,8 +636,8 @@ export const browserLocalDirectory = () => (dispatch, getState) => {
});
};
-export const openLocalCollectionEvent = (uid, pathname, name) => (dispatch, getState) => {
- const localCollection = {
+export const openCollectionEvent = (uid, pathname, name) => (dispatch, getState) => {
+ const collection = {
version: '1',
uid: uid,
name: name,
@@ -989,14 +647,14 @@ export const openLocalCollectionEvent = (uid, pathname, name) => (dispatch, getS
return new Promise((resolve, reject) => {
collectionSchema
- .validate(localCollection)
- .then(() => dispatch(_createCollection(localCollection)))
+ .validate(collection)
+ .then(() => dispatch(_createCollection(collection)))
.then(resolve)
.catch(reject);
});
};
-export const createLocalCollection = (collectionName, collectionLocation) => () => {
+export const createCollection = (collectionName, collectionLocation) => () => {
const { ipcRenderer } = window;
return new Promise((resolve, reject) => {
@@ -1004,7 +662,7 @@ export const createLocalCollection = (collectionName, collectionLocation) => ()
});
};
-export const openLocalCollection = () => () => {
+export const openCollection = () => () => {
return new Promise((resolve, reject) => {
const { ipcRenderer } = window;
@@ -1012,8 +670,8 @@ export const openLocalCollection = () => () => {
});
};
-export const localCollectionLoadEnvironmentsEvent = (payload) => (dispatch, getState) => {
- const { data: environments, meta } = payload;
+export const collectionAddEnvFileEvent = (payload) => (dispatch, getState) => {
+ const { data: environment, meta } = payload;
return new Promise((resolve, reject) => {
const state = getState();
@@ -1022,12 +680,12 @@ export const localCollectionLoadEnvironmentsEvent = (payload) => (dispatch, getS
return reject(new Error('Collection not found'));
}
- environmentsSchema
- .validate(environments)
+ environmentSchema
+ .validate(environment)
.then(() =>
dispatch(
- _localCollectionLoadEnvironmentsEvent({
- environments,
+ _collectionAddEnvFileEvent({
+ environment,
collectionUid: meta.collectionUid
})
)
@@ -1036,3 +694,14 @@ export const localCollectionLoadEnvironmentsEvent = (payload) => (dispatch, getS
.catch(reject);
});
};
+
+export const importCollection = (collection, collectionLocation) => (dispatch, getState) => {
+ return new Promise((resolve, reject) => {
+ const { ipcRenderer } = window;
+
+ ipcRenderer
+ .invoke('renderer:import-collection', collection, collectionLocation)
+ .then(resolve)
+ .catch(reject);
+ });
+};
diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
index 1a9b3ec1..ab8f22f8 100644
--- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
+++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
@@ -32,26 +32,6 @@ export const collectionsSlice = createSlice({
name: 'collections',
initialState,
reducers: {
- loadCollections: (state, action) => {
- const collectionUids = map(state.collections, (c) => c.uid);
- each(action.payload.collections, (c) => collapseCollection(c));
- each(action.payload.collections, (c) => addDepth(c.items));
- each(action.payload.collections, (c) => {
- if (!collectionUids.includes(c.uid)) {
- state.collections.push(c);
- collectionUids.push(c.uid);
- }
- });
- },
- collectionImported: (state, action) => {
- const collectionUids = map(state.collections, (c) => c.uid);
- const { collection } = action.payload;
- collapseCollection(collection);
- addDepth(collection.items);
- if (!collectionUids.includes(collection.uid)) {
- state.collections.push(collection);
- }
- },
createCollection: (state, action) => {
const collectionUids = map(state.collections, (c) => c.uid);
const collection = action.payload;
@@ -68,7 +48,7 @@ export const collectionsSlice = createSlice({
collection.name = action.payload.newName;
}
},
- deleteCollection: (state, action) => {
+ removeCollection: (state, action) => {
state.collections = filter(state.collections, (c) => c.uid !== action.payload.collectionUid);
},
addEnvironment: (state, action) => {
@@ -80,28 +60,12 @@ export const collectionsSlice = createSlice({
collection.environments.push(environment);
}
},
- renameEnvironment: (state, action) => {
- const { newName, environmentUid, collectionUid } = action.payload;
- const collection = findCollectionByUid(state.collections, collectionUid);
+ collectionUnlinkEnvFileEvent: (state, action) => {
+ const { data: environment, meta } = action.payload;
+ const collection = findCollectionByUid(state.collections, meta.collectionUid);
if (collection) {
- const environment = findEnvironmentInCollection(collection, environmentUid);
-
- if (environment) {
- environment.name = newName;
- }
- }
- },
- deleteEnvironment: (state, action) => {
- const { environmentUid, collectionUid } = action.payload;
- const collection = findCollectionByUid(state.collections, collectionUid);
-
- if (collection) {
- const environment = findEnvironmentInCollection(collection, environmentUid);
-
- if (environment) {
- collection.environments = filter(collection.environments, (e) => e.uid !== environmentUid);
- }
+ collection.environments = filter(collection.environments, (e) => e.uid !== environment.uid);
}
},
saveEnvironment: (state, action) => {
@@ -669,7 +633,7 @@ export const collectionsSlice = createSlice({
}
}
},
- localCollectionAddFileEvent: (state, action) => {
+ collectionAddFileEvent: (state, action) => {
const file = action.payload.file;
const collection = findCollectionByUid(state.collections, file.meta.collectionUid);
@@ -723,7 +687,7 @@ export const collectionsSlice = createSlice({
addDepth(collection.items);
}
},
- localCollectionAddDirectoryEvent: (state, action) => {
+ collectionAddDirectoryEvent: (state, action) => {
const { dir } = action.payload;
const collection = findCollectionByUid(state.collections, dir.meta.collectionUid);
@@ -751,7 +715,7 @@ export const collectionsSlice = createSlice({
addDepth(collection.items);
}
},
- localCollectionChangeFileEvent: (state, action) => {
+ collectionChangeFileEvent: (state, action) => {
const { file } = action.payload;
const collection = findCollectionByUid(state.collections, file.meta.collectionUid);
@@ -768,7 +732,7 @@ export const collectionsSlice = createSlice({
}
}
},
- localCollectionUnlinkFileEvent: (state, action) => {
+ collectionUnlinkFileEvent: (state, action) => {
const { file } = action.payload;
const collection = findCollectionByUid(state.collections, file.meta.collectionUid);
@@ -780,7 +744,7 @@ export const collectionsSlice = createSlice({
}
}
},
- localCollectionUnlinkDirectoryEvent: (state, action) => {
+ collectionUnlinkDirectoryEvent: (state, action) => {
const { directory } = action.payload;
const collection = findCollectionByUid(state.collections, directory.meta.collectionUid);
@@ -792,26 +756,31 @@ export const collectionsSlice = createSlice({
}
}
},
- localCollectionLoadEnvironmentsEvent: (state, action) => {
- const { environments, collectionUid } = action.payload;
+ collectionAddEnvFileEvent: (state, action) => {
+ const { environment, collectionUid } = action.payload;
const collection = findCollectionByUid(state.collections, collectionUid);
if (collection) {
- collection.environments = environments;
+ collection.environments = collection.environments || [];
+
+ const existingEnv = collection.environments.find((e) => e.uid === environment.uid);
+
+ if (existingEnv) {
+ existingEnv.variables = environment.variables;
+ } else {
+ collection.environments.push(environment);
+ }
}
}
}
});
export const {
- collectionImported,
createCollection,
renameCollection,
- deleteCollection,
- loadCollections,
+ removeCollection,
addEnvironment,
- renameEnvironment,
- deleteEnvironment,
+ collectionUnlinkEnvFileEvent,
saveEnvironment,
selectEnvironment,
newItem,
@@ -844,12 +813,12 @@ export const {
updateRequestBody,
updateRequestGraphqlQuery,
updateRequestMethod,
- localCollectionAddFileEvent,
- localCollectionAddDirectoryEvent,
- localCollectionChangeFileEvent,
- localCollectionUnlinkFileEvent,
- localCollectionUnlinkDirectoryEvent,
- localCollectionLoadEnvironmentsEvent
+ collectionAddFileEvent,
+ collectionAddDirectoryEvent,
+ collectionChangeFileEvent,
+ collectionUnlinkFileEvent,
+ collectionUnlinkDirectoryEvent,
+ collectionAddEnvFileEvent
} = collectionsSlice.actions;
export default collectionsSlice.reducer;
diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js b/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js
deleted file mode 100644
index ac0e559c..00000000
--- a/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js
+++ /dev/null
@@ -1,222 +0,0 @@
-import find from 'lodash/find';
-import filter from 'lodash/filter';
-import { uuid } from 'utils/common';
-import cloneDeep from 'lodash/cloneDeep';
-import { workspaceSchema } from '@usebruno/schema';
-import { findCollectionInWorkspace } from 'utils/workspaces';
-import { getWorkspacesFromIdb, saveWorkspaceToIdb, deleteWorkspaceInIdb } from 'utils/idb/workspaces';
-import { BrunoError } from 'utils/common/error';
-import {
- loadWorkspaces,
- addWorkspace as _addWorkspace,
- renameWorkspace as _renameWorkspace,
- deleteWorkspace as _deleteWorkspace,
- addCollectionToWorkspace as _addCollectionToWorkspace,
- removeCollectionFromWorkspace as _removeCollectionFromWorkspace
-} from './index';
-
-const seedWorkpace = () => {
- const uid = uuid();
- const workspace = {
- uid: uid,
- name: 'My workspace',
- collections: []
- };
-
- return new Promise((resolve, reject) => {
- workspaceSchema
- .validate(workspace)
- .then(() => saveWorkspaceToIdb(window.__idb, workspace))
- .then(() => resolve([workspace]))
- .catch(reject);
- });
-};
-
-export const loadWorkspacesFromIdb = () => (dispatch) => {
- return new Promise((resolve, reject) => {
- getWorkspacesFromIdb(window.__idb)
- .then((workspaces) => {
- if (!workspaces || !workspaces.length) {
- return seedWorkpace();
- }
-
- return workspaces;
- })
- .then((workspaces) =>
- dispatch(
- loadWorkspaces({
- workspaces: workspaces
- })
- )
- )
- .then(resolve)
- .catch(reject);
- });
-};
-
-export const addWorkspace = (workspaceName) => (dispatch) => {
- const newWorkspace = {
- uid: uuid(),
- name: workspaceName,
- collections: []
- };
-
- return new Promise((resolve, reject) => {
- workspaceSchema
- .validate(newWorkspace)
- .then(() => saveWorkspaceToIdb(window.__idb, newWorkspace))
- .then(() =>
- dispatch(
- _addWorkspace({
- workspace: newWorkspace
- })
- )
- )
- .then(resolve)
- .catch(reject);
- });
-};
-
-export const renameWorkspace = (newName, uid) => (dispatch, getState) => {
- const state = getState();
-
- return new Promise((resolve, reject) => {
- const workspace = find(state.workspaces.workspaces, (w) => w.uid === uid);
-
- if (!workspace) {
- return reject(new Error('Workspace not found'));
- }
-
- const workspaceCopy = cloneDeep(workspace);
- workspaceCopy.name = newName;
-
- workspaceSchema
- .validate(workspaceCopy)
- .then(() => saveWorkspaceToIdb(window.__idb, workspaceCopy))
- .then(() =>
- dispatch(
- _renameWorkspace({
- uid: uid,
- name: newName
- })
- )
- )
- .then(resolve)
- .catch(reject);
- });
-};
-
-export const deleteWorkspace = (workspaceUid) => (dispatch, getState) => {
- const state = getState();
-
- return new Promise((resolve, reject) => {
- if (state.workspaces.activeWorkspaceUid === workspaceUid) {
- throw new BrunoError('Cannot delete current workspace');
- }
-
- const workspace = find(state.workspaces.workspaces, (w) => w.uid === workspaceUid);
-
- if (!workspace) {
- return reject(new Error('Workspace not found'));
- }
-
- deleteWorkspaceInIdb(window.__idb, workspaceUid)
- .then(() =>
- dispatch(
- _deleteWorkspace({
- workspaceUid: workspaceUid
- })
- )
- )
- .then(resolve)
- .catch(reject);
- });
-};
-
-export const addCollectionToWorkspace = (workspaceUid, collectionUid) => (dispatch, getState) => {
- const state = getState();
-
- return new Promise((resolve, reject) => {
- const workspace = find(state.workspaces.workspaces, (w) => w.uid === workspaceUid);
- const collection = find(state.collections.collections, (c) => c.uid === collectionUid);
-
- if (!workspace) {
- return reject(new Error('Workspace not found'));
- }
-
- if (!collection) {
- return reject(new Error('Collection not found'));
- }
-
- const workspaceCopy = cloneDeep(workspace);
- if (workspaceCopy.collections && workspace.collections.length) {
- if (!findCollectionInWorkspace(workspace, collectionUid)) {
- workspaceCopy.collections.push({
- uid: collectionUid
- });
- }
- } else {
- workspaceCopy.collections = [
- {
- uid: collectionUid
- }
- ];
- }
-
- workspaceSchema
- .validate(workspaceCopy)
- .then(() => saveWorkspaceToIdb(window.__idb, workspaceCopy))
- .then(() =>
- dispatch(
- _addCollectionToWorkspace({
- workspaceUid: workspaceUid,
- collectionUid: collectionUid
- })
- )
- )
- .then(resolve)
- .catch(reject);
- });
-};
-
-export const removeCollectionFromWorkspace = (workspaceUid, collectionUid) => (dispatch, getState) => {
- const state = getState();
-
- return new Promise((resolve, reject) => {
- const workspace = find(state.workspaces.workspaces, (w) => w.uid === workspaceUid);
- const collection = find(state.collections.collections, (c) => c.uid === collectionUid);
-
- if (!workspace) {
- return reject(new Error('Workspace not found'));
- }
-
- if (!collection) {
- return reject(new Error('Collection not found'));
- }
-
- const workspaceCopy = cloneDeep(workspace);
- if (workspaceCopy.collections && workspace.collections.length) {
- workspaceCopy.collections = filter(workspaceCopy.collections, (c) => c.uid !== collectionUid);
- }
-
- workspaceSchema
- .validate(workspaceCopy)
- .then(() => saveWorkspaceToIdb(window.__idb, workspaceCopy))
- .then(() =>
- dispatch(
- _removeCollectionFromWorkspace({
- workspaceUid: workspaceUid,
- collectionUid: collectionUid
- })
- )
- )
- .then(resolve)
- .catch(reject);
- });
-};
-
-// TODO
-// Workspaces can have collection uids that no longer exist
-// or the user may have the collections access revoked (in teams)
-// This action will have to be called at the beginning to purge any zombi collection references in the workspaces
-export const removeZombieCollectionFromAllWorkspaces = (workspaceUid) => (dispatch, getState) => {};
diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/index.js b/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/index.js
deleted file mode 100644
index 1be9e641..00000000
--- a/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/index.js
+++ /dev/null
@@ -1,85 +0,0 @@
-import { createSlice } from '@reduxjs/toolkit';
-import find from 'lodash/find';
-import map from 'lodash/map';
-import filter from 'lodash/filter';
-import { findCollectionInWorkspace } from 'utils/workspaces';
-import cache from 'utils/common/cache';
-
-const initialState = {
- workspaces: [],
- activeWorkspaceUid: null
-};
-
-export const workspacesSlice = createSlice({
- name: 'workspaces',
- initialState,
- reducers: {
- loadWorkspaces: (state, action) => {
- state.workspaces = action.payload.workspaces;
-
- if (state.workspaces && state.workspaces.length) {
- const workspaceUids = map(state.workspaces, (w) => w.uid);
- const activeWorkspaceUid = cache.getActiveWorkspaceUid();
- if (activeWorkspaceUid && workspaceUids.includes(activeWorkspaceUid)) {
- state.activeWorkspaceUid = activeWorkspaceUid;
- } else {
- state.activeWorkspaceUid = state.workspaces[0].uid;
- cache.setActiveWorkspaceUid(state.activeWorkspaceUid);
- }
- }
- },
- selectWorkspace: (state, action) => {
- state.activeWorkspaceUid = action.payload.workspaceUid;
- cache.setActiveWorkspaceUid(state.activeWorkspaceUid);
- },
- renameWorkspace: (state, action) => {
- const { name, uid } = action.payload;
- const workspace = find(state.workspaces, (w) => w.uid === uid);
-
- if (workspace) {
- workspace.name = name;
- }
- },
- deleteWorkspace: (state, action) => {
- if (state.activeWorkspaceUid === action.payload.workspaceUid) {
- throw new Error('User cannot delete current workspace');
- }
- state.workspaces = state.workspaces.filter((workspace) => workspace.uid !== action.payload.workspaceUid);
- },
- addWorkspace: (state, action) => {
- state.workspaces.push(action.payload.workspace);
- },
- addCollectionToWorkspace: (state, action) => {
- const { workspaceUid, collectionUid } = action.payload;
- const workspace = find(state.workspaces, (w) => w.uid === workspaceUid);
-
- if (workspace) {
- if (workspace.collections && workspace.collections.length) {
- if (!findCollectionInWorkspace(workspace, collectionUid)) {
- workspace.collections.push({
- uid: collectionUid
- });
- }
- } else {
- workspace.collections = [
- {
- uid: collectionUid
- }
- ];
- }
- }
- },
- removeCollectionFromWorkspace: (state, action) => {
- const { workspaceUid, collectionUid } = action.payload;
- const workspace = find(state.workspaces, (w) => w.uid === workspaceUid);
-
- if (workspace && workspace.collections && workspace.collections.length) {
- workspace.collections = filter(workspace.collections, (c) => c.uid !== collectionUid);
- }
- }
- }
-});
-
-export const { loadWorkspaces, selectWorkspace, renameWorkspace, deleteWorkspace, addWorkspace, addCollectionToWorkspace, removeCollectionFromWorkspace } = workspacesSlice.actions;
-
-export default workspacesSlice.reducer;
diff --git a/packages/bruno-app/src/themes/dark.js b/packages/bruno-app/src/themes/dark.js
index 16cccca4..dff763d7 100644
--- a/packages/bruno-app/src/themes/dark.js
+++ b/packages/bruno-app/src/themes/dark.js
@@ -24,7 +24,7 @@ const darkTheme = {
bg: '#252526',
dragbar: '#8a8a8a',
- workspace: {
+ badge: {
bg: '#3D3D3D'
},
diff --git a/packages/bruno-app/src/themes/light.js b/packages/bruno-app/src/themes/light.js
index 6c7578dc..da6afd73 100644
--- a/packages/bruno-app/src/themes/light.js
+++ b/packages/bruno-app/src/themes/light.js
@@ -24,7 +24,7 @@ const lightTheme = {
bg: '#F3F3F3',
dragbar: 'rgb(200, 200, 200)',
- workspace: {
+ badge: {
bg: '#e1e1e1'
},
diff --git a/packages/bruno-app/src/utils/collections/export.js b/packages/bruno-app/src/utils/collections/export.js
index 579feaeb..43cc4f96 100644
--- a/packages/bruno-app/src/utils/collections/export.js
+++ b/packages/bruno-app/src/utils/collections/export.js
@@ -1,6 +1,37 @@
import * as FileSaver from 'file-saver';
+import get from 'lodash/get';
+import each from 'lodash/each';
+
+const deleteUidsInItems = (items) => {
+ each(items, (item) => {
+ delete item.uid;
+
+ if (['http-request', 'graphql-request'].includes(item.type)) {
+ each(get(item, 'request.headers'), (header) => delete header.uid);
+ each(get(item, 'request.params'), (param) => delete param.uid);
+ each(get(item, 'request.body.multipartForm'), (param) => delete param.uid);
+ each(get(item, 'request.body.formUrlEncoded'), (param) => delete param.uid);
+ }
+
+ if (item.items && item.items.length) {
+ deleteUidsInItems(item.items);
+ }
+ });
+};
+
+const deleteUidsInEnvs = (envs) => {
+ each(envs, (env) => {
+ delete env.uid;
+ each(env.variables, (variable) => delete variable.uid);
+ });
+};
const exportCollection = (collection) => {
+ // delete uids
+ delete collection.uid;
+ deleteUidsInItems(collection.items);
+ deleteUidsInEnvs(collection.environments);
+
const fileName = `${collection.name}.json`;
const fileBlob = new Blob([JSON.stringify(collection, null, 2)], { type: 'application/json' });
diff --git a/packages/bruno-app/src/utils/common/cache.js b/packages/bruno-app/src/utils/common/cache.js
index 88517f20..d8cee9e5 100644
--- a/packages/bruno-app/src/utils/common/cache.js
+++ b/packages/bruno-app/src/utils/common/cache.js
@@ -5,14 +5,6 @@ class Cache {
set(key, val) {
window.localStorage.setItem(key, val);
}
-
- getActiveWorkspaceUid() {
- return this.get('bruno.activeWorkspaceUid');
- }
-
- setActiveWorkspaceUid(workspaceUid) {
- this.set('bruno.activeWorkspaceUid', workspaceUid);
- }
}
module.exports = new Cache();
diff --git a/packages/bruno-app/src/utils/idb/index.js b/packages/bruno-app/src/utils/idb/index.js
index 8e066668..28ef2790 100644
--- a/packages/bruno-app/src/utils/idb/index.js
+++ b/packages/bruno-app/src/utils/idb/index.js
@@ -13,20 +13,6 @@ export const saveCollectionToIdb = (connection, collection) => {
});
};
-export const deleteCollectionInIdb = (connection, collectionUid) => {
- return new Promise((resolve, reject) => {
- connection
- .then((db) => {
- let tx = db.transaction(`collection`, 'readwrite');
- tx.objectStore('collection').delete(collectionUid);
-
- tx.oncomplete = () => resolve(collectionUid);
- tx.onerror = () => reject(tx.error);
- })
- .catch((err) => reject(err));
- });
-};
-
export const getCollectionsFromIdb = (connection) => {
return new Promise((resolve, reject) => {
connection
diff --git a/packages/bruno-app/src/utils/idb/workspaces.js b/packages/bruno-app/src/utils/idb/workspaces.js
deleted file mode 100644
index 29be46db..00000000
--- a/packages/bruno-app/src/utils/idb/workspaces.js
+++ /dev/null
@@ -1,59 +0,0 @@
-import isArray from 'lodash/isArray';
-
-export const saveWorkspaceToIdb = (connection, workspace) => {
- return new Promise((resolve, reject) => {
- connection
- .then((db) => {
- let tx = db.transaction(`workspace`, 'readwrite');
- let workspaceStore = tx.objectStore('workspace');
-
- if (isArray(workspace)) {
- for (let c of workspace) {
- workspaceStore.put(c);
- }
- } else {
- workspaceStore.put(workspace);
- }
-
- return new Promise((res, rej) => {
- tx.oncomplete = () => res();
- tx.onerror = () => rej(tx.error);
- });
- })
- .then(resolve)
- .catch((err) => reject(err));
- });
-};
-
-export const deleteWorkspaceInIdb = (connection, workspaceUid) => {
- return new Promise((resolve, reject) => {
- connection
- .then((db) => {
- let tx = db.transaction(`workspace`, 'readwrite');
- tx.objectStore('workspace').delete(workspaceUid);
-
- tx.oncomplete = () => resolve();
- tx.onerror = () => reject(tx.error);
- })
- .catch((err) => reject(err));
- });
-};
-
-export const getWorkspacesFromIdb = (connection) => {
- return new Promise((resolve, reject) => {
- connection
- .then((db) => {
- let tx = db.transaction('workspace');
- let workspaceStore = tx.objectStore('workspace');
- return workspaceStore.getAll();
- })
- .then((workspaces) => {
- if (!Array.isArray(workspaces)) {
- return new Error('IDB Corrupted');
- }
-
- return resolve(workspaces);
- })
- .catch((err) => reject(err));
- });
-};
diff --git a/packages/bruno-app/src/utils/importers/bruno-collection.js b/packages/bruno-app/src/utils/importers/bruno-collection.js
index 847b2f61..019314d5 100644
--- a/packages/bruno-app/src/utils/importers/bruno-collection.js
+++ b/packages/bruno-app/src/utils/importers/bruno-collection.js
@@ -1,8 +1,6 @@
import fileDialog from 'file-dialog';
-import { saveCollectionToIdb } from 'utils/idb';
import { BrunoError } from 'utils/common/error';
import { validateSchema, updateUidsInCollection } from './common';
-import sampleCollection from './samples/sample-collection.json';
const readFile = (files) => {
return new Promise((resolve, reject) => {
@@ -30,10 +28,8 @@ const importCollection = () => {
fileDialog({ accept: 'application/json' })
.then(readFile)
.then(parseJsonCollection)
- .then(validateSchema)
.then(updateUidsInCollection)
.then(validateSchema)
- .then((collection) => saveCollectionToIdb(window.__idb, collection))
.then((collection) => resolve(collection))
.catch((err) => {
console.log(err);
@@ -42,15 +38,4 @@ const importCollection = () => {
});
};
-export const importSampleCollection = () => {
- return new Promise((resolve, reject) => {
- validateSchema(sampleCollection)
- .then(updateUidsInCollection)
- .then(validateSchema)
- .then((collection) => saveCollectionToIdb(window.__idb, collection))
- .then(resolve)
- .catch(reject);
- });
-};
-
export default importCollection;
diff --git a/packages/bruno-app/src/utils/importers/common.js b/packages/bruno-app/src/utils/importers/common.js
index eee7108f..e9995b73 100644
--- a/packages/bruno-app/src/utils/importers/common.js
+++ b/packages/bruno-app/src/utils/importers/common.js
@@ -40,5 +40,14 @@ export const updateUidsInCollection = (_collection) => {
};
updateItemUids(collection.items);
+ const updateEnvUids = (envs = []) => {
+ each(envs, (env) => {
+ env.uid = uuid();
+ each(env.variables, (variable) => (variable.uid = uuid()));
+ });
+ };
+ updateEnvUids(collection.environments);
+ updateEnvUids(collection.environments);
+
return collection;
};
diff --git a/packages/bruno-app/src/utils/importers/postman-collection.js b/packages/bruno-app/src/utils/importers/postman-collection.js
index e0976dd7..23265f55 100644
--- a/packages/bruno-app/src/utils/importers/postman-collection.js
+++ b/packages/bruno-app/src/utils/importers/postman-collection.js
@@ -2,7 +2,6 @@ import each from 'lodash/each';
import get from 'lodash/get';
import fileDialog from 'file-dialog';
import { uuid } from 'utils/common';
-import { saveCollectionToIdb } from 'utils/idb';
import { BrunoError } from 'utils/common/error';
import { validateSchema, updateUidsInCollection } from './common';
@@ -180,9 +179,6 @@ const importCollection = () => {
.then(readFile)
.then(parsePostmanCollection)
.then(validateSchema)
- .then(updateUidsInCollection)
- .then(validateSchema)
- .then((collection) => saveCollectionToIdb(window.__idb, collection))
.then((collection) => resolve(collection))
.catch((err) => {
console.log(err);
diff --git a/packages/bruno-app/src/utils/importers/samples/sample-collection.json b/packages/bruno-app/src/utils/importers/samples/sample-collection.json
deleted file mode 100644
index 51468b5e..00000000
--- a/packages/bruno-app/src/utils/importers/samples/sample-collection.json
+++ /dev/null
@@ -1,129 +0,0 @@
-{
- "name": "sample-collection",
- "uid": "c1PdISj460OeNmFLI8rCY",
- "version": "1",
- "items": [
- {
- "uid": "myeFbgzNlwIhDpYcOVBWS",
- "type": "http-request",
- "name": "Users",
- "request": {
- "url": "https://reqres.in/api/users?page=2",
- "method": "GET",
- "headers": [],
- "params": [
- {
- "uid": "viHGWSpAQhpiwH9UQxb7W",
- "name": "page",
- "value": "2",
- "enabled": true
- }
- ],
- "body": {
- "mode": "json",
- "json": "",
- "text": null,
- "xml": null,
- "formUrlEncoded": [],
- "multipartForm": []
- }
- }
- },
- {
- "uid": "ytzXIADbhEwLB0BqIQOKD",
- "type": "http-request",
- "name": "Single User",
- "request": {
- "url": "https://reqres.in/api/users/2",
- "method": "GET",
- "headers": [],
- "params": [],
- "body": {
- "mode": "json",
- "json": "",
- "text": null,
- "xml": null,
- "formUrlEncoded": [],
- "multipartForm": []
- }
- }
- },
- {
- "uid": "DuEyHudhVuxrdplKLAMsU",
- "type": "http-request",
- "name": "User Not Found",
- "request": {
- "url": "https://reqres.in/api/users/23",
- "method": "GET",
- "headers": [],
- "params": [],
- "body": {
- "mode": "json",
- "json": "",
- "text": null,
- "xml": null,
- "formUrlEncoded": [],
- "multipartForm": []
- }
- }
- },
- {
- "uid": "UZFjsr14q8iZ1Do90q02Q",
- "type": "http-request",
- "name": "Create",
- "request": {
- "url": "https://reqres.in/api/users",
- "method": "POST",
- "headers": [],
- "params": [],
- "body": {
- "mode": "json",
- "json": "{\n \"name\": \"morpheus\",\n \"job\": \"leader\"\n}",
- "text": null,
- "xml": null,
- "formUrlEncoded": [],
- "multipartForm": []
- }
- }
- },
- {
- "uid": "lYLCTXaerD9etRDLJHbVN",
- "type": "http-request",
- "name": "Update",
- "request": {
- "url": "https://reqres.in/api/users/2",
- "method": "PUT",
- "headers": [],
- "params": [],
- "body": {
- "mode": "json",
- "json": "{\n \"name\": \"morpheus\",\n \"job\": \"zion resident\"\n}",
- "text": null,
- "xml": null,
- "formUrlEncoded": [],
- "multipartForm": []
- }
- }
- },
- {
- "uid": "qVCKx5xUqxpBf8jeka8Gu",
- "type": "http-request",
- "name": "Remove",
- "request": {
- "url": "https://reqres.in/api/users/2",
- "method": "DELETE",
- "headers": [],
- "params": [],
- "body": {
- "mode": "json",
- "json": "{\n \"name\": \"morpheus\",\n \"job\": \"zion resident\"\n}",
- "text": null,
- "xml": null,
- "formUrlEncoded": [],
- "multipartForm": []
- }
- }
- }
- ],
- "environments": []
-}
diff --git a/packages/bruno-app/src/utils/workspaces/index.js b/packages/bruno-app/src/utils/workspaces/index.js
deleted file mode 100644
index 77f56a03..00000000
--- a/packages/bruno-app/src/utils/workspaces/index.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import find from 'lodash/find';
-
-export const findCollectionInWorkspace = (workspace, collectionUid) => {
- return find(workspace.collections, (c) => c.uid === collectionUid);
-};
diff --git a/packages/bruno-electron/src/app/collections.js b/packages/bruno-electron/src/app/collections.js
index 04dfd58f..870b1f5e 100644
--- a/packages/bruno-electron/src/app/collections.js
+++ b/packages/bruno-electron/src/app/collections.js
@@ -5,13 +5,14 @@ const Yup = require('yup');
const { isDirectory, normalizeAndResolvePath } = require('../utils/filesystem');
const { generateUidBasedOnHash } = require('../utils/common');
+// uid inside collections is deprecated, but we still need to validate it
+// for backward compatibility
const uidSchema = Yup.string()
.length(21, 'uid must be 21 characters in length')
- .matches(/^[a-zA-Z0-9]*$/, 'uid must be alphanumeric')
- .required('uid is required')
- .strict();
+ .matches(/^[a-zA-Z0-9]*$/, 'uid must be alphanumeric');
const configSchema = Yup.object({
+ uid: uidSchema,
name: Yup.string().nullable().max(256, 'name must be 256 characters or less'),
type: Yup.string().oneOf(['collection']).required('type is required'),
version: Yup.string().oneOf(['1']).required('type is required')
diff --git a/packages/bruno-electron/src/app/watcher.js b/packages/bruno-electron/src/app/watcher.js
index 1a53c497..c156a62e 100644
--- a/packages/bruno-electron/src/app/watcher.js
+++ b/packages/bruno-electron/src/app/watcher.js
@@ -5,17 +5,27 @@ const chokidar = require('chokidar');
const { hasJsonExtension, hasBruExtension, writeFile } = require('../utils/filesystem');
const {
bruToJson,
- jsonToBru
+ jsonToBru,
+ bruToEnvJson,
+ envJsonToBru,
} = require('@usebruno/bruno-lang');
const { itemSchema } = require('@usebruno/schema');
const { generateUidBasedOnHash, uuid } = require('../utils/common');
-const isEnvironmentConfig = (pathname, collectionPath) => {
+const isJsonEnvironmentConfig = (pathname, collectionPath) => {
const dirname = path.dirname(pathname);
const basename = path.basename(pathname);
return dirname === collectionPath && basename === 'environments.json';
-}
+};
+
+const isBruEnvironmentConfig = (pathname, collectionPath) => {
+ const dirname = path.dirname(pathname);
+ const envDirectory = path.join(collectionPath, 'environments');
+ const basename = path.basename(pathname);
+
+ return dirname === envDirectory && hasBruExtension(basename);
+};
const hydrateRequestWithUuid = (request, pathname) => {
request.uid = generateUidBasedOnHash(pathname);
@@ -35,16 +45,21 @@ const hydrateRequestWithUuid = (request, pathname) => {
const addEnvironmentFile = async (win, pathname, collectionUid) => {
try {
+ const basename = path.basename(pathname);
const file = {
meta: {
collectionUid,
pathname,
- name: path.basename(pathname),
- }
+ name: basename
+ },
};
- const jsonData = fs.readFileSync(pathname, 'utf8');
- file.data = JSON.parse(jsonData);
+ const bruContent = fs.readFileSync(pathname, 'utf8');
+ file.data = bruToEnvJson(bruContent);
+ file.data.name = basename.substring(0, basename.length - 4);
+ file.data.uid = generateUidBasedOnHash(pathname);
+
+ _.each(_.get(file, 'data.variables', []), (variable) => variable.uid = uuid());
win.webContents.send('main:collection-tree-updated', 'addEnvironmentFile', file);
} catch (err) {
console.error(err)
@@ -53,17 +68,25 @@ const addEnvironmentFile = async (win, pathname, collectionUid) => {
const changeEnvironmentFile = async (win, pathname, collectionUid) => {
try {
+ const basename = path.basename(pathname);
const file = {
meta: {
collectionUid,
pathname,
- name: path.basename(pathname),
+ name: basename
}
};
- const jsonData = fs.readFileSync(pathname, 'utf8');
- file.data = JSON.parse(jsonData);
- win.webContents.send('main:collection-tree-updated', 'changeEnvironmentFile', file);
+ const bruContent = fs.readFileSync(pathname, 'utf8');
+ file.data = bruToEnvJson(bruContent);
+ file.data.name = basename.substring(0, basename.length - 4);
+ file.data.uid = generateUidBasedOnHash(pathname);
+ _.each(_.get(file, 'data.variables', []), (variable) => variable.uid = uuid());
+
+ // we are reusing the addEnvironmentFile event itself
+ // this is because the uid of the pathname remains the same
+ // and the collection tree will be able to update the existing environment
+ win.webContents.send('main:collection-tree-updated', 'addEnvironmentFile', file);
} catch (err) {
console.error(err)
}
@@ -77,23 +100,49 @@ const unlinkEnvironmentFile = async (win, pathname, collectionUid) => {
pathname,
name: path.basename(pathname),
},
- data: []
+ data: {
+ uid: generateUidBasedOnHash(pathname),
+ name: path.basename(pathname).substring(0, path.basename(pathname).length - 4),
+ }
};
- win.webContents.send('main:collection-tree-updated', 'changeEnvironmentFile', file);
+ win.webContents.send('main:collection-tree-updated', 'unlinkEnvironmentFile', file);
} catch (err) {
console.error(err)
}
};
const add = async (win, pathname, collectionUid, collectionPath) => {
- const isJson = hasJsonExtension(pathname);
console.log(`watcher add: ${pathname}`);
- if(isJson) {
- if(isEnvironmentConfig(pathname, collectionPath)) {
- return addEnvironmentFile(win, pathname, collectionUid);
+ if(isJsonEnvironmentConfig(pathname, collectionPath)) {
+ // migrate old env json to bru file
+ try {
+ const dirname = path.dirname(pathname);
+ const jsonStr = fs.readFileSync(pathname, 'utf8');
+ const jsonData = JSON.parse(jsonStr);
+
+ const envDirectory = path.join(dirname, 'environments');
+ if (!fs.existsSync(envDirectory)) {
+ fs.mkdirSync(envDirectory);
+ }
+
+ for(const env of jsonData) {
+ const bruEnvFilename = path.join(envDirectory, `${env.name}.bru`);
+ const bruContent = envJsonToBru(env);
+ await writeFile(bruEnvFilename, bruContent);
+ }
+
+ await fs.unlinkSync(pathname);
+ } catch (err) {
+ // do nothing
}
+
+ return;
+ }
+
+ if(isBruEnvironmentConfig(pathname, collectionPath)) {
+ return addEnvironmentFile(win, pathname, collectionUid);
}
// migrate old json files to bru
@@ -137,8 +186,14 @@ const add = async (win, pathname, collectionUid, collectionPath) => {
}
};
-const addDirectory = (win, pathname, collectionUid) => {
- console.log(`watcher addDirectory: ${pathname}`);
+const addDirectory = (win, pathname, collectionUid, collectionPath) => {
+ const dirname = path.dirname(pathname);
+ const envDirectory = path.join(collectionPath, 'environments');
+
+ if(dirname === envDirectory) {
+ return;
+ }
+
const directory = {
meta: {
collectionUid,
@@ -150,9 +205,7 @@ const addDirectory = (win, pathname, collectionUid) => {
};
const change = async (win, pathname, collectionUid, collectionPath) => {
- console.log(`watcher change: ${pathname}`);
-
- if(isEnvironmentConfig(pathname, collectionPath)) {
+ if(isBruEnvironmentConfig(pathname, collectionPath)) {
return changeEnvironmentFile(win, pathname, collectionUid);
}
@@ -178,7 +231,7 @@ const change = async (win, pathname, collectionUid, collectionPath) => {
};
const unlink = (win, pathname, collectionUid, collectionPath) => {
- if(isEnvironmentConfig(pathname, collectionPath)) {
+ if(isBruEnvironmentConfig(pathname, collectionPath)) {
return unlinkEnvironmentFile(win, pathname, collectionUid);
}
@@ -195,6 +248,13 @@ const unlink = (win, pathname, collectionUid, collectionPath) => {
}
const unlinkDir = (win, pathname, collectionUid) => {
+ const dirname = path.dirname(pathname);
+ const envDirectory = path.join(collectionPath, 'environments');
+
+ if(dirname === envDirectory) {
+ return;
+ }
+
const directory = {
meta: {
collectionUid,
diff --git a/packages/bruno-electron/src/ipc/local-collection.js b/packages/bruno-electron/src/ipc/local-collection.js
index 9cae43ef..918d7aa0 100644
--- a/packages/bruno-electron/src/ipc/local-collection.js
+++ b/packages/bruno-electron/src/ipc/local-collection.js
@@ -5,6 +5,7 @@ const { ipcMain } = require('electron');
const {
jsonToBru,
bruToJson,
+ envJsonToBru,
} = require('@usebruno/bruno-lang');
const {
isValidPathname,
@@ -16,6 +17,7 @@ const {
} = require('../utils/filesystem');
const { uuid, stringifyJson } = require('../utils/common');
const { openCollectionDialog, openCollection } = require('../app/collections');
+const { generateUidBasedOnHash } = require('../utils/common');
const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollections) => {
// browse directory
@@ -43,10 +45,9 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
await createDirectory(dirPath);
- const uid = uuid();
+ const uid = generateUidBasedOnHash(dirPath);
const content = await stringifyJson({
version: '1',
- uid: uid,
name: collectionName,
type: 'collection'
});
@@ -89,18 +90,83 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
}
});
- // save environment
- ipcMain.handle('renderer:save-environment', async (event, collectionPathname, environments) => {
+ // create environment
+ ipcMain.handle('renderer:create-environment', async (event, collectionPathname, name) => {
try {
- const envFilePath = path.join(collectionPathname, 'environments.json');
+ const envDirPath = path.join(collectionPathname, 'environments');
+ if (!fs.existsSync(envDirPath)){
+ await createDirectory(envDirPath);
+ }
- const content = await stringifyJson(environments);
+ const envFilePath = path.join(envDirPath, `${name}.bru`);
+ if (fs.existsSync(envFilePath)){
+ throw new Error(`environment: ${envFilePath} already exists`);
+ }
+
+ const content = envJsonToBru({
+ variables: []
+ });
await writeFile(envFilePath, content);
} catch (error) {
return Promise.reject(error);
}
});
+ // save environment
+ ipcMain.handle('renderer:save-environment', async (event, collectionPathname, environment) => {
+ try {
+ const envDirPath = path.join(collectionPathname, 'environments');
+ if (!fs.existsSync(envDirPath)){
+ await createDirectory(envDirPath);
+ }
+
+ const envFilePath = path.join(envDirPath, `${environment.name}.bru`);
+ if (!fs.existsSync(envFilePath)){
+ throw new Error(`environment: ${envFilePath} does not exist`);
+ }
+
+ const content = envJsonToBru(environment);
+ await writeFile(envFilePath, content);
+ } catch (error) {
+ return Promise.reject(error);
+ }
+ });
+
+ // rename environment
+ ipcMain.handle('renderer:rename-environment', async (event, collectionPathname, environmentName, newName) => {
+ try {
+ const envDirPath = path.join(collectionPathname, 'environments');
+ const envFilePath = path.join(envDirPath, `${environmentName}.bru`);
+ if (!fs.existsSync(envFilePath)){
+ throw new Error(`environment: ${envFilePath} does not exist`);
+ }
+
+ const newEnvFilePath = path.join(envDirPath, `${newName}.bru`);
+ if (fs.existsSync(newEnvFilePath)){
+ throw new Error(`environment: ${newEnvFilePath} already exists`);
+ }
+
+ fs.renameSync(envFilePath, newEnvFilePath);
+ } catch (error) {
+ return Promise.reject(error);
+ }
+ });
+
+ // delete environment
+ ipcMain.handle('renderer:delete-environment', async (event, collectionPathname, environmentName) => {
+ try {
+ const envDirPath = path.join(collectionPathname, 'environments');
+ const envFilePath = path.join(envDirPath, `${environmentName}.bru`);
+ if (!fs.existsSync(envFilePath)){
+ throw new Error(`environment: ${envFilePath} does not exist`);
+ }
+
+ fs.unlinkSync(envFilePath);
+ } catch (error) {
+ return Promise.reject(error);
+ }
+ });
+
// rename item
ipcMain.handle('renderer:rename-item', async (event, oldPath, newPath, newName) => {
try {
@@ -177,6 +243,71 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
}
});
+ ipcMain.handle('renderer:import-collection', async (event, collection, collectionLocation) => {
+ try {
+ let collectionName = collection.name;
+ let collectionPath = path.join(collectionLocation, collectionName);
+
+ if (fs.existsSync(collectionPath)){
+ throw new Error(`collection: ${collectionPath} already exists`);
+ }
+
+ // Recursive function to parse the collection items and create files/folders
+ const parseCollectionItems = (items = [], currentPath) => {
+ items.forEach(item => {
+ if (item.type === 'http-request') {
+ const content = jsonToBru(item);
+ const filePath = path.join(currentPath, `${item.name}.bru`);
+ fs.writeFileSync(filePath, content);
+ }
+ if (item.type === 'folder') {
+ const folderPath = path.join(currentPath, item.name);
+ fs.mkdirSync(folderPath);
+
+ if(item.items && item.items.length) {
+ parseCollectionItems(item.items, folderPath);
+ }
+ }
+ });
+ };
+
+ const parseEnvironments = (environments = [], collectionPath) => {
+ const envDirPath = path.join(collectionPath, 'environments');
+ if(!fs.existsSync(envDirPath)){
+ fs.mkdirSync(envDirPath);
+ }
+
+ environments.forEach(env => {
+ const content = envJsonToBru(env);
+ const filePath = path.join(envDirPath, `${env.name}.bru`);
+ fs.writeFileSync(filePath, content);
+ });
+ };
+
+ await createDirectory(collectionPath);
+
+ const uid = generateUidBasedOnHash(collectionPath);
+ const content = await stringifyJson({
+ version: '1',
+ name: collection.name,
+ type: 'collection'
+ });
+ await writeFile(path.join(collectionPath, 'bruno.json'), content);
+
+ mainWindow.webContents.send('main:collection-opened', collectionPath, uid, collectionName);
+ ipcMain.emit('main:collection-opened', mainWindow, collectionPath, uid);
+
+ lastOpenedCollections.add(collectionPath);
+
+ // create folder and files based on collection
+ await parseCollectionItems(collection.items, collectionPath);
+ await parseEnvironments(collection.environments, collectionPath);
+
+ } catch (error) {
+ return Promise.reject(error);
+ }
+ });
+
ipcMain.handle('renderer:ready', async (event) => {
// reload last opened collections
const lastOpened = lastOpenedCollections.getAll();
diff --git a/packages/bruno-lang/src/body-tag.js b/packages/bruno-lang/src/body-tag.js
index 0dfbc338..ccc1caec 100644
--- a/packages/bruno-lang/src/body-tag.js
+++ b/packages/bruno-lang/src/body-tag.js
@@ -63,15 +63,16 @@ const bodyXmlTag = between(bodyXmlBegin)(bodyEnd)(everyCharUntil(bodyEnd)).map((
// generic key value parser
const newline = regex(/^\r?\n/);
const newLineOrEndOfInput = choice([newline, endOfInput]);
-const word = regex(/^[^\s\t\n]+/g);
+const wordWithoutWhitespace = regex(/^[^\s\t\n]+/g);
+const wordWithWhitespace = regex(/^[^\n]+/g);
const line = sequenceOf([
optionalWhitespace,
digit,
whitespace,
- word,
+ wordWithoutWhitespace,
whitespace,
- word,
+ wordWithWhitespace,
newLineOrEndOfInput
]).map(([_, enabled, __, key, ___, value]) => {
return {
diff --git a/packages/bruno-lang/src/env-vars-tag.js b/packages/bruno-lang/src/env-vars-tag.js
new file mode 100644
index 00000000..3b81cff7
--- /dev/null
+++ b/packages/bruno-lang/src/env-vars-tag.js
@@ -0,0 +1,47 @@
+const {
+ sequenceOf,
+ whitespace,
+ optionalWhitespace,
+ choice,
+ endOfInput,
+ between,
+ digit,
+ many,
+ regex,
+ sepBy
+} = require("arcsecond");
+
+const newline = regex(/^\r?\n/);
+const newLineOrEndOfInput = choice([newline, endOfInput]);
+
+const begin = regex(/^vars\s*\r?\n/);
+const end = regex(/^[\r?\n]*\/vars\s*[\r?\n]*/);
+const wordWithoutWhitespace = regex(/^[^\s\t\n]+/g);
+const wordWithWhitespace = regex(/^[^\n]+/g);
+
+const line = sequenceOf([
+ optionalWhitespace,
+ digit,
+ whitespace,
+ wordWithoutWhitespace,
+ whitespace,
+ wordWithWhitespace,
+ newLineOrEndOfInput
+]).map(([_, enabled, __, key, ___, value]) => {
+ return {
+ "enabled": Number(enabled) ? true : false,
+ "name": key,
+ "value": value,
+ "type": "text"
+ };
+});
+
+const lines = many(line);
+const envVarsLines = sepBy(newline)(lines);
+const envVarsTag = between(begin)(end)(envVarsLines).map(([variables]) => {
+ return {
+ variables
+ };
+});
+
+module.exports = envVarsTag;
diff --git a/packages/bruno-lang/src/headers-tag.js b/packages/bruno-lang/src/headers-tag.js
index e9d1f394..825daf69 100644
--- a/packages/bruno-lang/src/headers-tag.js
+++ b/packages/bruno-lang/src/headers-tag.js
@@ -16,15 +16,16 @@ const newLineOrEndOfInput = choice([newline, endOfInput]);
const begin = regex(/^headers\s*\r?\n/);
const end = regex(/^[\r?\n]*\/headers\s*[\r?\n]*/);
-const word = regex(/^[^\s\t\n]+/g);
+const wordWithoutWhitespace = regex(/^[^\s\t\n]+/g);
+const wordWithWhitespace = regex(/^[^\n]+/g);
const line = sequenceOf([
optionalWhitespace,
digit,
whitespace,
- word,
+ wordWithoutWhitespace,
whitespace,
- word,
+ wordWithWhitespace,
newLineOrEndOfInput
]).map(([_, enabled, __, key, ___, value]) => {
return {
diff --git a/packages/bruno-lang/src/index.js b/packages/bruno-lang/src/index.js
index 715be190..2258262e 100644
--- a/packages/bruno-lang/src/index.js
+++ b/packages/bruno-lang/src/index.js
@@ -51,7 +51,7 @@ const bruToJson = (fileContents) => {
headers: parsed.headers || [],
body: parsed.body || {mode: 'none'}
}
- }
+ };
const body = get(json, 'request.body');
@@ -161,7 +161,47 @@ ${body.multipartForm.map(item => ` ${item.enabled ? 1 : 0} ${item.name} ${item.
return bru;
};
+// env
+const envVarsTag = require('./env-vars-tag');
+
+const bruToEnvJson = (fileContents) => {
+ const parser = many(choice([
+ envVarsTag,
+ anyChar
+ ]));
+
+ const parsed = parser
+ .run(fileContents)
+ .result
+ .reduce((acc, item) => _.merge(acc, item), {});
+
+ const json = {
+ variables: parsed.variables || []
+ };
+
+ return json;
+};
+
+const envJsonToBru = (json) => {
+ const {
+ variables
+ } = json;
+
+ let bru = '';
+
+ if(variables && variables.length) {
+ bru += `vars
+${variables.map(item => ` ${item.enabled ? 1 : 0} ${item.name} ${item.value}`).join('\n')}
+/vars
+`;
+ }
+
+ return bru;
+};
+
module.exports = {
bruToJson,
- jsonToBru
+ jsonToBru,
+ bruToEnvJson,
+ envJsonToBru
};
\ No newline at end of file
diff --git a/packages/bruno-lang/src/params-tag.js b/packages/bruno-lang/src/params-tag.js
index ac025baf..f5696262 100644
--- a/packages/bruno-lang/src/params-tag.js
+++ b/packages/bruno-lang/src/params-tag.js
@@ -17,15 +17,16 @@ const newLineOrEndOfInput = choice([newline, endOfInput]);
const begin = regex(/^params\s*\r?\n/);
const end = regex(/^[\r?\n]*\/params\s*[\r?\n]*/);
-const word = regex(/^[^\s\t\n]+/g);
+const wordWithoutWhitespace = regex(/^[^\s\t\n]+/g);
+const wordWithWhitespace = regex(/^[^\n]+/g);
const line = sequenceOf([
optionalWhitespace,
digit,
whitespace,
- word,
+ wordWithoutWhitespace,
whitespace,
- word,
+ wordWithWhitespace,
newLineOrEndOfInput
]).map(([_, enabled, __, key, ___, value]) => {
return {
diff --git a/packages/bruno-lang/tests/bru-to-env-json.spec.js b/packages/bruno-lang/tests/bru-to-env-json.spec.js
new file mode 100644
index 00000000..67d633b5
--- /dev/null
+++ b/packages/bruno-lang/tests/bru-to-env-json.spec.js
@@ -0,0 +1,33 @@
+const fs = require('fs');
+const path = require('path');
+
+const {
+ bruToEnvJson
+} = require('../src');
+
+describe('bruToEnvJson', () => {
+ it('should parse .bru file contents', () => {
+ const requestFile = fs.readFileSync(path.join(__dirname, 'fixtures', 'env.bru'), 'utf8');
+ const result = bruToEnvJson(requestFile);
+
+ expect(result).toEqual({
+ "variables": [{
+ "enabled": true,
+ "name": "host",
+ "value": "https://www.google.com",
+ "type": "text"
+ }, {
+ "enabled": true,
+ "name": "jwt",
+ "value": "secret",
+ "type": "text"
+ }, {
+ "enabled": false,
+ "name": "Content-type",
+ "value": "application/json",
+ "type": "text"
+ }]
+ });
+ });
+});
+
diff --git a/packages/bruno-lang/tests/env-json-to-bru.spec.js b/packages/bruno-lang/tests/env-json-to-bru.spec.js
new file mode 100644
index 00000000..ea96beb2
--- /dev/null
+++ b/packages/bruno-lang/tests/env-json-to-bru.spec.js
@@ -0,0 +1,35 @@
+const fs = require('fs');
+const path = require('path');
+
+const {
+ envJsonToBru
+} = require('../src');
+
+describe('envJsonToBru', () => {
+ it('should convert json file into .bru file', () => {
+ const env = {
+ "variables": [{
+ "enabled": true,
+ "name": "host",
+ "value": "https://www.google.com",
+ "type": "text"
+ }, {
+ "enabled": true,
+ "name": "jwt",
+ "value": "secret",
+ "type": "text"
+ }, {
+ "enabled": false,
+ "name": "Content-type",
+ "value": "application/json",
+ "type": "text"
+ }]
+ };
+
+ const expectedBruFile = fs.readFileSync(path.join(__dirname, 'fixtures', 'env.bru'), 'utf8');
+ const actualBruFile = envJsonToBru(env);
+
+ expect(expectedBruFile).toEqual(actualBruFile);
+ });
+});
+
diff --git a/packages/bruno-lang/tests/fixtures/env.bru b/packages/bruno-lang/tests/fixtures/env.bru
new file mode 100644
index 00000000..bea55e9b
--- /dev/null
+++ b/packages/bruno-lang/tests/fixtures/env.bru
@@ -0,0 +1,5 @@
+vars
+ 1 host https://www.google.com
+ 1 jwt secret
+ 0 Content-type application/json
+/vars
diff --git a/packages/bruno-schema/src/collections/index.js b/packages/bruno-schema/src/collections/index.js
index e4481e6b..22494d52 100644
--- a/packages/bruno-schema/src/collections/index.js
+++ b/packages/bruno-schema/src/collections/index.js
@@ -12,7 +12,7 @@ const environmentVariablesSchema = Yup.object({
const environmentSchema = Yup.object({
uid: uidSchema,
- name: Yup.string().min(1).max(50, 'name must be 50 characters or less').required('name is required'),
+ name: Yup.string().min(1).max(50, 'name must be 100 characters or less').required('name is required'),
variables: Yup.array().of(environmentVariablesSchema).required('variables are required')
}).noUnknown(true).strict();
@@ -91,6 +91,7 @@ const collectionSchema = Yup.object({
module.exports = {
requestSchema,
itemSchema,
+ environmentSchema,
environmentsSchema,
collectionSchema
};
\ No newline at end of file
diff --git a/packages/bruno-schema/src/index.js b/packages/bruno-schema/src/index.js
index bfede823..ad25aaad 100644
--- a/packages/bruno-schema/src/index.js
+++ b/packages/bruno-schema/src/index.js
@@ -1,8 +1,9 @@
const { workspaceSchema } = require("./workspaces");
-const { collectionSchema, itemSchema, environmentsSchema } = require("./collections");
+const { collectionSchema, itemSchema, environmentSchema, environmentsSchema } = require("./collections");
module.exports = {
itemSchema,
+ environmentSchema,
environmentsSchema,
collectionSchema,
workspaceSchema