change(ui): projects revamp - project form
This commit is contained in:
parent
c329d47c7f
commit
9374c98669
4 changed files with 174 additions and 14 deletions
148
frontend/app/components/Client/Projects/ProjectForm.tsx
Normal file
148
frontend/app/components/Client/Projects/ProjectForm.tsx
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
import React, { ChangeEvent, FormEvent, useEffect } from 'react';
|
||||
import styles from 'Components/Client/Sites/siteForm.module.css';
|
||||
import { Icon } from 'UI';
|
||||
import Project from '@/mstore/types/project';
|
||||
import { projectStore, useStore } from '@/mstore';
|
||||
import { Modal, Segmented, Form, Input, Button } from 'antd';
|
||||
import { toast } from 'react-toastify';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
interface Props {
|
||||
project?: Project;
|
||||
onClose?: (arg: any) => void;
|
||||
}
|
||||
|
||||
function ProjectForm(props: Props) {
|
||||
const { onClose } = props;
|
||||
const { projectsStore } = useStore();
|
||||
const project = projectsStore.instance as Project;
|
||||
const loading = projectsStore.loading;
|
||||
const canDelete = projectsStore.list.length > 1;
|
||||
const pathname = window.location.pathname;
|
||||
|
||||
useEffect(() => {
|
||||
if (props.project && props.project.id) {
|
||||
projectsStore.initProject(props.project);
|
||||
} else {
|
||||
projectsStore.initProject({});
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleEdit = ({ target: { name, value } }: ChangeEvent<HTMLInputElement>) => {
|
||||
projectsStore.editInstance({ [name]: value });
|
||||
};
|
||||
|
||||
const onSubmit = (e: FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (!projectsStore.instance) return;
|
||||
if (projectsStore.instance.id && projectsStore.instance.exists()) {
|
||||
projectsStore
|
||||
.updateProject(projectsStore.instance.id, project)
|
||||
.then((response: any) => {
|
||||
if (!response || !response.errors || response.errors.size === 0) {
|
||||
if (onClose) {
|
||||
onClose(null);
|
||||
}
|
||||
if (!pathname.includes('onboarding')) {
|
||||
void projectsStore.fetchList();
|
||||
}
|
||||
toast.success('Project updated successfully');
|
||||
} else {
|
||||
toast.error(response.errors[0]);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
projectsStore.save(projectsStore.instance!).then((response: any) => {
|
||||
if (!response || !response.errors || response.errors.size === 0) {
|
||||
if (onClose) {
|
||||
onClose(null);
|
||||
}
|
||||
// searchStore.clearSearch();
|
||||
// mstore.searchStoreLive.clearSearch();
|
||||
// mstore.initClient();
|
||||
toast.success('Project added successfully');
|
||||
} else {
|
||||
toast.error(response.errors[0]);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemove = async () => {
|
||||
Modal.confirm({
|
||||
title: 'Project Deletion Alert',
|
||||
content: 'Are you sure you want to delete this project? Deleting it will permanently remove the project, along with all associated sessions and data.',
|
||||
onOk: () => {
|
||||
projectsStore.removeProject(project.id!).then(() => {
|
||||
if (onClose) {
|
||||
onClose(null);
|
||||
}
|
||||
if (project.id === projectsStore.active?.id) {
|
||||
projectsStore.setSiteId(projectStore.list[0].id!);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Form onFinish={project.validate ? onSubmit : () => null}>
|
||||
<div className={styles.content}>
|
||||
<Form.Item>
|
||||
<label>{'Name'}</label>
|
||||
<Input
|
||||
placeholder="Ex. OpenReplay"
|
||||
name="name"
|
||||
maxLength={40}
|
||||
value={project.name}
|
||||
onChange={handleEdit}
|
||||
className={styles.input}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<label>Project Type</label>
|
||||
<div>
|
||||
<Segmented
|
||||
options={[
|
||||
{
|
||||
value: 'web',
|
||||
label: 'Web'
|
||||
},
|
||||
{
|
||||
value: 'ios',
|
||||
label: 'Mobile'
|
||||
}
|
||||
]}
|
||||
value={project.platform}
|
||||
onChange={(value) => {
|
||||
projectsStore.editInstance({ platform: value });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Form.Item>
|
||||
<div className="mt-6 flex justify-between">
|
||||
<Button
|
||||
htmlType="submit"
|
||||
type="primary"
|
||||
className="float-left mr-2"
|
||||
loading={loading}
|
||||
disabled={!project.validate}
|
||||
>
|
||||
{project.exists() ? 'Update' : 'Add'}
|
||||
</Button>
|
||||
{project.exists() && (
|
||||
<Button
|
||||
variant="text"
|
||||
onClick={handleRemove}
|
||||
disabled={!canDelete}
|
||||
>
|
||||
<Icon name="trash" size="16" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
export default observer(ProjectForm);
|
||||
|
|
@ -21,7 +21,12 @@ function ProjectList() {
|
|||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<Input.Search placeholder="Search" onSearch={onSearch} />
|
||||
<Input.Search
|
||||
placeholder="Search"
|
||||
onSearch={onSearch}
|
||||
onClear={() => setSearch('')}
|
||||
allowClear
|
||||
/>
|
||||
<List
|
||||
dataSource={list.filter((item) => item.name.toLowerCase().includes(search.toLowerCase()))}
|
||||
renderItem={(item: Project) => (
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
import React from 'react';
|
||||
import { Tabs } from 'antd';
|
||||
import { Tabs, TabsProps } from 'antd';
|
||||
import { useStore } from '@/mstore';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
const customTabBar: TabsProps['renderTabBar'] = (props, DefaultTabBar) => (
|
||||
<DefaultTabBar {...props} className="!mb-0" />
|
||||
);
|
||||
|
||||
function ProjectTabs() {
|
||||
const { projectsStore } = useStore();
|
||||
const activeTab = projectsStore.config.tab;
|
||||
|
|
@ -22,14 +26,14 @@ function ProjectTabs() {
|
|||
return (
|
||||
<Tabs
|
||||
type="line"
|
||||
defaultActiveKey="installation"
|
||||
defaultActiveKey={tabItems[0].key}
|
||||
activeKey={activeTab}
|
||||
style={{ borderBottom: 'none' }}
|
||||
onChange={onTabChange}
|
||||
renderTabBar={customTabBar}
|
||||
items={tabItems.map((tab) => ({
|
||||
key: tab.key,
|
||||
label: tab.label
|
||||
// children: tab.content,
|
||||
}))}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@ import { useStore } from '@/mstore';
|
|||
import { observer } from 'mobx-react-lite';
|
||||
import { PlusIcon } from 'lucide-react';
|
||||
import ProjectTabContent from 'Components/Client/Projects/ProjectTabContent';
|
||||
import NewSiteForm from 'Components/Client/Sites/NewSiteForm';
|
||||
import { useModal } from 'Components/ModalContext';
|
||||
import ProjectForm from 'Components/Client/Projects/ProjectForm';
|
||||
import Project from '@/mstore/types/project';
|
||||
|
||||
function Projects() {
|
||||
const { projectsStore } = useStore();
|
||||
|
|
@ -37,7 +38,7 @@ function Projects() {
|
|||
}, [pid, tab]);
|
||||
|
||||
const createProject = () => {
|
||||
openModal(<NewSiteForm onClose={closeModal} />, {
|
||||
openModal(<ProjectForm onClose={closeModal} project={new Project()} />, {
|
||||
title: 'New Project'
|
||||
});
|
||||
};
|
||||
|
|
@ -52,23 +53,25 @@ function Projects() {
|
|||
style={{ height: 'calc(100vh - 140px)' }}
|
||||
extra={
|
||||
<Space>
|
||||
<Button type="primary" onClick={createProject} icon={<PlusIcon />}>
|
||||
<Button onClick={createProject} icon={<PlusIcon />}>
|
||||
Create Project
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<Row className="items-stretch">
|
||||
<Col span={6} className="border-r !p-4">
|
||||
<ProjectList />
|
||||
<Row className="h-full">
|
||||
<Col span={6} className="border-r !p-4 flex flex-col">
|
||||
<div className="flex-1 !overflow-y-auto">
|
||||
<ProjectList />
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={18} className="!p-4 !overflow-hidden">
|
||||
<Space className="flex justify-between">
|
||||
<Col span={18} className="!p-4 flex flex-col">
|
||||
<Space className="flex justify-between">
|
||||
<Typography.Title level={5} className="capitalize !m-0">{project?.name}</Typography.Title>
|
||||
<ProjectTabs />
|
||||
</Space>
|
||||
<Divider />
|
||||
<div className="!overflow-y-auto">
|
||||
<Divider style={{ margin: '0px' }} />
|
||||
<div className="flex-1 !overflow-y-auto my-4">
|
||||
{project && <ProjectTabContent />}
|
||||
</div>
|
||||
</Col>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue