mirror of
https://github.com/usebruno/bruno.git
synced 2024-11-25 01:14:23 +01:00
feat: environment configuration (resolves #8)
This commit is contained in:
parent
008704c4e1
commit
4a5378a2e1
@ -0,0 +1,70 @@
|
||||
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';
|
||||
import * as Yup from 'yup';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
const CreateEnvironment = ({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({name: values.name}));
|
||||
// onClose();
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if(inputRef && inputRef.current) {
|
||||
inputRef.current.focus();
|
||||
}
|
||||
}, [inputRef]);
|
||||
|
||||
const onSubmit = () => {
|
||||
formik.handleSubmit();
|
||||
}
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<Modal
|
||||
size="sm"
|
||||
title={"Create Environment"}
|
||||
confirmText='Create'
|
||||
handleConfirm={onSubmit}
|
||||
handleCancel={onClose}
|
||||
>
|
||||
<form className="bruno-form" onSubmit={formik.handleSubmit}>
|
||||
<div>
|
||||
<label htmlFor="name" className="block font-semibold">Environment Name</label>
|
||||
<input
|
||||
id="environment-name" type="text" name="name"
|
||||
ref={inputRef}
|
||||
className="block textbox mt-2 w-full"
|
||||
autoComplete="off" autoCorrect="off" autoCapitalize="off" spellCheck="false"
|
||||
onChange={formik.handleChange}
|
||||
value={formik.values.name || ''}
|
||||
/>
|
||||
{formik.touched.name && formik.errors.name ? (
|
||||
<div className="text-red-500">{formik.errors.name}</div>
|
||||
) : null}
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
</Portal>
|
||||
);
|
||||
}
|
||||
|
||||
export default CreateEnvironment;
|
||||
|
@ -0,0 +1,15 @@
|
||||
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;
|
@ -0,0 +1,34 @@
|
||||
import React from 'react';
|
||||
import Portal from "components/Portal/index";
|
||||
import Modal from "components/Modal/index";
|
||||
// import { deleteWorkspace } from 'providers/ReduxStore/slices/workspaces';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const DeleteEnvironment = ({onClose, environment}) => {
|
||||
const dispatch = useDispatch();
|
||||
const onConfirm = () =>{
|
||||
// dispatch(deleteWorkspace({workspaceUid: workspace.uid}))
|
||||
onClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<StyledWrapper>
|
||||
<Modal
|
||||
size="sm"
|
||||
title={"Delete Environment"}
|
||||
confirmText="Delete"
|
||||
handleConfirm={onConfirm}
|
||||
handleCancel={onClose}
|
||||
>
|
||||
Are you sure you want to delete <span className="font-semibold">{environment.name}</span> ?
|
||||
</Modal>
|
||||
</StyledWrapper>
|
||||
</Portal>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
export default DeleteEnvironment;
|
||||
|
@ -0,0 +1,25 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { IconEdit, IconTrash } from "@tabler/icons";
|
||||
import RenameEnvironment from "../../RenameEnvironment";
|
||||
import DeleteEnvironment from "../../DeleteEnvironment";
|
||||
// import StyledWrapper from "./StyledWrapper";
|
||||
|
||||
const EnvironmentDetails = ({selected}) => {
|
||||
const [ openEditModal, setOpenEditModal] = useState(false);
|
||||
const [ openDeleteModal, setOpenDeleteModal] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="ml-10 flex-grow flex pt-4" style={{maxWidth: '700px'}}>
|
||||
<span>{selected.name}</span>
|
||||
<div className="flex gap-x-4 pl-4" >
|
||||
<IconEdit className="cursor-pointer" size={20} strokeWidth={1.5} onClick={() => setOpenEditModal(true)}/>
|
||||
<IconTrash className="cursor-pointer" size={20} strokeWidth={1.5} onClick={() => setOpenDeleteModal(true)}/>
|
||||
</div>
|
||||
{openEditModal && <RenameEnvironment onClose={() => setOpenEditModal(false)} environment={selected} />}
|
||||
{openDeleteModal && <DeleteEnvironment onClose={() => setOpenDeleteModal(false)} environment={selected} />}
|
||||
</div>
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
export default EnvironmentDetails;
|
@ -0,0 +1,43 @@
|
||||
import styled from "styled-components";
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
margin-left: -1rem;
|
||||
margin-block: -1.5rem;
|
||||
.environments-sidebar {
|
||||
margin-bottom: 8px;
|
||||
background-color: #ffffff;
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
.environment-item {
|
||||
min-width: 150px;
|
||||
display: block;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
padding: 8px 10px;
|
||||
color: rgb(35, 35, 35);
|
||||
border-bottom: 1px solid #eaecef;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
background-color: #f6f8fa;
|
||||
}
|
||||
}
|
||||
|
||||
.active {
|
||||
background-color: #e1e4e8;
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
background-color: #e1e4e8;
|
||||
}
|
||||
}
|
||||
|
||||
.create-env {
|
||||
padding: 8px 10px;
|
||||
cursor: pointer;
|
||||
border-bottom: none;
|
||||
color: var(--color-text-link);
|
||||
}
|
||||
`;
|
||||
|
||||
export default StyledWrapper;
|
@ -0,0 +1,40 @@
|
||||
import React, { useEffect, useState, forwardRef, useRef } from "react";
|
||||
import EnvironmentDetails from "./EnvironmentDetails";
|
||||
import CreateEnvironment from "../CreateEnvironment/index";
|
||||
import StyledWrapper from "./StyledWrapper";
|
||||
|
||||
const environments = [
|
||||
{name: "My env", uid: 123},
|
||||
{name: "hjdgfh dj", uid: 3876},
|
||||
{name: "hjdgfer dj", uid: 4678},
|
||||
];
|
||||
|
||||
const Layout = () => {
|
||||
const [selectedEnvironment, setSelectedEnvironment] = useState({});
|
||||
const [openCreateModal, setOpenCreateModal] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedEnvironment(environments[0]);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<div className="flex">
|
||||
<div style={{borderRight: "1px solid #ccc"}}>
|
||||
<div className="environments-sidebar">
|
||||
{environments && environments.length && environments.map((env) => (
|
||||
<div className={selectedEnvironment.uid === env.uid ? "environment-item active": "environment-item"} onClick={() => setSelectedEnvironment(env)}>
|
||||
<span>{env.name}</span>
|
||||
</div>
|
||||
))}
|
||||
<p className="create-env" onClick={() => setOpenCreateModal(true)}> + Create</p>
|
||||
</div>
|
||||
</div>
|
||||
<EnvironmentDetails selected={selectedEnvironment}/>
|
||||
</div>
|
||||
{openCreateModal && <CreateEnvironment onClose={() => setOpenCreateModal(false)}/>}
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default Layout;
|
@ -0,0 +1,70 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import Portal from "components/Portal/index";
|
||||
import Modal from "components/Modal/index";
|
||||
import { useFormik } from 'formik';
|
||||
// import { rename } from 'providers/ReduxStore/slices/environments';
|
||||
import * as Yup from 'yup';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
const RenameEnvironment = ({onClose, environment}) => {
|
||||
// const dispatch = useDispatch();
|
||||
const inputRef = useRef();
|
||||
const formik = useFormik({
|
||||
enableReinitialize: true,
|
||||
initialValues: {
|
||||
name: environment.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(rename({name: values.name, uid: environment.uid}));
|
||||
onClose();
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if(inputRef && inputRef.current) {
|
||||
inputRef.current.focus();
|
||||
}
|
||||
}, [inputRef]);
|
||||
|
||||
const onSubmit = () => {
|
||||
formik.handleSubmit();
|
||||
}
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<Modal
|
||||
size="sm"
|
||||
title={"Rename Environment"}
|
||||
confirmText='Rename'
|
||||
handleConfirm={onSubmit}
|
||||
handleCancel={onClose}
|
||||
>
|
||||
<form className="bruno-form" onSubmit={formik.handleSubmit}>
|
||||
<div>
|
||||
<label htmlFor="name" className="block font-semibold">Environment Name</label>
|
||||
<input
|
||||
id="environment-name" type="text" name="name"
|
||||
ref={inputRef}
|
||||
className="block textbox mt-2 w-full"
|
||||
autoComplete="off" autoCorrect="off" autoCapitalize="off" spellCheck="false"
|
||||
onChange={formik.handleChange}
|
||||
value={formik.values.name || ''}
|
||||
/>
|
||||
{formik.touched.name && formik.errors.name ? (
|
||||
<div className="text-red-500">{formik.errors.name}</div>
|
||||
) : null}
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
</Portal>
|
||||
);
|
||||
}
|
||||
|
||||
export default RenameEnvironment;
|
||||
|
@ -0,0 +1,43 @@
|
||||
import Modal from "components/Modal/index";
|
||||
import React, { useState } from "react";
|
||||
import CreateEnvironment from "./CreateEnvironment";
|
||||
import Layout from "./Layout";
|
||||
|
||||
const EnvironmentSettings = ({onClose}) => {
|
||||
const environments = [
|
||||
{name: "My env", uid: 123},
|
||||
{name: "hjdgfh dj", uid: 3876},
|
||||
];
|
||||
const [openCreateModal, setOpenCreateModal] = useState(false)
|
||||
|
||||
if(!environments.length) {
|
||||
return (
|
||||
<Modal
|
||||
size="lg"
|
||||
title="Environment"
|
||||
confirmText={"Close"}
|
||||
handleConfirm={onClose}
|
||||
hideCancel={true}
|
||||
>
|
||||
<p>No environment found!</p>
|
||||
<button className="btn-add-param text-link pr-2 py-3 mt-2 select-none" onClick={() => setOpenCreateModal(true)}>+ Create Environment</button>
|
||||
{openCreateModal && <CreateEnvironment onClose={() => setOpenCreateModal(false)}/>}
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
size="lg"
|
||||
title="Environment"
|
||||
confirmText={"Close"}
|
||||
handleCancel={onClose}
|
||||
hideFooter={true}
|
||||
>
|
||||
<Layout />
|
||||
</Modal>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
export default EnvironmentSettings;
|
@ -1,10 +1,12 @@
|
||||
import React, { useRef, forwardRef } from 'react';
|
||||
import React, { useRef, forwardRef, useState } from 'react';
|
||||
import Dropdown from 'components/Dropdown';
|
||||
import { IconAdjustmentsHorizontal, IconCaretDown } from '@tabler/icons';
|
||||
import EnvironmentSettings from "./EnvironmentSettings";
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const EnvironmentSelector = () => {
|
||||
const dropdownTippyRef = useRef();
|
||||
const [openSettingsModal, setOpenSettingsModal] = useState(false);
|
||||
|
||||
const Icon = forwardRef((props, ref) => {
|
||||
return (
|
||||
@ -36,9 +38,7 @@ const EnvironmentSelector = () => {
|
||||
}}>
|
||||
<span>No Environment</span>
|
||||
</div>
|
||||
<div className="dropdown-item" style={{borderTop: 'solid 1px #e7e7e7'}} onClick={() => {
|
||||
dropdownTippyRef.current.hide();
|
||||
}}>
|
||||
<div className="dropdown-item" style={{borderTop: 'solid 1px #e7e7e7'}} onClick={() => setOpenSettingsModal(true)}>
|
||||
<div className="pr-2 text-gray-600">
|
||||
<IconAdjustmentsHorizontal size={18} strokeWidth={1.5}/>
|
||||
</div>
|
||||
@ -46,6 +46,7 @@ const EnvironmentSelector = () => {
|
||||
</div>
|
||||
</Dropdown>
|
||||
</div>
|
||||
{openSettingsModal && <EnvironmentSettings onClose={() => setOpenSettingsModal(false)}/>}
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
@ -18,10 +18,14 @@ const ModalContent = ({children}) => (
|
||||
</div>
|
||||
);
|
||||
|
||||
const ModalFooter = ({confirmText, cancelText, handleSubmit, handleCancel, confirmDisabled, hideCancel}) => {
|
||||
const ModalFooter = ({confirmText, cancelText, handleSubmit, handleCancel, confirmDisabled, hideCancel, hideFooter}) => {
|
||||
confirmText = confirmText || 'Save';
|
||||
cancelText = cancelText || 'Cancel';
|
||||
|
||||
if (hideFooter) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex justify-end p-4 bruno-modal-footer">
|
||||
<span className={hideCancel ? "hidden" : "mr-2"}>
|
||||
@ -47,7 +51,8 @@ const Modal = ({
|
||||
handleConfirm,
|
||||
children,
|
||||
confirmDisabled,
|
||||
hideCancel
|
||||
hideCancel,
|
||||
hideFooter
|
||||
}) => {
|
||||
const [isClosing, setIsClosing] = useState(false);
|
||||
const escFunction = (event) => {
|
||||
@ -86,6 +91,7 @@ const Modal = ({
|
||||
handleSubmit={handleConfirm}
|
||||
confirmDisabled={confirmDisabled}
|
||||
hideCancel={hideCancel}
|
||||
hideFooter={hideFooter}
|
||||
/>
|
||||
</div>
|
||||
<div className="bruno-modal-backdrop" onClick={() => closeModal()} />
|
||||
|
@ -47,7 +47,7 @@ const AddWorkspace = ({onClose}) => {
|
||||
>
|
||||
<form className="bruno-form" onSubmit={formik.handleSubmit}>
|
||||
<div>
|
||||
<label htmlFor="name" className="block font-semibold">Workpsace Name</label>
|
||||
<label htmlFor="name" className="block font-semibold">Workspace Name</label>
|
||||
<input
|
||||
id="workspace-name" type="text" name="name"
|
||||
ref={inputRef}
|
||||
|
@ -47,7 +47,7 @@ const EditWorkspace = ({onClose, workspace}) => {
|
||||
>
|
||||
<form className="bruno-form" onSubmit={formik.handleSubmit}>
|
||||
<div>
|
||||
<label htmlFor="name" className="block font-semibold">Workpsace Name</label>
|
||||
<label htmlFor="name" className="block font-semibold">Workspace Name</label>
|
||||
<input
|
||||
id="workspace-name" type="text" name="name"
|
||||
ref={inputRef}
|
||||
|
Loading…
Reference in New Issue
Block a user