-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(ui): implemented ui for env management table
- Loading branch information
Showing
7 changed files
with
661 additions
and
0 deletions.
There are no files selected for viewing
127 changes: 127 additions & 0 deletions
127
frontend/components/basic/dialog/AddEnvironmentDialog.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import { FormEventHandler, Fragment, useEffect, useState } from 'react'; | ||
import { Dialog, Transition } from '@headlessui/react'; | ||
|
||
import Button from '../buttons/Button'; | ||
import InputField from '../InputField'; | ||
|
||
type FormFields = { name: string; slug: string }; | ||
|
||
type Props = { | ||
isOpen?: boolean; | ||
isEditMode?: boolean; | ||
// on edit mode load up initial values | ||
initialValues?: FormFields; | ||
onClose: () => void; | ||
onSubmit: (envName: string, envSlug: string) => void; | ||
}; | ||
|
||
/** | ||
* The dialog modal for when the user wants to create a new workspace | ||
* @param {*} param0 | ||
* @returns | ||
*/ | ||
export const AddEnvironmentDialog = ({ isOpen, onClose, onSubmit, initialValues, isEditMode }: Props) => { | ||
const [formInput, setFormInput] = useState<FormFields>({ | ||
name: '', | ||
slug: '', | ||
}); | ||
|
||
// This use effect can be removed when the unmount is happening from outside the component | ||
// When unmount happens outside state gets unmounted also | ||
useEffect(() => { | ||
setFormInput(initialValues || { name: '', slug: '' }); | ||
}, [isOpen]); | ||
|
||
// REFACTOR: Move to react-hook-form with yup for better form management | ||
const onInputChange = (fieldName: string, fieldValue: string) => { | ||
setFormInput((state) => ({ ...state, [fieldName]: fieldValue })); | ||
}; | ||
|
||
const onFormSubmit: FormEventHandler = (e) => { | ||
e.preventDefault(); | ||
console.log(formInput); | ||
}; | ||
|
||
return ( | ||
<div> | ||
<Transition appear show={isOpen} as={Fragment}> | ||
<Dialog as='div' className='relative z-20' onClose={onClose}> | ||
<Transition.Child | ||
as={Fragment} | ||
enter='ease-out duration-300' | ||
enterFrom='opacity-0' | ||
enterTo='opacity-100' | ||
leave='ease-out duration-150' | ||
leaveFrom='opacity-100' | ||
leaveTo='opacity-0' | ||
> | ||
<div className='fixed inset-0 bg-black bg-opacity-70' /> | ||
</Transition.Child> | ||
|
||
<div className='fixed inset-0 overflow-y-auto z-50'> | ||
<div className='flex min-h-full items-center justify-center p-4 text-center'> | ||
<Transition.Child | ||
as={Fragment} | ||
enter='ease-out duration-300' | ||
enterFrom='opacity-0 scale-95' | ||
enterTo='opacity-100 scale-100' | ||
leave='ease-in duration-200' | ||
leaveFrom='opacity-100 scale-100' | ||
leaveTo='opacity-0 scale-95' | ||
> | ||
<Dialog.Panel className='w-full max-w-md transform overflow-hidden rounded-2xl bg-bunker-800 border border-gray-700 p-6 text-left align-middle shadow-xl transition-all'> | ||
<Dialog.Title | ||
as='h3' | ||
className='text-lg font-medium leading-6 text-gray-400' | ||
> | ||
{isEditMode | ||
? 'Update environment' | ||
: 'Create a new environment'} | ||
</Dialog.Title> | ||
<form onSubmit={onFormSubmit}> | ||
<div className='max-h-28 mt-4'> | ||
<InputField | ||
label='Project Name' | ||
onChangeHandler={(val) => onInputChange('name', val)} | ||
type='varName' | ||
value={formInput.name} | ||
placeholder='' | ||
isRequired | ||
// error={error.length > 0} | ||
// errorText={error} | ||
/> | ||
</div> | ||
<div className='max-h-28 mt-4'> | ||
<InputField | ||
label='Environment Slug' | ||
onChangeHandler={(val) => onInputChange('slug', val)} | ||
type='varName' | ||
value={formInput.slug} | ||
placeholder='' | ||
isRequired | ||
// error={error.length > 0} | ||
// errorText={error} | ||
/> | ||
</div> | ||
<p className='text-xs text-gray-500 mt-2'> | ||
Slugs are shorthands used in cli to access environment | ||
</p> | ||
<div className='mt-4 max-w-min'> | ||
<Button | ||
onButtonPressed={() => null} | ||
type='submit' | ||
color='mineshaft' | ||
text={isEditMode ? 'Update' : 'Create'} | ||
size='md' | ||
/> | ||
</div> | ||
</form> | ||
</Dialog.Panel> | ||
</Transition.Child> | ||
</div> | ||
</div> | ||
</Dialog> | ||
</Transition> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import { Fragment, useState } from 'react'; | ||
import { Dialog, Transition } from '@headlessui/react'; | ||
|
||
import InputField from '../InputField'; | ||
|
||
// REFACTOR: Move all these modals into one reusable one | ||
type Props = { | ||
isOpen?: boolean; | ||
onClose: ()=>void; | ||
title: string; | ||
onSubmit:()=>void; | ||
deleteKey?:string; | ||
} | ||
|
||
const DeleteActionModal = ({ | ||
isOpen, | ||
onClose, | ||
title, | ||
onSubmit, | ||
deleteKey | ||
}:Props) => { | ||
const [deleteInputField, setDeleteInputField] = useState("") | ||
|
||
return ( | ||
<div> | ||
<Transition appear show={isOpen} as={Fragment}> | ||
<Dialog as='div' className='relative z-10' onClose={onClose}> | ||
<Transition.Child | ||
as={Fragment} | ||
enter='ease-out duration-300' | ||
enterFrom='opacity-0' | ||
enterTo='opacity-100' | ||
leave='ease-in duration-150' | ||
leaveFrom='opacity-100' | ||
leaveTo='opacity-0' | ||
> | ||
<div className='fixed inset-0 bg-black bg-opacity-25' /> | ||
</Transition.Child> | ||
<div className='fixed inset-0 overflow-y-auto'> | ||
<div className='flex min-h-full items-center justify-center p-4 text-center'> | ||
<Transition.Child | ||
as={Fragment} | ||
enter='ease-out duration-300' | ||
enterFrom='opacity-0 scale-95' | ||
enterTo='opacity-100 scale-100' | ||
leave='ease-in duration-200' | ||
leaveFrom='opacity-100 scale-100' | ||
leaveTo='opacity-0 scale-95' | ||
> | ||
<Dialog.Panel className='w-full max-w-md transform overflow-hidden rounded-2xl bg-grey border border-gray-700 p-6 text-left align-middle shadow-xl transition-all'> | ||
<Dialog.Title | ||
as='h3' | ||
className='text-lg font-medium leading-6 text-gray-400' | ||
> | ||
{title} | ||
</Dialog.Title> | ||
<div className='mt-2'> | ||
<p className='text-sm text-gray-500'> | ||
This action is irrevertible. | ||
</p> | ||
</div> | ||
<div className='mt-2'> | ||
<InputField | ||
isRequired | ||
label={`Type ${deleteKey} to delete the resource`} | ||
onChangeHandler={(val) => setDeleteInputField(val)} | ||
value={deleteInputField} | ||
type='text' | ||
/> | ||
</div> | ||
<div className='mt-6'> | ||
<button | ||
type='button' | ||
className='inline-flex justify-center rounded-md border border-transparent bg-gray-800 px-4 py-2 text-sm font-medium text-gray-400 hover:bg-alizarin hover:text-white hover:text-semibold duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2' | ||
onClick={onSubmit} | ||
disabled={ | ||
Boolean(deleteKey) && deleteInputField !== deleteKey | ||
} | ||
> | ||
Delete | ||
</button> | ||
<button | ||
type='button' | ||
className='ml-2 inline-flex justify-center rounded-md border border-transparent bg-gray-800 px-4 py-2 text-sm font-medium text-gray-400 hover:border-white hover:text-white hover:text-semibold duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2' | ||
onClick={onClose} | ||
> | ||
Cancel | ||
</button> | ||
</div> | ||
</Dialog.Panel> | ||
</Transition.Child> | ||
</div> | ||
</div> | ||
</Dialog> | ||
</Transition> | ||
</div> | ||
); | ||
}; | ||
|
||
export default DeleteActionModal; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
import { faPencil,faPlus,faX } from '@fortawesome/free-solid-svg-icons'; | ||
|
||
import { usePopUp } from '../../../hooks/usePopUp'; | ||
import Button from '../buttons/Button'; | ||
import {AddEnvironmentDialog} from '../dialog/AddEnvironmentDialog'; | ||
import DeleteActionModal from '../dialog/DeleteActionModal'; | ||
|
||
const EnvironmentTable = ({ data = [] }) => { | ||
const { popUp, handlePopUpOpen, handlePopUpClose } = usePopUp([ | ||
'createUpdateEnv', | ||
'deleteEnv', | ||
] as const); | ||
|
||
return ( | ||
<> | ||
<div className='flex flex-row justify-between w-full'> | ||
<div className='flex flex-col w-full'> | ||
<p className='text-xl font-semibold mb-3'>Project Environments</p> | ||
<p className='text-base text-gray-400 mb-4'> | ||
Choose which environments will show up in your dashboard like | ||
development, staging, production | ||
</p> | ||
<p className='text-sm mr-1 text-gray-500 self-start'> | ||
Note: the text in slugs shows how these environmant should be | ||
accessed in CLI. | ||
</p> | ||
</div> | ||
<div className='w-48'> | ||
<Button | ||
text='Add New Env' | ||
onButtonPressed={() => handlePopUpOpen('createUpdateEnv')} | ||
color='mineshaft' | ||
icon={faPlus} | ||
size='md' | ||
/> | ||
</div> | ||
</div> | ||
<div className='table-container w-full bg-bunker rounded-md mb-6 border border-mineshaft-700 relative mt-1'> | ||
<div className='absolute rounded-t-md w-full h-12 bg-white/5'></div> | ||
<table className='w-full my-1'> | ||
<thead className='text-bunker-300'> | ||
<tr> | ||
<th className='text-left pl-6 pt-2.5 pb-2'>Name</th> | ||
<th className='text-left pl-6 pt-2.5 pb-2'>Slug</th> | ||
<th></th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{data?.length > 0 ? ( | ||
data.map(({ name, slug }) => { | ||
return ( | ||
<tr | ||
key={name} | ||
className='bg-bunker-800 hover:bg-bunker-800/5 duration-100' | ||
> | ||
<td className='pl-6 py-2 border-mineshaft-700 border-t text-gray-300 capitalize'> | ||
{name} | ||
</td> | ||
<td className='pl-6 py-2 border-mineshaft-700 border-t text-gray-300'> | ||
{slug} | ||
</td> | ||
<td className='py-2 border-mineshaft-700 border-t flex'> | ||
<div className='opacity-50 hover:opacity-100 duration-200 flex items-center mr-8'> | ||
<Button | ||
onButtonPressed={() => handlePopUpOpen("createUpdateEnv",{ name, slug })} | ||
color='red' | ||
size='icon-sm' | ||
icon={faPencil} | ||
/> | ||
</div> | ||
<div className='opacity-50 hover:opacity-100 duration-200 flex items-center'> | ||
<Button | ||
onButtonPressed={() => | ||
handlePopUpOpen('deleteEnv', { name, slug }) | ||
} | ||
color='red' | ||
size='icon-sm' | ||
icon={faX} | ||
/> | ||
</div> | ||
</td> | ||
</tr> | ||
); | ||
}) | ||
) : ( | ||
<tr> | ||
<td | ||
colSpan={4} | ||
className='text-center pt-7 pb-4 text-bunker-400' | ||
> | ||
No environmants found | ||
</td> | ||
</tr> | ||
)} | ||
</tbody> | ||
</table> | ||
<DeleteActionModal | ||
isOpen={popUp['deleteEnv'].isOpen} | ||
title={`Are you sure want to delete ${ | ||
(popUp?.deleteEnv?.data as { name: string })?.name || ' ' | ||
}?`} | ||
deleteKey={(popUp?.deleteEnv?.data as { slug: string })?.slug || ''} | ||
onClose={() => handlePopUpClose('deleteEnv')} | ||
onSubmit={() => handlePopUpClose('deleteEnv')} | ||
/> | ||
<AddEnvironmentDialog | ||
isOpen={popUp.createUpdateEnv.isOpen} | ||
isEditMode={Boolean(popUp.createUpdateEnv?.data)} | ||
initialValues={popUp?.createUpdateEnv?.data as any} | ||
onClose={() => handlePopUpClose('createUpdateEnv')} | ||
onSubmit={() => null} | ||
/> | ||
</div> | ||
</> | ||
); | ||
}; | ||
|
||
export default EnvironmentTable; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { usePopUp } from './usePopUp'; |
Oops, something went wrong.