Implement functionality to create project using a template (#60)
* Create repository from selected template * Create project based on created repository * Replace dropdown component with component from material tailwind * Remove repository name from query parameters
This commit is contained in:
parent
413ed03eb8
commit
e0001466e0
@ -1,9 +1,11 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
"id": "2379cf1f-a232-4ad2-ae14-4d881131cc26",
|
||||||
"name": "Snowball Tools",
|
"name": "Snowball Tools",
|
||||||
"slug": "snowball-tools"
|
"slug": "snowball-tools"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"id": "7eb9b3eb-eb74-4b53-b59a-69884c82a7fb",
|
||||||
"name": "AirFoil",
|
"name": "AirFoil",
|
||||||
"slug": "airfoil"
|
"slug": "airfoil"
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,27 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"framework": "React",
|
"id": "1",
|
||||||
|
"name": "Progressive Web App (PWA)",
|
||||||
"icon": "^"
|
"icon": "^"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"framework": "Reactnative",
|
"id": "2",
|
||||||
|
"name": "Kotlin",
|
||||||
"icon": "^"
|
"icon": "^"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"framework": "Kotlin",
|
"id": "3",
|
||||||
|
"name": "React Native",
|
||||||
"icon": "^"
|
"icon": "^"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"framework": "Swift",
|
"id": "4",
|
||||||
|
"name": "Swift",
|
||||||
"icon": "^"
|
"icon": "^"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"framework": "Webapp",
|
"id": "5",
|
||||||
|
"name": "Web app",
|
||||||
"icon": "^"
|
"icon": "^"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -5,7 +5,7 @@ import {
|
|||||||
} from 'react-dropdown';
|
} from 'react-dropdown';
|
||||||
import 'react-dropdown/style.css';
|
import 'react-dropdown/style.css';
|
||||||
|
|
||||||
interface Option {
|
export interface Option {
|
||||||
value: string;
|
value: string;
|
||||||
label: string;
|
label: string;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
import { Button, Typography } from '@material-tailwind/react';
|
import { Button, Typography } from '@material-tailwind/react';
|
||||||
|
|
||||||
@ -8,8 +8,12 @@ import { Stopwatch, setStopWatchOffset } from '../../StopWatch';
|
|||||||
import ConfirmDialog from '../../shared/ConfirmDialog';
|
import ConfirmDialog from '../../shared/ConfirmDialog';
|
||||||
|
|
||||||
const Deploy = () => {
|
const Deploy = () => {
|
||||||
|
const [searchParams] = useSearchParams();
|
||||||
|
const projectId = searchParams.get('projectId');
|
||||||
|
|
||||||
const [open, setOpen] = React.useState(false);
|
const [open, setOpen] = React.useState(false);
|
||||||
const handleOpen = () => setOpen(!open);
|
const handleOpen = () => setOpen(!open);
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { orgSlug } = useParams();
|
const { orgSlug } = useParams();
|
||||||
|
|
||||||
@ -70,6 +74,14 @@ const Deploy = () => {
|
|||||||
status={DeployStatus.NOT_STARTED}
|
status={DeployStatus.NOT_STARTED}
|
||||||
step="4"
|
step="4"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
navigate(`/${orgSlug}/projects/create/success/${projectId}`);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
VIEW DEMO
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,43 +1,61 @@
|
|||||||
import React from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
|
|
||||||
import { Chip, IconButton } from '@material-tailwind/react';
|
import { Chip, IconButton } from '@material-tailwind/react';
|
||||||
|
|
||||||
import { relativeTime } from '../../../utils/time';
|
import { relativeTime } from '../../../utils/time';
|
||||||
import { GitRepositoryDetails } from '../../../types/project';
|
import { GitRepositoryDetails } from '../../../types/project';
|
||||||
|
import { useGQLClient } from '../../../context/GQLClientContext';
|
||||||
|
|
||||||
interface ProjectRepoCardProps {
|
interface ProjectRepoCardProps {
|
||||||
repository: GitRepositoryDetails;
|
repository: GitRepositoryDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProjectRepoCard: React.FC<ProjectRepoCardProps> = ({ repository }) => {
|
const ProjectRepoCard: React.FC<ProjectRepoCardProps> = ({ repository }) => {
|
||||||
|
const client = useGQLClient();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const { orgSlug } = useParams();
|
||||||
|
|
||||||
|
const createProject = useCallback(async () => {
|
||||||
|
if (!repository) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { addProject } = await client.addProject(orgSlug!, {
|
||||||
|
name: `${repository.owner!.login}-${repository.name}`,
|
||||||
|
// TODO: Get organization id from context or URL
|
||||||
|
prodBranch: repository.default_branch!,
|
||||||
|
repository: repository.full_name,
|
||||||
|
});
|
||||||
|
|
||||||
|
navigate(`import?projectId=${addProject.id}`);
|
||||||
|
}, [client, repository]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link
|
<div
|
||||||
to={`import?owner=${repository.owner?.login}&repo=${repository.name}`}
|
className="group flex items-center gap-4 text-gray-500 text-xs hover:bg-gray-100 p-2 cursor-pointer"
|
||||||
|
onClick={createProject}
|
||||||
>
|
>
|
||||||
<div className="group flex items-center gap-4 text-gray-500 text-xs hover:bg-gray-100 p-2 cursor-pointer">
|
<div>^</div>
|
||||||
<div>^</div>
|
<div className="grow">
|
||||||
<div className="grow">
|
<div>
|
||||||
<div>
|
<span className="text-black">{repository.full_name}</span>
|
||||||
<span className="text-black">{repository.full_name}</span>
|
{repository.visibility === 'private' && (
|
||||||
{repository.visibility === 'private' ? (
|
<Chip
|
||||||
<Chip
|
className="normal-case inline ml-6 font-normal"
|
||||||
className="normal-case inline ml-6 bg-[#FED7AA] text-[#EA580C] font-normal"
|
size="sm"
|
||||||
size="sm"
|
value="Private"
|
||||||
value="Private"
|
icon={'^'}
|
||||||
icon={'^'}
|
/>
|
||||||
/>
|
)}
|
||||||
) : (
|
|
||||||
''
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<p>{repository.updated_at && relativeTime(repository.updated_at)}</p>
|
|
||||||
</div>
|
|
||||||
<div className="hidden group-hover:block">
|
|
||||||
<IconButton size="sm">{'>'}</IconButton>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p>{repository.updated_at && relativeTime(repository.updated_at)}</p>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
<div className="hidden group-hover:block">
|
||||||
|
<IconButton size="sm">{'>'}</IconButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6,19 +6,20 @@ import { IconButton, Typography } from '@material-tailwind/react';
|
|||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
interface TemplateDetails {
|
interface TemplateDetails {
|
||||||
framework: string;
|
id: string;
|
||||||
|
name: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
}
|
}
|
||||||
interface TemplateCardProps {
|
interface TemplateCardProps {
|
||||||
framework: TemplateDetails;
|
template: TemplateDetails;
|
||||||
isGitAuth: boolean;
|
isGitAuth: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CardDetails = ({ framework }: { framework: TemplateDetails }) => {
|
const CardDetails = ({ template }: { template: TemplateDetails }) => {
|
||||||
return (
|
return (
|
||||||
<div className="h-14 group bg-gray-200 border-gray-200 rounded-lg shadow p-4 flex items-center justify-between">
|
<div className="h-14 group bg-gray-200 border-gray-200 rounded-lg shadow p-4 flex items-center justify-between">
|
||||||
<Typography className="grow">
|
<Typography className="grow">
|
||||||
{framework.icon} {framework.framework}
|
{template.icon} {template.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
<div>
|
<div>
|
||||||
<IconButton size="sm" className="rounded-full hidden group-hover:block">
|
<IconButton size="sm" className="rounded-full hidden group-hover:block">
|
||||||
@ -29,13 +30,10 @@ const CardDetails = ({ framework }: { framework: TemplateDetails }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const TemplateCard: React.FC<TemplateCardProps> = ({
|
const TemplateCard: React.FC<TemplateCardProps> = ({ template, isGitAuth }) => {
|
||||||
framework,
|
|
||||||
isGitAuth,
|
|
||||||
}) => {
|
|
||||||
return isGitAuth ? (
|
return isGitAuth ? (
|
||||||
<Link to="template">
|
<Link to={`template?templateId=${template.id}`}>
|
||||||
<CardDetails framework={framework} />
|
<CardDetails template={template} />
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
<a
|
<a
|
||||||
@ -43,7 +41,7 @@ const TemplateCard: React.FC<TemplateCardProps> = ({
|
|||||||
toast.error('Connect Git account to start with a template')
|
toast.error('Connect Git account to start with a template')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<CardDetails framework={framework} />
|
<CardDetails template={template} />
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -3,3 +3,5 @@ export const COMMIT_DETAILS = {
|
|||||||
createdAt: '2023-12-11T04:20:00',
|
createdAt: '2023-12-11T04:20:00',
|
||||||
branch: 'main',
|
branch: 'main',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ORGANIZATION_ID = '2379cf1f-a232-4ad2-ae14-4d881131cc26';
|
||||||
|
@ -1,65 +1,37 @@
|
|||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
import { useSearchParams } from 'react-router-dom';
|
||||||
|
import assert from 'assert';
|
||||||
|
|
||||||
import { Button } from '@material-tailwind/react';
|
|
||||||
|
|
||||||
import { useOctokit } from '../../../../context/OctokitContext';
|
|
||||||
import { GitRepositoryDetails } from '../../../../types/project';
|
|
||||||
import Deploy from '../../../../components/projects/create/Deploy';
|
import Deploy from '../../../../components/projects/create/Deploy';
|
||||||
import { useGQLClient } from '../../../../context/GQLClientContext';
|
import { useGQLClient } from '../../../../context/GQLClientContext';
|
||||||
|
|
||||||
const Import = () => {
|
const Import = () => {
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const { orgSlug } = useParams();
|
const projectId = searchParams.get('projectId');
|
||||||
const navigate = useNavigate();
|
assert(projectId);
|
||||||
const { octokit } = useOctokit();
|
|
||||||
|
const [repoName, setRepoName] = useState<string>('');
|
||||||
const client = useGQLClient();
|
const client = useGQLClient();
|
||||||
const [gitRepo, setGitRepo] = useState<GitRepositoryDetails>();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchRepo = async () => {
|
const fetchRepo = async () => {
|
||||||
if (!octokit) {
|
const { project } = await client.getProject(projectId);
|
||||||
return;
|
assert(project);
|
||||||
}
|
|
||||||
|
|
||||||
const result = await octokit.rest.repos.get({
|
setRepoName(project.repository);
|
||||||
owner: searchParams.get('owner') ?? '',
|
|
||||||
repo: searchParams.get('repo') ?? '',
|
|
||||||
});
|
|
||||||
|
|
||||||
setGitRepo(result.data);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchRepo();
|
fetchRepo();
|
||||||
}, [searchParams, octokit]);
|
}, [projectId]);
|
||||||
|
|
||||||
const createProjectAndCreate = useCallback(async () => {
|
|
||||||
if (!gitRepo) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { addProject } = await client.addProject(orgSlug!, {
|
|
||||||
// TODO: Implement form for setting project name
|
|
||||||
name: `${gitRepo.owner!.login}-${gitRepo.name}`,
|
|
||||||
prodBranch: gitRepo.default_branch ?? 'main',
|
|
||||||
repository: gitRepo.full_name,
|
|
||||||
});
|
|
||||||
|
|
||||||
navigate(`/${orgSlug}/projects/create/success/${addProject.id}`);
|
|
||||||
}, [client, gitRepo]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center">
|
<div className="flex flex-col items-center">
|
||||||
<div className="flex w-5/6 my-4 bg-gray-200 rounded-xl p-6">
|
<div className="flex w-5/6 my-4 bg-gray-200 rounded-xl p-6">
|
||||||
<div>^</div>
|
<div>^</div>
|
||||||
<div className="grow">{gitRepo?.full_name}</div>
|
<div className="grow">{repoName}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Deploy />
|
<Deploy />
|
||||||
|
|
||||||
<Button onClick={createProjectAndCreate}>
|
|
||||||
CREATE PROJECT (FOR DEMO)
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { Outlet, useLocation } from 'react-router-dom';
|
import { Outlet, useLocation, useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
import Stepper from '../../../../components/Stepper';
|
import Stepper from '../../../../components/Stepper';
|
||||||
|
import templateDetails from '../../../../assets/templates.json';
|
||||||
|
|
||||||
const STEPPER_VALUES = [
|
const STEPPER_VALUES = [
|
||||||
{ step: 1, route: '/projects/create/template', label: 'Create repository' },
|
{ step: 1, route: '/projects/create/template', label: 'Create repository' },
|
||||||
@ -12,6 +13,12 @@ const STEPPER_VALUES = [
|
|||||||
const CreateWithTemplate = () => {
|
const CreateWithTemplate = () => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
|
const [searchParams] = useSearchParams();
|
||||||
|
|
||||||
|
const template = templateDetails.find(
|
||||||
|
(template) => template.id === searchParams.get('templateId'),
|
||||||
|
);
|
||||||
|
|
||||||
const activeStep = useMemo(
|
const activeStep = useMemo(
|
||||||
() =>
|
() =>
|
||||||
STEPPER_VALUES.find((data) => data.route === location.pathname)?.step ??
|
STEPPER_VALUES.find((data) => data.route === location.pathname)?.step ??
|
||||||
@ -23,7 +30,7 @@ const CreateWithTemplate = () => {
|
|||||||
<div className="flex flex-col items-center">
|
<div className="flex flex-col items-center">
|
||||||
<div className="flex justify-between w-5/6 my-4 bg-gray-200 rounded-xl p-6">
|
<div className="flex justify-between w-5/6 my-4 bg-gray-200 rounded-xl p-6">
|
||||||
<div>^</div>
|
<div>^</div>
|
||||||
<div className="grow">React native</div>
|
<div className="grow">{template?.name}</div>
|
||||||
{/* TODO: Get template Git link from DB */}
|
{/* TODO: Get template Git link from DB */}
|
||||||
<div>^snowball-tools/react-native-starter</div>
|
<div>^snowball-tools/react-native-starter</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -13,12 +13,12 @@ const NewProject = () => {
|
|||||||
<>
|
<>
|
||||||
<h5 className="mt-4 ml-4">Start with template</h5>
|
<h5 className="mt-4 ml-4">Start with template</h5>
|
||||||
<div className="grid grid-cols-3 p-4 gap-4">
|
<div className="grid grid-cols-3 p-4 gap-4">
|
||||||
{templateDetails.map((framework, key) => {
|
{templateDetails.map((template) => {
|
||||||
return (
|
return (
|
||||||
<TemplateCard
|
<TemplateCard
|
||||||
isGitAuth={Boolean(octokit)}
|
isGitAuth={Boolean(octokit)}
|
||||||
framework={framework}
|
template={template}
|
||||||
key={key}
|
key={template.id}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
@ -1,31 +1,104 @@
|
|||||||
import React from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import { useForm, Controller } from 'react-hook-form';
|
import { useForm, Controller, SubmitHandler } from 'react-hook-form';
|
||||||
import { Link } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
|
import toast from 'react-hot-toast';
|
||||||
|
import assert from 'assert';
|
||||||
|
|
||||||
import { Typography } from '@material-tailwind/react';
|
import { Option, Typography } from '@material-tailwind/react';
|
||||||
|
|
||||||
import Dropdown from '../../../../../components/Dropdown';
|
import { useOctokit } from '../../../../../context/OctokitContext';
|
||||||
|
import { useGQLClient } from '../../../../../context/GQLClientContext';
|
||||||
|
import AsyncSelect from '../../../../../components/shared/AsyncSelect';
|
||||||
|
|
||||||
const USER_OPTIONS = [
|
type SubmitRepoValues = {
|
||||||
{ value: 'saugatyadav1', label: 'saugatyadav1' },
|
framework: string;
|
||||||
{ value: 'brad102', label: 'brad102' },
|
repoName: string;
|
||||||
{ value: 'erin20', label: 'erin20' },
|
isPrivate: boolean;
|
||||||
];
|
account: string;
|
||||||
|
};
|
||||||
|
|
||||||
const CreateRepo = () => {
|
const CreateRepo = () => {
|
||||||
const { register, handleSubmit, control } = useForm({
|
const { octokit } = useOctokit();
|
||||||
|
|
||||||
|
const client = useGQLClient();
|
||||||
|
|
||||||
|
const { orgSlug } = useParams();
|
||||||
|
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const [gitAccounts, setGitAccounts] = useState<string[]>([]);
|
||||||
|
|
||||||
|
const submitRepoHandler: SubmitHandler<SubmitRepoValues> = useCallback(
|
||||||
|
async (data) => {
|
||||||
|
assert(data.account);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// TODO: Handle this functionality in backend
|
||||||
|
const gitRepo = await octokit?.rest.repos.createUsingTemplate({
|
||||||
|
template_owner: 'github-rest',
|
||||||
|
template_repo: 'test-progressive-web-app',
|
||||||
|
owner: data.account,
|
||||||
|
name: data.repoName,
|
||||||
|
description: 'This is your first repository',
|
||||||
|
include_all_branches: false,
|
||||||
|
private: data.isPrivate,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!gitRepo) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { addProject } = await client.addProject(orgSlug!, {
|
||||||
|
name: `${gitRepo.data.owner!.login}-${gitRepo.data.name}`,
|
||||||
|
// TODO: Get organization id from context or URL
|
||||||
|
prodBranch: gitRepo.data.default_branch ?? 'main',
|
||||||
|
repository: gitRepo.data.full_name,
|
||||||
|
});
|
||||||
|
|
||||||
|
navigate(
|
||||||
|
`/${orgSlug}/projects/create/template/deploy?projectId=${addProject.id}`,
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
toast.error('Error deploying project');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[octokit],
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchUserAndOrgs = async () => {
|
||||||
|
const user = await octokit?.rest.users.getAuthenticated();
|
||||||
|
const orgs = await octokit?.rest.orgs.listForAuthenticatedUser();
|
||||||
|
|
||||||
|
if (user && orgs) {
|
||||||
|
const orgsLoginArr = orgs.data.map((org) => org.login);
|
||||||
|
|
||||||
|
setGitAccounts([user.data.login, ...orgsLoginArr]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchUserAndOrgs();
|
||||||
|
}, [octokit]);
|
||||||
|
|
||||||
|
const { register, handleSubmit, control, reset } = useForm<SubmitRepoValues>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
framework: 'reactNative',
|
framework: 'React',
|
||||||
repoName: '',
|
repoName: '',
|
||||||
isPrivate: false,
|
isPrivate: false,
|
||||||
account: { value: 'saugatyadav1', label: 'saugatyadav1' },
|
account: gitAccounts[0],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (gitAccounts.length > 0) {
|
||||||
|
reset({ account: gitAccounts[0] });
|
||||||
|
}
|
||||||
|
}, [gitAccounts]);
|
||||||
|
|
||||||
// TODO: Get users and orgs from GitHub
|
// TODO: Get users and orgs from GitHub
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit(() => {})}>
|
<form onSubmit={handleSubmit(submitRepoHandler)}>
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
<Typography variant="h6">Create a repository</Typography>
|
<Typography variant="h6">Create a repository</Typography>
|
||||||
<Typography color="gray">
|
<Typography color="gray">
|
||||||
@ -39,19 +112,19 @@ const CreateRepo = () => {
|
|||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
{...register('framework')}
|
{...register('framework')}
|
||||||
value="reactNative"
|
value="React"
|
||||||
className="h-5 w-5 text-indigo-600 rounded"
|
className="h-5 w-5 text-indigo-600 rounded"
|
||||||
/>
|
/>
|
||||||
<span className="ml-2">^React Native</span>
|
<span className="ml-2">^React</span>
|
||||||
</label>
|
</label>
|
||||||
<label className="inline-flex items-center w-1/2 border rounded-lg p-2">
|
<label className="inline-flex items-center w-1/2 border rounded-lg p-2">
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
{...register('framework')}
|
{...register('framework')}
|
||||||
className="h-5 w-5 text-indigo-600 rounded"
|
className="h-5 w-5 text-indigo-600 rounded"
|
||||||
value="expo"
|
value="Next"
|
||||||
/>
|
/>
|
||||||
<span className="ml-2">^Expo</span>
|
<span className="ml-2">^Next</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -61,12 +134,17 @@ const CreateRepo = () => {
|
|||||||
<Controller
|
<Controller
|
||||||
name="account"
|
name="account"
|
||||||
control={control}
|
control={control}
|
||||||
render={({ field: { onChange, value } }) => (
|
render={({ field }) => (
|
||||||
<Dropdown
|
<AsyncSelect
|
||||||
onChange={onChange}
|
{...field}
|
||||||
value={value}
|
label={!field.value ? 'Select an account / Organization' : ''}
|
||||||
options={USER_OPTIONS}
|
>
|
||||||
/>
|
{gitAccounts.map((account, key) => (
|
||||||
|
<Option key={key} value={account}>
|
||||||
|
^ {account}
|
||||||
|
</Option>
|
||||||
|
))}
|
||||||
|
</AsyncSelect>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -93,11 +171,9 @@ const CreateRepo = () => {
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
<Link to="deploy">
|
<button className="bg-blue-500 rounded-xl p-2" type="submit">
|
||||||
<button className="bg-blue-500 rounded-xl p-2" type="submit">
|
Deploy ^
|
||||||
Deploy ^
|
</button>
|
||||||
</button>
|
|
||||||
</Link>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user