[7/n][project settings ui] ProjectSettingContainer (#33)
This commit is contained in:
commit
690fc8d2cb
@ -0,0 +1,32 @@
|
|||||||
|
import { PropsWithChildren } from 'react';
|
||||||
|
|
||||||
|
import { ProjectSettingHeader } from './ProjectSettingHeader';
|
||||||
|
|
||||||
|
export interface ProjectSettingContainerProps extends PropsWithChildren {
|
||||||
|
headingText: string;
|
||||||
|
className?: string;
|
||||||
|
button?: React.ReactNode;
|
||||||
|
badge?: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProjectSettingContainer: React.FC<ProjectSettingContainerProps> = ({
|
||||||
|
headingText,
|
||||||
|
className,
|
||||||
|
button,
|
||||||
|
children,
|
||||||
|
badge,
|
||||||
|
...props
|
||||||
|
}: ProjectSettingContainerProps) => {
|
||||||
|
return (
|
||||||
|
<div className={'flex-col justify-start gap-8 space-y-3 px-2'} {...props}>
|
||||||
|
<ProjectSettingHeader
|
||||||
|
headingText={headingText}
|
||||||
|
button={button}
|
||||||
|
badge={badge}
|
||||||
|
/>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { ProjectSettingContainer };
|
@ -0,0 +1,30 @@
|
|||||||
|
import { PropsWithChildren } from 'react';
|
||||||
|
|
||||||
|
import { Heading } from 'components/shared/Heading';
|
||||||
|
|
||||||
|
export interface ProjectSettingHeaderProps extends PropsWithChildren {
|
||||||
|
headingText: string;
|
||||||
|
button?: React.ReactNode;
|
||||||
|
badge?: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProjectSettingHeader: React.FC<ProjectSettingHeaderProps> = ({
|
||||||
|
headingText,
|
||||||
|
button,
|
||||||
|
badge,
|
||||||
|
...props
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className="flex justify-between items-center" {...props}>
|
||||||
|
<div className="flex space-x-2 items-center">
|
||||||
|
<Heading className="text-lg font-medium leading-normal">
|
||||||
|
{headingText}
|
||||||
|
</Heading>
|
||||||
|
{badge}
|
||||||
|
</div>
|
||||||
|
{button ?? button}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { ProjectSettingHeader };
|
@ -6,11 +6,11 @@ import MemberCard from 'components/projects/project/settings/MemberCard';
|
|||||||
import AddMemberDialog from 'components/projects/project/settings/AddMemberDialog';
|
import AddMemberDialog from 'components/projects/project/settings/AddMemberDialog';
|
||||||
import { useGQLClient } from '../../../../../context/GQLClientContext';
|
import { useGQLClient } from '../../../../../context/GQLClientContext';
|
||||||
import { OutletContextType } from '../../../../../types';
|
import { OutletContextType } from '../../../../../types';
|
||||||
import { useToast } from 'components/shared/Toast';
|
import { useToast } from '../../../../../components/shared/Toast';
|
||||||
import { Button } from 'components/shared/Button';
|
import { Button } from 'components/shared/Button';
|
||||||
import { PlusIcon } from 'components/shared/CustomIcon';
|
import { PlusIcon } from 'components/shared/CustomIcon';
|
||||||
import { Badge } from 'components/shared/Badge';
|
import { Badge } from 'components/shared/Badge';
|
||||||
import { Heading } from 'components/shared/Heading';
|
import { ProjectSettingContainer } from 'components/projects/project/settings/ProjectSettingContainer';
|
||||||
|
|
||||||
const FIRST_MEMBER_CARD = 0;
|
const FIRST_MEMBER_CARD = 0;
|
||||||
|
|
||||||
@ -105,16 +105,14 @@ const CollaboratorsTabPanel = () => {
|
|||||||
}, [project.id, fetchProjectMembers]);
|
}, [project.id, fetchProjectMembers]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-3 px-2">
|
<ProjectSettingContainer
|
||||||
<div className="flex justify-between">
|
headingText="Collaborators"
|
||||||
<div className="flex space-x-2">
|
badge={
|
||||||
<Heading className="text-sky-950 text-lg font-medium leading-normal">
|
<Badge size="sm" variant="inset">
|
||||||
Collaborators
|
{projectMembers.length + 1}
|
||||||
</Heading>
|
</Badge>
|
||||||
<Badge size="sm" variant="inset">
|
}
|
||||||
{projectMembers.length + 1}
|
button={
|
||||||
</Badge>
|
|
||||||
</div>
|
|
||||||
<Button
|
<Button
|
||||||
size="md"
|
size="md"
|
||||||
onClick={() => setAddMemberDialogOpen((preVal) => !preVal)}
|
onClick={() => setAddMemberDialogOpen((preVal) => !preVal)}
|
||||||
@ -123,7 +121,8 @@ const CollaboratorsTabPanel = () => {
|
|||||||
>
|
>
|
||||||
Add member
|
Add member
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
}
|
||||||
|
>
|
||||||
<MemberCard
|
<MemberCard
|
||||||
member={project.owner}
|
member={project.owner}
|
||||||
isFirstCard={true}
|
isFirstCard={true}
|
||||||
@ -156,7 +155,7 @@ const CollaboratorsTabPanel = () => {
|
|||||||
open={addmemberDialogOpen}
|
open={addmemberDialogOpen}
|
||||||
handleAddMember={addMemberHandler}
|
handleAddMember={addMemberHandler}
|
||||||
/>
|
/>
|
||||||
</div>
|
</ProjectSettingContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7,8 +7,9 @@ import DomainCard from 'components/projects/project/settings/DomainCard';
|
|||||||
import { useGQLClient } from '../../../../../context/GQLClientContext';
|
import { useGQLClient } from '../../../../../context/GQLClientContext';
|
||||||
import { OutletContextType } from '../../../../../types';
|
import { OutletContextType } from '../../../../../types';
|
||||||
import { useOctokit } from '../../../../../context/OctokitContext';
|
import { useOctokit } from '../../../../../context/OctokitContext';
|
||||||
import { Heading } from 'components/shared/Heading';
|
|
||||||
import { Button } from 'components/shared/Button';
|
import { Button } from 'components/shared/Button';
|
||||||
|
import { PlusIcon } from 'components/shared/CustomIcon';
|
||||||
|
import { ProjectSettingContainer } from 'components/projects/project/settings/ProjectSettingContainer';
|
||||||
|
|
||||||
const Domains = () => {
|
const Domains = () => {
|
||||||
const client = useGQLClient();
|
const client = useGQLClient();
|
||||||
@ -57,16 +58,20 @@ const Domains = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<ProjectSettingContainer
|
||||||
<div className="space-y-3 px-2">
|
headingText="Domains"
|
||||||
<Heading className="text-sky-950 text-lg font-medium leading-normal">
|
button={
|
||||||
Domains
|
<Button
|
||||||
</Heading>
|
as="a"
|
||||||
<Button as="a" href="add">
|
href="add"
|
||||||
|
variant="secondary"
|
||||||
|
leftIcon={<PlusIcon />}
|
||||||
|
size="md"
|
||||||
|
>
|
||||||
Add domain
|
Add domain
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
}
|
||||||
|
>
|
||||||
{domains.map((domain) => {
|
{domains.map((domain) => {
|
||||||
return (
|
return (
|
||||||
<DomainCard
|
<DomainCard
|
||||||
@ -80,7 +85,7 @@ const Domains = () => {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</>
|
</ProjectSettingContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import { Button } from 'components/shared/Button';
|
|||||||
import { Checkbox } from 'components/shared/Checkbox';
|
import { Checkbox } from 'components/shared/Checkbox';
|
||||||
import { PlusIcon } from 'components/shared/CustomIcon';
|
import { PlusIcon } from 'components/shared/CustomIcon';
|
||||||
import { InlineNotification } from 'components/shared/InlineNotification';
|
import { InlineNotification } from 'components/shared/InlineNotification';
|
||||||
|
import { ProjectSettingContainer } from 'components/projects/project/settings/ProjectSettingContainer';
|
||||||
|
|
||||||
export const EnvironmentVariablesTabPanel = () => {
|
export const EnvironmentVariablesTabPanel = () => {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
@ -130,10 +131,7 @@ export const EnvironmentVariablesTabPanel = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-3 px-2">
|
<ProjectSettingContainer headingText="Environment variables">
|
||||||
<Heading className="text-sky-950 text-lg font-medium leading-normal">
|
|
||||||
Environment variables
|
|
||||||
</Heading>
|
|
||||||
<p className="text-slate-600 text-sm font-normal leading-tight">
|
<p className="text-slate-600 text-sm font-normal leading-tight">
|
||||||
A new deployment is required for your changes to take effect.
|
A new deployment is required for your changes to take effect.
|
||||||
</p>
|
</p>
|
||||||
@ -236,6 +234,6 @@ export const EnvironmentVariablesTabPanel = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</ProjectSettingContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -12,6 +12,7 @@ import { Button } from 'components/shared/Button';
|
|||||||
import { Select, SelectOption } from 'components/shared/Select';
|
import { Select, SelectOption } from 'components/shared/Select';
|
||||||
import { TrashIcon, CopyUnfilledIcon } from 'components/shared/CustomIcon';
|
import { TrashIcon, CopyUnfilledIcon } from 'components/shared/CustomIcon';
|
||||||
import { useToast } from 'components/shared/Toast';
|
import { useToast } from 'components/shared/Toast';
|
||||||
|
import { ProjectSettingContainer } from 'components/projects/project/settings/ProjectSettingContainer';
|
||||||
|
|
||||||
const GeneralTabPanel = () => {
|
const GeneralTabPanel = () => {
|
||||||
const client = useGQLClient();
|
const client = useGQLClient();
|
||||||
@ -109,7 +110,7 @@ const GeneralTabPanel = () => {
|
|||||||
}, [project]);
|
}, [project]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex-col justify-start items-start gap-6 inline-flex">
|
<ProjectSettingContainer headingText="Project Info">
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmit(async ({ appName, description }) => {
|
onSubmit={handleSubmit(async ({ appName, description }) => {
|
||||||
const { updateProject } = await client.updateProject(project.id, {
|
const { updateProject } = await client.updateProject(project.id, {
|
||||||
@ -120,11 +121,8 @@ const GeneralTabPanel = () => {
|
|||||||
await onUpdate();
|
await onUpdate();
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
className="self-stretch space-y-3 px-2"
|
className="self-stretch space-y-3"
|
||||||
>
|
>
|
||||||
<Heading className="text-sky-950 text-lg font-medium leading-normal">
|
|
||||||
Project Info
|
|
||||||
</Heading>
|
|
||||||
<Input
|
<Input
|
||||||
// TODO: Debug issue: https://github.com/creativetimofficial/material-tailwind/issues/427
|
// TODO: Debug issue: https://github.com/creativetimofficial/material-tailwind/issues/427
|
||||||
label="App name"
|
label="App name"
|
||||||
@ -221,7 +219,7 @@ const GeneralTabPanel = () => {
|
|||||||
project={project}
|
project={project}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</ProjectSettingContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -8,8 +8,9 @@ import { OutletContextType } from '../../../../../types';
|
|||||||
import { Button } from 'components/shared/Button';
|
import { Button } from 'components/shared/Button';
|
||||||
import { Input } from 'components/shared/Input';
|
import { Input } from 'components/shared/Input';
|
||||||
import { Switch } from 'components/shared/Switch';
|
import { Switch } from 'components/shared/Switch';
|
||||||
import { Heading } from 'components/shared/Heading';
|
|
||||||
import { useToast } from 'components/shared/Toast';
|
import { useToast } from 'components/shared/Toast';
|
||||||
|
import { ProjectSettingContainer } from 'components/projects/project/settings/ProjectSettingContainer';
|
||||||
|
import { ProjectSettingHeader } from 'components/projects/project/settings/ProjectSettingHeader';
|
||||||
|
|
||||||
type UpdateProdBranchValues = {
|
type UpdateProdBranchValues = {
|
||||||
prodBranch: string;
|
prodBranch: string;
|
||||||
@ -134,12 +135,8 @@ const GitTabPanel = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex-col justify-start items-start gap-6 inline-flex">
|
<ProjectSettingContainer headingText="Git repository">
|
||||||
<div className="self-stretch space-y-3 px-2">
|
<div className="self-stretch space-y-3">
|
||||||
<Heading className="text-sky-950 text-lg font-medium leading-normal">
|
|
||||||
Git repository
|
|
||||||
</Heading>
|
|
||||||
|
|
||||||
<div className="flex justify-between mt-4">
|
<div className="flex justify-between mt-4">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-slate-600 text-sm font-normal leading-tight">
|
<p className="text-slate-600 text-sm font-normal leading-tight">
|
||||||
@ -171,11 +168,9 @@ const GitTabPanel = () => {
|
|||||||
|
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmitProdBranch(updateProdBranchHandler)}
|
onSubmit={handleSubmitProdBranch(updateProdBranchHandler)}
|
||||||
className="space-y-3 px-2"
|
className="space-y-3"
|
||||||
>
|
>
|
||||||
<Heading className="text-sky-950 text-lg font-medium leading-normal">
|
<ProjectSettingHeader headingText="Production branch" />
|
||||||
Production branch
|
|
||||||
</Heading>
|
|
||||||
<p className="text-slate-600 text-sm font-normal leading-tight">
|
<p className="text-slate-600 text-sm font-normal leading-tight">
|
||||||
By default, each commit pushed to the{' '}
|
By default, each commit pushed to the{' '}
|
||||||
<span className="font-bold">{project.prodBranch}</span> branch
|
<span className="font-bold">{project.prodBranch}</span> branch
|
||||||
@ -193,11 +188,9 @@ const GitTabPanel = () => {
|
|||||||
|
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmitWebhooks(updateWebhooksHandler)}
|
onSubmit={handleSubmitWebhooks(updateWebhooksHandler)}
|
||||||
className="space-y-3 px-2"
|
className="space-y-3"
|
||||||
>
|
>
|
||||||
<Heading className="text-sky-950 text-lg font-medium leading-normal">
|
<ProjectSettingHeader headingText="Deploy webhooks" />
|
||||||
Deploy webhooks
|
|
||||||
</Heading>
|
|
||||||
<p className="text-slate-600 text-sm font-normal leading-tight">
|
<p className="text-slate-600 text-sm font-normal leading-tight">
|
||||||
{' '}
|
{' '}
|
||||||
Webhooks configured to trigger when there is a change in a
|
Webhooks configured to trigger when there is a change in a
|
||||||
@ -228,7 +221,7 @@ const GitTabPanel = () => {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</ProjectSettingContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,11 +2,11 @@ import toast from 'react-hot-toast';
|
|||||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
import { useGQLClient } from '../../../../../../../context/GQLClientContext';
|
import { useGQLClient } from '../../../../../../../context/GQLClientContext';
|
||||||
import { Heading } from 'components/shared/Heading';
|
|
||||||
import { Table } from 'components/shared/Table';
|
import { Table } from 'components/shared/Table';
|
||||||
import { Button } from 'components/shared/Button';
|
import { Button } from 'components/shared/Button';
|
||||||
import { InlineNotification } from 'components/shared/InlineNotification';
|
import { InlineNotification } from 'components/shared/InlineNotification';
|
||||||
import { ArrowRightCircleIcon } from 'components/shared/CustomIcon';
|
import { ArrowRightCircleIcon } from 'components/shared/CustomIcon';
|
||||||
|
import { ProjectSettingContainer } from 'components/projects/project/settings/ProjectSettingContainer';
|
||||||
|
|
||||||
const Config = () => {
|
const Config = () => {
|
||||||
const { id, orgSlug } = useParams();
|
const { id, orgSlug } = useParams();
|
||||||
@ -40,18 +40,13 @@ const Config = () => {
|
|||||||
|
|
||||||
// TODO: Figure out DNS Provider if possible and update appropriatly
|
// TODO: Figure out DNS Provider if possible and update appropriatly
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-6 w-full">
|
<ProjectSettingContainer headingText="Setup domain name">
|
||||||
<div>
|
<p className="text-blue-gray-500">
|
||||||
<Heading className="text-sky-950 text-lg font-medium leading-normal">
|
Add the following records to your domain.
|
||||||
Setup domain name
|
<a href="https://www.namecheap.com/" target="_blank" rel="noreferrer">
|
||||||
</Heading>
|
<span className="underline">Go to NameCheap</span>
|
||||||
<p className="text-blue-gray-500">
|
</a>
|
||||||
Add the following records to your domain.
|
</p>
|
||||||
<a href="https://www.namecheap.com/" target="_blank" rel="noreferrer">
|
|
||||||
<span className="underline">Go to NameCheap</span>
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Table>
|
<Table>
|
||||||
<Table.Header>
|
<Table.Header>
|
||||||
@ -90,7 +85,7 @@ const Config = () => {
|
|||||||
>
|
>
|
||||||
Finish
|
Finish
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</ProjectSettingContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import {
|
|||||||
IconButton,
|
IconButton,
|
||||||
} from '@snowballtools/material-tailwind-react-fork';
|
} from '@snowballtools/material-tailwind-react-fork';
|
||||||
|
|
||||||
import Stepper from '../../../../../../../components/Stepper';
|
import Stepper from 'components/Stepper';
|
||||||
|
|
||||||
const AddDomain = () => {
|
const AddDomain = () => {
|
||||||
const { id, orgSlug } = useParams();
|
const { id, orgSlug } = useParams();
|
||||||
|
Loading…
Reference in New Issue
Block a user