forked from cerc-io/snowballtools-base
Implement routes for project settings tab (#64)
* Add routes to settings tab panel * Refactor code to move settings tab components to pages * Rename registry fields in project and deployment entity * Use kebab case for routes --------- Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
+1
-1
@@ -3,7 +3,7 @@ import { UseFormRegister } from 'react-hook-form';
|
||||
|
||||
import { Typography, Input, IconButton } from '@material-tailwind/react';
|
||||
|
||||
import { EnvironmentVariablesFormValues } from './EnvironmentVariablesTabPanel';
|
||||
import { EnvironmentVariablesFormValues } from '../../../../types/project';
|
||||
|
||||
interface AddEnvironmentVariableRowProps {
|
||||
onDelete: () => void;
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Link, Outlet, useLocation, useOutletContext } from 'react-router-dom';
|
||||
|
||||
import { Tabs, TabsHeader, TabsBody, Tab } from '@material-tailwind/react';
|
||||
|
||||
import { OutletContextType } from '../../../../types/project';
|
||||
|
||||
const tabsData = [
|
||||
{
|
||||
label: 'General',
|
||||
icon: '^',
|
||||
value: 'general',
|
||||
},
|
||||
{
|
||||
label: 'Domains',
|
||||
icon: '^',
|
||||
value: 'domains',
|
||||
},
|
||||
{
|
||||
label: 'Git',
|
||||
icon: '^',
|
||||
value: 'git',
|
||||
},
|
||||
{
|
||||
label: 'Environment variables',
|
||||
icon: '^',
|
||||
value: 'environment-variables',
|
||||
},
|
||||
{
|
||||
label: 'Members',
|
||||
icon: '^',
|
||||
value: 'members',
|
||||
},
|
||||
];
|
||||
|
||||
const SettingsTabPanel = () => {
|
||||
const { project, onUpdate } = useOutletContext<OutletContextType>();
|
||||
|
||||
const location = useLocation();
|
||||
|
||||
const currentTab = useMemo(() => {
|
||||
if (project) {
|
||||
const currTabArr = location.pathname.split('settings');
|
||||
return currTabArr[currTabArr.length - 1];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}, [location, project]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tabs
|
||||
value={currentTab}
|
||||
orientation="vertical"
|
||||
className="grid grid-cols-4"
|
||||
>
|
||||
<TabsHeader
|
||||
className="bg-transparent col-span-1"
|
||||
indicatorProps={{
|
||||
className: 'bg-gray-900/10 shadow-none !text-gray-900',
|
||||
}}
|
||||
>
|
||||
{tabsData.map(({ label, value, icon }) => (
|
||||
<Link key={value} to={value === 'general' ? '' : value}>
|
||||
<Tab
|
||||
value={value === 'general' ? '' : `/${value}`}
|
||||
className="flex justify-start"
|
||||
>
|
||||
<div className="flex gap-2">
|
||||
<div>{icon}</div>
|
||||
<div>{label}</div>
|
||||
</div>
|
||||
</Tab>
|
||||
</Link>
|
||||
))}
|
||||
</TabsHeader>
|
||||
<TabsBody className="col-span-2">
|
||||
<Outlet context={{ project, onUpdate }} />
|
||||
</TabsBody>
|
||||
</Tabs>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsTabPanel;
|
||||
@@ -1,92 +0,0 @@
|
||||
import React, { createElement } from 'react';
|
||||
import { useOutletContext } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
Tabs,
|
||||
TabsHeader,
|
||||
TabsBody,
|
||||
Tab,
|
||||
TabPanel,
|
||||
} from '@material-tailwind/react';
|
||||
|
||||
import Domains from '../../../../components/projects/project/settings/Domains';
|
||||
import GeneralTabPanel from '../../../../components/projects/project/settings/GeneralTabPanel';
|
||||
import { EnvironmentVariablesTabPanel } from '../../../../components/projects/project/settings/EnvironmentVariablesTabPanel';
|
||||
import GitTabPanel from '../../../../components/projects/project/settings/GitTabPanel';
|
||||
import MembersTabPanel from '../../../../components/projects/project/settings/MembersTabPanel';
|
||||
import { OutletContextType } from '../../../../types/project';
|
||||
|
||||
const tabsData = [
|
||||
{
|
||||
label: 'General',
|
||||
icon: '^',
|
||||
value: 'general',
|
||||
component: GeneralTabPanel,
|
||||
},
|
||||
{
|
||||
label: 'Domains',
|
||||
icon: '^',
|
||||
value: 'domains',
|
||||
component: Domains,
|
||||
},
|
||||
{
|
||||
label: 'Git',
|
||||
icon: '^',
|
||||
value: 'git',
|
||||
component: GitTabPanel,
|
||||
},
|
||||
{
|
||||
label: 'Environment variables',
|
||||
icon: '^',
|
||||
value: 'environmentVariables',
|
||||
component: EnvironmentVariablesTabPanel,
|
||||
},
|
||||
{
|
||||
label: 'Members',
|
||||
icon: '^',
|
||||
value: 'members',
|
||||
component: MembersTabPanel,
|
||||
},
|
||||
];
|
||||
|
||||
const SettingsTabPanel = () => {
|
||||
const { project, onUpdate } = useOutletContext<OutletContextType>();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tabs
|
||||
value={'general'}
|
||||
orientation="vertical"
|
||||
className="grid grid-cols-4"
|
||||
>
|
||||
<TabsHeader
|
||||
className="bg-transparent col-span-1"
|
||||
indicatorProps={{
|
||||
className: 'bg-gray-900/10 shadow-none !text-gray-900',
|
||||
}}
|
||||
>
|
||||
{tabsData.map(({ label, value, icon }) => (
|
||||
<Tab key={value} value={value} className="flex justify-start">
|
||||
<div className="flex gap-2">
|
||||
<div>{icon}</div>
|
||||
<div>{label}</div>
|
||||
</div>
|
||||
</Tab>
|
||||
))}
|
||||
</TabsHeader>
|
||||
<TabsBody className="col-span-2">
|
||||
{tabsData.map(({ value, component }) => (
|
||||
<TabPanel key={value} value={value} className="p-2">
|
||||
{createElement(component, {
|
||||
project: project,
|
||||
onUpdate: onUpdate,
|
||||
})}
|
||||
</TabPanel>
|
||||
))}
|
||||
</TabsBody>
|
||||
</Tabs>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsTabPanel;
|
||||
@@ -1,8 +1,13 @@
|
||||
import React from 'react';
|
||||
|
||||
import OverviewTabPanel from './OverviewTabPanel';
|
||||
import DeploymentsTabPanel from './DeploymentsTabPanel';
|
||||
import SettingsTabPanel from './SettingsTabPanel';
|
||||
import OverviewTabPanel from './Overview';
|
||||
import DeploymentsTabPanel from './Deployments';
|
||||
import SettingsTabPanel from './Settings';
|
||||
import GeneralTabPanel from './settings/General';
|
||||
import GitTabPanel from './settings/Git';
|
||||
import { EnvironmentVariablesTabPanel } from './settings/EnvironmentVariables';
|
||||
import MembersTabPanel from './settings/Members';
|
||||
import Domains from './settings/Domains';
|
||||
|
||||
const Database = () => (
|
||||
<div>
|
||||
@@ -23,6 +28,29 @@ const Integrations = () => (
|
||||
</div>
|
||||
);
|
||||
|
||||
export const settingsTabRoutes = [
|
||||
{
|
||||
index: true,
|
||||
element: <GeneralTabPanel />,
|
||||
},
|
||||
{
|
||||
path: 'domains',
|
||||
element: <Domains />,
|
||||
},
|
||||
{
|
||||
path: 'git',
|
||||
element: <GitTabPanel />,
|
||||
},
|
||||
{
|
||||
path: 'environment-variables',
|
||||
element: <EnvironmentVariablesTabPanel />,
|
||||
},
|
||||
{
|
||||
path: 'members',
|
||||
element: <MembersTabPanel />,
|
||||
},
|
||||
];
|
||||
|
||||
export const projectTabRoutes = [
|
||||
{
|
||||
index: true,
|
||||
@@ -43,5 +71,6 @@ export const projectTabRoutes = [
|
||||
{
|
||||
path: 'settings',
|
||||
element: <SettingsTabPanel />,
|
||||
children: settingsTabRoutes,
|
||||
},
|
||||
];
|
||||
|
||||
+9
-6
@@ -1,15 +1,18 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Domain, Project } from 'gql-client';
|
||||
import { Link, useOutletContext } from 'react-router-dom';
|
||||
import { Domain } from 'gql-client';
|
||||
|
||||
import { Button, Typography } from '@material-tailwind/react';
|
||||
|
||||
import DomainCard from './DomainCard';
|
||||
import { useGQLClient } from '../../../../context/GQLClientContext';
|
||||
import repositories from '../../../../assets/repositories.json';
|
||||
import DomainCard from '../../../../../components/projects/project/settings/DomainCard';
|
||||
import { useGQLClient } from '../../../../../context/GQLClientContext';
|
||||
import repositories from '../../../../../assets/repositories.json';
|
||||
import { OutletContextType } from '../../../../../types/project';
|
||||
|
||||
const Domains = ({ project }: { project: Project }) => {
|
||||
const Domains = () => {
|
||||
const client = useGQLClient();
|
||||
const { project } = useOutletContext<OutletContextType>();
|
||||
|
||||
const [domains, setDomains] = useState<Domain[]>([]);
|
||||
|
||||
const fetchDomains = async () => {
|
||||
+5
-16
@@ -13,22 +13,11 @@ import {
|
||||
Chip,
|
||||
} from '@material-tailwind/react';
|
||||
|
||||
import AddEnvironmentVariableRow from './AddEnvironmentVariableRow';
|
||||
import DisplayEnvironmentVariables from './DisplayEnvironmentVariables';
|
||||
import HorizontalLine from '../../../HorizontalLine';
|
||||
import { useGQLClient } from '../../../../context/GQLClientContext';
|
||||
|
||||
export type EnvironmentVariablesFormValues = {
|
||||
variables: {
|
||||
key: string;
|
||||
value: string;
|
||||
}[];
|
||||
environment: {
|
||||
development: boolean;
|
||||
preview: boolean;
|
||||
production: boolean;
|
||||
};
|
||||
};
|
||||
import AddEnvironmentVariableRow from '../../../../../components/projects/project/settings/AddEnvironmentVariableRow';
|
||||
import DisplayEnvironmentVariables from '../../../../../components/projects/project/settings/DisplayEnvironmentVariables';
|
||||
import HorizontalLine from '../../../../../components/HorizontalLine';
|
||||
import { useGQLClient } from '../../../../../context/GQLClientContext';
|
||||
import { EnvironmentVariablesFormValues } from '../../../../../types/project';
|
||||
|
||||
export const EnvironmentVariablesTabPanel = () => {
|
||||
const { id } = useParams();
|
||||
+10
-13
@@ -1,15 +1,16 @@
|
||||
import React, { useState, useEffect, useCallback, useMemo } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Link, useOutletContext } from 'react-router-dom';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import toast from 'react-hot-toast';
|
||||
import { Organization, Project } from 'gql-client';
|
||||
import { Organization } from 'gql-client';
|
||||
|
||||
import { Button, Typography, Input, Option } from '@material-tailwind/react';
|
||||
|
||||
import DeleteProjectDialog from './DeleteProjectDialog';
|
||||
import ConfirmDialog from '../../../shared/ConfirmDialog';
|
||||
import { useGQLClient } from '../../../../context/GQLClientContext';
|
||||
import AsyncSelect from '../../../shared/AsyncSelect';
|
||||
import DeleteProjectDialog from '../../../../../components/projects/project/settings/DeleteProjectDialog';
|
||||
import ConfirmDialog from '../../../../../components/shared/ConfirmDialog';
|
||||
import { useGQLClient } from '../../../../../context/GQLClientContext';
|
||||
import AsyncSelect from '../../../../../components/shared/AsyncSelect';
|
||||
import { OutletContextType } from '../../../../../types/project';
|
||||
|
||||
const CopyIcon = ({ value }: { value: string }) => {
|
||||
return (
|
||||
@@ -25,14 +26,10 @@ const CopyIcon = ({ value }: { value: string }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const GeneralTabPanel = ({
|
||||
project,
|
||||
onUpdate,
|
||||
}: {
|
||||
project: Project;
|
||||
onUpdate: () => Promise<void>;
|
||||
}) => {
|
||||
const GeneralTabPanel = () => {
|
||||
const client = useGQLClient();
|
||||
const { project, onUpdate } = useOutletContext<OutletContextType>();
|
||||
|
||||
const [transferOrganizations, setTransferOrganizations] = useState<
|
||||
Organization[]
|
||||
>([]);
|
||||
+6
-10
@@ -1,12 +1,13 @@
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import { useOutletContext } from 'react-router-dom';
|
||||
import { SubmitHandler, useForm } from 'react-hook-form';
|
||||
import toast from 'react-hot-toast';
|
||||
import { Project } from 'gql-client';
|
||||
|
||||
import { Button, Input, Switch, Typography } from '@material-tailwind/react';
|
||||
|
||||
import WebhookCard from './WebhookCard';
|
||||
import { useGQLClient } from '../../../../context/GQLClientContext';
|
||||
import WebhookCard from '../../../../../components/projects/project/settings/WebhookCard';
|
||||
import { useGQLClient } from '../../../../../context/GQLClientContext';
|
||||
import { OutletContextType } from '../../../../../types/project';
|
||||
|
||||
type UpdateProdBranchValues = {
|
||||
prodBranch: string;
|
||||
@@ -16,14 +17,9 @@ type UpdateWebhooksValues = {
|
||||
webhookUrl: string;
|
||||
};
|
||||
|
||||
const GitTabPanel = ({
|
||||
project,
|
||||
onUpdate,
|
||||
}: {
|
||||
project: Project;
|
||||
onUpdate: () => Promise<void>;
|
||||
}) => {
|
||||
const GitTabPanel = () => {
|
||||
const client = useGQLClient();
|
||||
const { project, onUpdate } = useOutletContext<OutletContextType>();
|
||||
|
||||
const {
|
||||
register: registerProdBranch,
|
||||
+9
-12
@@ -1,22 +1,20 @@
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import toast, { Toaster } from 'react-hot-toast';
|
||||
import {
|
||||
Permission,
|
||||
Project,
|
||||
AddProjectMemberInput,
|
||||
ProjectMember,
|
||||
} from 'gql-client';
|
||||
import { useOutletContext } from 'react-router-dom';
|
||||
import toast from 'react-hot-toast';
|
||||
import { Permission, AddProjectMemberInput, ProjectMember } from 'gql-client';
|
||||
|
||||
import { Chip, Button, Typography } from '@material-tailwind/react';
|
||||
|
||||
import MemberCard from './MemberCard';
|
||||
import AddMemberDialog from './AddMemberDialog';
|
||||
import { useGQLClient } from '../../../../context/GQLClientContext';
|
||||
import MemberCard from '../../../../../components/projects/project/settings/MemberCard';
|
||||
import AddMemberDialog from '../../../../../components/projects/project/settings/AddMemberDialog';
|
||||
import { useGQLClient } from '../../../../../context/GQLClientContext';
|
||||
import { OutletContextType } from '../../../../../types/project';
|
||||
|
||||
const FIRST_MEMBER_CARD = 0;
|
||||
|
||||
const MembersTabPanel = ({ project }: { project: Project }) => {
|
||||
const MembersTabPanel = () => {
|
||||
const client = useGQLClient();
|
||||
const { project } = useOutletContext<OutletContextType>();
|
||||
|
||||
const [addmemberDialogOpen, setAddMemberDialogOpen] = useState(false);
|
||||
|
||||
@@ -127,7 +125,6 @@ const MembersTabPanel = ({ project }: { project: Project }) => {
|
||||
open={addmemberDialogOpen}
|
||||
handleAddMember={addMemberHandler}
|
||||
/>
|
||||
<Toaster />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -65,3 +65,15 @@ export type OutletContextType = {
|
||||
project: Project;
|
||||
onUpdate: () => Promise<void>;
|
||||
};
|
||||
|
||||
export type EnvironmentVariablesFormValues = {
|
||||
variables: {
|
||||
key: string;
|
||||
value: string;
|
||||
}[];
|
||||
environment: {
|
||||
development: boolean;
|
||||
preview: boolean;
|
||||
production: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user