Display searched project from different organization (#52)

* Refactor to remove use of organization project

* Remove organization project from member tab panel

* Handle review changes

---------

Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
Nabarun Gogoi 2024-01-30 17:24:40 +05:30 committed by Ashwin Phatak
parent 8bbe2583cb
commit 8ead083ab3
6 changed files with 32 additions and 118 deletions

View File

@ -1,28 +1,20 @@
import React, { useMemo } from 'react'; import React from 'react';
import { Project } from 'gql-client'; import { Project } from 'gql-client';
import { Typography, Button, Chip } from '@material-tailwind/react'; import { Typography, Button, Chip } from '@material-tailwind/react';
import ActivityCard from './ActivityCard'; import ActivityCard from './ActivityCard';
import activityDetails from '../../../assets/activities.json'; import activityDetails from '../../../assets/activities.json';
import { ProjectDetails } from '../../../types/project';
import { relativeTimeMs } from '../../../utils/time'; import { relativeTimeMs } from '../../../utils/time';
interface OverviewProps { interface OverviewProps {
project: Project; project: Project;
organizationProject: ProjectDetails;
} }
const OverviewTabPanel = ({ project, organizationProject }: OverviewProps) => { // TODO: Check any live domain is set for production branch
// TODO: Fetch current deployment const IS_DOMAIN_SETUP = true;
const currentDeploymentTitle = useMemo(() => {
const deployment = organizationProject?.deployments.find((deployment) => {
return deployment.isCurrent === true;
});
return deployment?.title;
}, [organizationProject]);
const OverviewTabPanel = ({ project }: OverviewProps) => {
return ( return (
<div className="grid grid-cols-5"> <div className="grid grid-cols-5">
<div className="col-span-3 p-2"> <div className="col-span-3 p-2">
@ -39,17 +31,24 @@ const OverviewTabPanel = ({ project, organizationProject }: OverviewProps) => {
<div className="flex justify-between p-2 text-sm items-center"> <div className="flex justify-between p-2 text-sm items-center">
<div> <div>
^ Domain ^ Domain
{!organizationProject.domain && ( {!IS_DOMAIN_SETUP && (
<Chip <Chip
className="normal-case ml-6 bg-[#FED7AA] text-[#EA580C] inline font-normal" className="normal-case ml-6 inline font-normal"
size="sm" size="sm"
value="Not connected" value="Not connected"
icon="^" icon="^"
color="orange"
/> />
)} )}
</div> </div>
{organizationProject.domain ? ( {IS_DOMAIN_SETUP ? (
<p>{organizationProject.domain}</p> <Chip
className="normal-case ml-6 inline font-normal"
size="sm"
value="Connected"
icon="^"
color="green"
/>
) : ( ) : (
<Button className="normal-case rounded-full" color="blue" size="sm"> <Button className="normal-case rounded-full" color="blue" size="sm">
Setup Setup
@ -58,11 +57,13 @@ const OverviewTabPanel = ({ project, organizationProject }: OverviewProps) => {
</div> </div>
<div className="flex justify-between p-2 text-sm"> <div className="flex justify-between p-2 text-sm">
<p>^ Source</p> <p>^ Source</p>
<p>{organizationProject.source}</p> <p>{project.deployments[0]?.branch}</p>
</div> </div>
<div className="flex justify-between p-2 text-sm"> <div className="flex justify-between p-2 text-sm">
<p>^ Deployment</p> <p>^ Deployment</p>
<p className="text-blue-600">{currentDeploymentTitle}</p> <p className="text-blue-600">
{project.deployments[0]?.domain?.name}
</p>
</div> </div>
<div className="flex justify-between p-2 text-sm"> <div className="flex justify-between p-2 text-sm">
<p>^ Created</p> <p>^ Created</p>

View File

@ -4,12 +4,10 @@ import { Project } from 'gql-client';
import OverviewTabPanel from './OverviewTabPanel'; import OverviewTabPanel from './OverviewTabPanel';
import DeploymentsTabPanel from './DeploymentsTabPanel'; import DeploymentsTabPanel from './DeploymentsTabPanel';
import { ProjectDetails } from '../../../types/project';
import SettingsTabPanel from './SettingsTabPanel'; import SettingsTabPanel from './SettingsTabPanel';
interface ProjectTabsProps { interface ProjectTabsProps {
project: Project; project: Project;
organizationProject: ProjectDetails;
onUpdate: () => Promise<void>; onUpdate: () => Promise<void>;
} }
@ -31,11 +29,7 @@ const Integrations = () => (
</div> </div>
); );
const ProjectTabs = ({ const ProjectTabs = ({ project, onUpdate }: ProjectTabsProps) => {
project,
onUpdate,
organizationProject,
}: ProjectTabsProps) => {
return ( return (
<Tabs <Tabs
selectedTabClassName={ selectedTabClassName={
@ -50,10 +44,7 @@ const ProjectTabs = ({
<Tab className={'p-2 cursor-pointer'}>Settings</Tab> <Tab className={'p-2 cursor-pointer'}>Settings</Tab>
</TabList> </TabList>
<TabPanel> <TabPanel>
<OverviewTabPanel <OverviewTabPanel project={project} />
project={project}
organizationProject={organizationProject}
/>
</TabPanel> </TabPanel>
<TabPanel> <TabPanel>
<DeploymentsTabPanel projectId={project.id} /> <DeploymentsTabPanel projectId={project.id} />

View File

@ -1,33 +1,21 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react'; import React, { useCallback, useEffect, useState } from 'react';
import { useOutletContext, useParams } from 'react-router-dom';
import toast, { Toaster } from 'react-hot-toast'; import toast, { Toaster } from 'react-hot-toast';
import { Project } from 'gql-client'; import { Project } from 'gql-client';
import { Chip, Button, Typography } from '@material-tailwind/react'; import { Chip, Button, Typography } from '@material-tailwind/react';
import MemberCard from './MemberCard'; import MemberCard from './MemberCard';
import { ProjectMember } from '../../../../types/project';
import {
ProjectMember,
ProjectSearchOutletContext,
} from '../../../../types/project';
import AddMemberDialog from './AddMemberDialog'; import AddMemberDialog from './AddMemberDialog';
import { useGQLClient } from '../../../../context/GQLClientContext'; import { useGQLClient } from '../../../../context/GQLClientContext';
const FIRST_MEMBER_CARD = 0; const FIRST_MEMBER_CARD = 0;
const MembersTabPanel = ({ project }: { project: Project }) => { const MembersTabPanel = ({ project }: { project: Project }) => {
const { id } = useParams();
const client = useGQLClient(); const client = useGQLClient();
const [addmemberDialogOpen, setAddMemberDialogOpen] = useState(false); const [addmemberDialogOpen, setAddMemberDialogOpen] = useState(false);
const { projects } = useOutletContext<ProjectSearchOutletContext>();
const currentProject = useMemo(() => {
return projects.find((project) => project.id === id);
}, [id]);
const [projectMembers, setProjectMembers] = useState<ProjectMember[]>([]); const [projectMembers, setProjectMembers] = useState<ProjectMember[]>([]);
const addMemberHandler = useCallback((projectMember: ProjectMember) => { const addMemberHandler = useCallback((projectMember: ProjectMember) => {
@ -36,14 +24,10 @@ const MembersTabPanel = ({ project }: { project: Project }) => {
}, []); }, []);
const fetchProjectMembers = useCallback(async () => { const fetchProjectMembers = useCallback(async () => {
if (currentProject) { const { projectMembers } = await client.getProjectMembers(project.id);
const { projectMembers } = await client.getProjectMembers(
currentProject.id,
);
setProjectMembers(projectMembers); setProjectMembers(projectMembers);
} }, [project.id]);
}, [currentProject]);
const removeMemberHandler = async (projectMemberId: string) => { const removeMemberHandler = async (projectMemberId: string) => {
const { removeMember: isMemberRemoved } = const { removeMember: isMemberRemoved } =
@ -59,7 +43,7 @@ const MembersTabPanel = ({ project }: { project: Project }) => {
useEffect(() => { useEffect(() => {
fetchProjectMembers(); fetchProjectMembers();
}, []); }, [project.id]);
return ( return (
<div className="p-2 mb-20"> <div className="p-2 mb-20">
@ -98,7 +82,7 @@ const MembersTabPanel = ({ project }: { project: Project }) => {
member={projectMember.member} member={projectMember.member}
key={projectMember.id} key={projectMember.id}
isFirstCard={index === FIRST_MEMBER_CARD} isFirstCard={index === FIRST_MEMBER_CARD}
isOwner={projectMember.member.id === currentProject?.owner.id} isOwner={projectMember.member.id === project.owner.id}
isPending={projectMember.member.name === ''} isPending={projectMember.member.name === ''}
permissions={projectMember.permissions} permissions={projectMember.permissions}
handleDeletePendingMember={(id: string) => { handleDeletePendingMember={(id: string) => {

View File

@ -1,5 +1,5 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react'; import React, { useCallback, useEffect, useState } from 'react';
import { useNavigate, useOutletContext, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import { Project as ProjectType } from 'gql-client'; import { Project as ProjectType } from 'gql-client';
import { Button, Typography } from '@material-tailwind/react'; import { Button, Typography } from '@material-tailwind/react';
@ -7,7 +7,6 @@ import { Button, Typography } from '@material-tailwind/react';
import HorizontalLine from '../../components/HorizontalLine'; import HorizontalLine from '../../components/HorizontalLine';
import ProjectTabs from '../../components/projects/project/ProjectTabs'; import ProjectTabs from '../../components/projects/project/ProjectTabs';
import { useGQLClient } from '../../context/GQLClientContext'; import { useGQLClient } from '../../context/GQLClientContext';
import { ProjectSearchOutletContext } from '../../types/project';
const Project = () => { const Project = () => {
const { id } = useParams(); const { id } = useParams();
@ -31,19 +30,9 @@ const Project = () => {
await fetchProject(id); await fetchProject(id);
}; };
// TODO: Remove organization projects
const { projects: organizationProjects } =
useOutletContext<ProjectSearchOutletContext>();
const organizationProject = useMemo(() => {
return organizationProjects.find((project) => {
return project.id === id;
});
}, [id, organizationProjects]);
return ( return (
<div className="h-full"> <div className="h-full">
{project && organizationProject ? ( {project ? (
<> <>
<div className="flex p-4 gap-4 items-center"> <div className="flex p-4 gap-4 items-center">
<Button <Button
@ -65,11 +54,7 @@ const Project = () => {
</div> </div>
<HorizontalLine /> <HorizontalLine />
<div className="p-4"> <div className="p-4">
<ProjectTabs <ProjectTabs project={project} onUpdate={onUpdate} />
project={project}
organizationProject={organizationProject}
onUpdate={onUpdate}
/>
</div> </div>
</> </>
) : ( ) : (

View File

@ -1,43 +0,0 @@
import React from 'react';
import { Link, useOutletContext } from 'react-router-dom';
import { Button, Typography, Chip } from '@material-tailwind/react';
import ProjectCard from '../../components/projects/ProjectCard';
import { ProjectSearchOutletContext } from '../../types/project';
const Projects = () => {
const { projects } = useOutletContext<ProjectSearchOutletContext>();
return (
<div>
<div className="flex p-5">
<div className="grow">
<div className="flex gap-2 items-center">
<Typography variant="h4">Projects</Typography>
<Chip
className="bg-gray-300 rounded-full static"
value={projects.length}
size="sm"
/>
</div>
</div>
<div>
<Link to="/projects/create">
<Button className="rounded-full" color="blue">
Create project
</Button>
</Link>
</div>
</div>
<div className="grid grid-cols-3 gap-5 p-5">
{projects.length !== 0 &&
projects.map((project: any, key: number) => {
return <ProjectCard project={project} key={key} />;
})}
</div>
</div>
);
};
export default Projects;

View File

@ -1,10 +1,6 @@
import { Project, Deployment } from 'gql-client'; import { Project, Deployment } from 'gql-client';
export interface ProjectDetails extends Project { export interface ProjectDetails extends Project {
// TODO: isDomain flag
domain?: string | null;
// TODO: Use deployment branch
source?: string;
latestCommit: Commit; latestCommit: Commit;
// TODO: Move out of project // TODO: Move out of project