feat: environment configuration (resolves #8)

This commit is contained in:
Anusree Subash 2022-10-16 01:15:36 +05:30
parent 008704c4e1
commit 4a5378a2e1
12 changed files with 355 additions and 8 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -1,10 +1,12 @@
import React, { useRef, forwardRef } from 'react'; import React, { useRef, forwardRef, useState } from 'react';
import Dropdown from 'components/Dropdown'; import Dropdown from 'components/Dropdown';
import { IconAdjustmentsHorizontal, IconCaretDown } from '@tabler/icons'; import { IconAdjustmentsHorizontal, IconCaretDown } from '@tabler/icons';
import EnvironmentSettings from "./EnvironmentSettings";
import StyledWrapper from './StyledWrapper'; import StyledWrapper from './StyledWrapper';
const EnvironmentSelector = () => { const EnvironmentSelector = () => {
const dropdownTippyRef = useRef(); const dropdownTippyRef = useRef();
const [openSettingsModal, setOpenSettingsModal] = useState(false);
const Icon = forwardRef((props, ref) => { const Icon = forwardRef((props, ref) => {
return ( return (
@ -36,9 +38,7 @@ const EnvironmentSelector = () => {
}}> }}>
<span>No Environment</span> <span>No Environment</span>
</div> </div>
<div className="dropdown-item" style={{borderTop: 'solid 1px #e7e7e7'}} onClick={() => { <div className="dropdown-item" style={{borderTop: 'solid 1px #e7e7e7'}} onClick={() => setOpenSettingsModal(true)}>
dropdownTippyRef.current.hide();
}}>
<div className="pr-2 text-gray-600"> <div className="pr-2 text-gray-600">
<IconAdjustmentsHorizontal size={18} strokeWidth={1.5}/> <IconAdjustmentsHorizontal size={18} strokeWidth={1.5}/>
</div> </div>
@ -46,6 +46,7 @@ const EnvironmentSelector = () => {
</div> </div>
</Dropdown> </Dropdown>
</div> </div>
{openSettingsModal && <EnvironmentSettings onClose={() => setOpenSettingsModal(false)}/>}
</StyledWrapper> </StyledWrapper>
); );
}; };

View File

@ -18,10 +18,14 @@ const ModalContent = ({children}) => (
</div> </div>
); );
const ModalFooter = ({confirmText, cancelText, handleSubmit, handleCancel, confirmDisabled, hideCancel}) => { const ModalFooter = ({confirmText, cancelText, handleSubmit, handleCancel, confirmDisabled, hideCancel, hideFooter}) => {
confirmText = confirmText || 'Save'; confirmText = confirmText || 'Save';
cancelText = cancelText || 'Cancel'; cancelText = cancelText || 'Cancel';
if (hideFooter) {
return null;
}
return ( return (
<div className="flex justify-end p-4 bruno-modal-footer"> <div className="flex justify-end p-4 bruno-modal-footer">
<span className={hideCancel ? "hidden" : "mr-2"}> <span className={hideCancel ? "hidden" : "mr-2"}>
@ -47,7 +51,8 @@ const Modal = ({
handleConfirm, handleConfirm,
children, children,
confirmDisabled, confirmDisabled,
hideCancel hideCancel,
hideFooter
}) => { }) => {
const [isClosing, setIsClosing] = useState(false); const [isClosing, setIsClosing] = useState(false);
const escFunction = (event) => { const escFunction = (event) => {
@ -86,6 +91,7 @@ const Modal = ({
handleSubmit={handleConfirm} handleSubmit={handleConfirm}
confirmDisabled={confirmDisabled} confirmDisabled={confirmDisabled}
hideCancel={hideCancel} hideCancel={hideCancel}
hideFooter={hideFooter}
/> />
</div> </div>
<div className="bruno-modal-backdrop" onClick={() => closeModal()} /> <div className="bruno-modal-backdrop" onClick={() => closeModal()} />

View File

@ -47,7 +47,7 @@ const AddWorkspace = ({onClose}) => {
> >
<form className="bruno-form" onSubmit={formik.handleSubmit}> <form className="bruno-form" onSubmit={formik.handleSubmit}>
<div> <div>
<label htmlFor="name" className="block font-semibold">Workpsace Name</label> <label htmlFor="name" className="block font-semibold">Workspace Name</label>
<input <input
id="workspace-name" type="text" name="name" id="workspace-name" type="text" name="name"
ref={inputRef} ref={inputRef}

View File

@ -47,7 +47,7 @@ const EditWorkspace = ({onClose, workspace}) => {
> >
<form className="bruno-form" onSubmit={formik.handleSubmit}> <form className="bruno-form" onSubmit={formik.handleSubmit}>
<div> <div>
<label htmlFor="name" className="block font-semibold">Workpsace Name</label> <label htmlFor="name" className="block font-semibold">Workspace Name</label>
<input <input
id="workspace-name" type="text" name="name" id="workspace-name" type="text" name="name"
ref={inputRef} ref={inputRef}