UI fixes in Snowball frontend app (#93)

* Fix alignment of deployment status chip

* Use template name from env

* Use env for git template link

* Add loading spinner for create project

* Display user name

* Format the displayed user name

---------

Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
Nabarun Gogoi 2024-02-22 11:25:17 +05:30 committed by GitHub
parent e816c596ca
commit 6b17dce2ae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 90 additions and 34 deletions

View File

@ -1,19 +1,19 @@
[
{
"id": "59f4355d-9549-4aac-9b54-eeefceeabef0",
"name": "Snowball",
"name": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"email": "snowball@snowballtools.xyz",
"isVerified": true
},
{
"id": "e505b212-8da6-48b2-9614-098225dab34b",
"name": "Alice Anderson",
"name": "0xbe0eb53f46cd790cd13851d5eff43d12404d33e8",
"email": "alice@snowballtools.xyz",
"isVerified": true
},
{
"id": "cd892fad-9138-4aa2-a62c-414a32776ea7",
"name": "Bob Banner",
"name": "0x8315177ab297ba92a06054ce80a67ed4dbd7ed3a",
"email": "bob@snowballtools.xyz",
"isVerified": true
}

View File

@ -1,7 +1,8 @@
import React, { useCallback } from 'react';
import toast from 'react-hot-toast';
import { useNavigate, useParams } from 'react-router-dom';
import { Chip, IconButton } from '@material-tailwind/react';
import { Chip, IconButton, Spinner } from '@material-tailwind/react';
import { relativeTimeISO } from '../../../utils/time';
import { GitRepositoryDetails } from '../../../types';
@ -14,6 +15,7 @@ interface ProjectRepoCardProps {
const ProjectRepoCard: React.FC<ProjectRepoCardProps> = ({ repository }) => {
const client = useGQLClient();
const navigate = useNavigate();
const [isLoading, setIsLoading] = React.useState(false);
const { orgSlug } = useParams();
@ -22,6 +24,7 @@ const ProjectRepoCard: React.FC<ProjectRepoCardProps> = ({ repository }) => {
return;
}
setIsLoading(true);
const { addProject } = await client.addProject(orgSlug!, {
name: `${repository.owner!.login}-${repository.name}`,
prodBranch: repository.default_branch!,
@ -30,7 +33,13 @@ const ProjectRepoCard: React.FC<ProjectRepoCardProps> = ({ repository }) => {
template: 'webapp',
});
navigate(`import?projectId=${addProject.id}`);
if (Boolean(addProject)) {
setIsLoading(false);
navigate(`import?projectId=${addProject.id}`);
} else {
setIsLoading(false);
toast.error('Failed to create project');
}
}, [client, repository]);
return (
@ -53,9 +62,13 @@ const ProjectRepoCard: React.FC<ProjectRepoCardProps> = ({ repository }) => {
</div>
<p>{repository.updated_at && relativeTimeISO(repository.updated_at)}</p>
</div>
<div className="hidden group-hover:block">
<IconButton size="sm">{'>'}</IconButton>
</div>
{isLoading ? (
<Spinner className="h-4 w-4" />
) : (
<div className="hidden group-hover:block">
<IconButton size="sm">{'>'}</IconButton>
</div>
)}
</div>
);
};

View File

@ -87,18 +87,12 @@ const DeploymentDetailsCard = ({
};
return (
<div className="grid grid-cols-4 gap-2 border-b border-gray-300 p-3 my-2">
<div className="col-span-2">
<div className="grid grid-cols-8 gap-2 border-b border-gray-300 p-3 my-2">
<div className="col-span-3">
<div className="flex">
{deployment.url && (
<Typography className=" basis-3/4">{deployment.url}</Typography>
)}
<Chip
value={deployment.status}
color={STATUS_COLORS[deployment.status] ?? 'gray'}
variant="ghost"
icon={<i>^</i>}
/>
</div>
<Typography color="gray">
{deployment.environment === Environment.Production
@ -107,13 +101,21 @@ const DeploymentDetailsCard = ({
</Typography>
</div>
<div className="col-span-1">
<Chip
value={deployment.status}
color={STATUS_COLORS[deployment.status] ?? 'gray'}
variant="ghost"
icon={<i>^</i>}
/>
</div>
<div className="col-span-2">
<Typography color="gray">^ {deployment.branch}</Typography>
<Typography color="gray">
^ {deployment.commitHash.substring(0, SHORT_COMMIT_HASH_LENGTH)}{' '}
{deployment.commitMessage}
</Typography>
</div>
<div className="col-span-1 flex items-center">
<div className="col-span-2 flex items-center">
<Typography color="gray" className="grow">
^ {relativeTimeMs(deployment.createdAt)} ^ {deployment.createdBy.name}
</Typography>

View File

@ -44,18 +44,18 @@ const FilterForm = ({ value, onChange }: FilterFormProps) => {
}, [value]);
return (
<div className="grid grid-cols-4 gap-2 text-sm text-gray-600">
<div className="col-span-2">
<div className="grid grid-cols-8 gap-2 text-sm text-gray-600">
<div className="col-span-4">
<SearchBar
placeholder="Search branches"
value={searchedBranch}
onChange={(event) => setSearchedBranch(event.target.value)}
/>
</div>
<div className="col-span-1">
<div className="col-span-2">
<DatePicker mode="range" selected={dateRange} onSelect={setDateRange} />
</div>
<div className="col-span-1 relative">
<div className="col-span-2 relative">
<Select
value={selectedStatus}
onChange={(value) => setSelectedStatus(value as StatusOptions)}

View File

@ -1,4 +1,3 @@
export const GIT_TEMPLATE_LINK =
'https://git.vdb.to/cerc-io/test-progressive-web-app';
export const GIT_TEMPLATE_LINK = `https://github.com/${process.env.REACT_APP_GITHUB_TEMPLATE_REPO}`;
export const SHORT_COMMIT_HASH_LENGTH = 8;

View File

@ -1,13 +1,40 @@
import React from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Outlet, useNavigate } from 'react-router-dom';
import { User } from 'gql-client';
import { IconButton, Typography } from '@material-tailwind/react';
import { IconButton, Tooltip, Typography } from '@material-tailwind/react';
import HorizontalLine from '../components/HorizontalLine';
import ProjectSearchBar from '../components/projects/ProjectSearchBar';
import { useGQLClient } from '../context/GQLClientContext';
const ProjectSearch = () => {
const navigate = useNavigate();
const client = useGQLClient();
const [user, setUser] = useState<User>();
const fetchUser = useCallback(async () => {
const { user } = await client.getUser();
setUser(user);
}, []);
const formattedAddress = useMemo(() => {
const address = user?.name || '';
if (address.length <= 8) {
return address;
}
if (address.startsWith('0x')) {
return address.slice(0, 4) + '..' + address.slice(-4);
}
return address;
}, [user?.name]);
useEffect(() => {
fetchUser();
}, []);
return (
<div>
@ -28,8 +55,10 @@ const ProjectSearch = () => {
<div className="mr-2 flex items-center">
<Typography>^</Typography>
</div>
<div className="px-2 py-1 bg-blue-gray-50 rounded-lg">
<Typography variant="lead">SY</Typography>
<div className="px-2 py-1 bg-blue-gray-50 rounded-lg flex items-center">
{user?.name && (
<Tooltip content={user.name}>{formattedAddress}</Tooltip>
)}
</div>
</div>
<HorizontalLine />

View File

@ -50,7 +50,7 @@ const CreateWithTemplate = () => {
<div className="grow px-2">{template?.name}</div>
<div>
<a href={GIT_TEMPLATE_LINK} target="_blank" rel="noreferrer">
^ cerc-io/test-progressive-web-app
^ {process.env.REACT_APP_GITHUB_TEMPLATE_REPO}
</a>
</div>
</div>

View File

@ -4,7 +4,7 @@ import { useNavigate, useParams } from 'react-router-dom';
import toast from 'react-hot-toast';
import assert from 'assert';
import { Option, Typography } from '@material-tailwind/react';
import { Button, Option, Typography } from '@material-tailwind/react';
import { useOctokit } from '../../../../../context/OctokitContext';
import { useGQLClient } from '../../../../../context/GQLClientContext';
@ -27,10 +27,12 @@ const CreateRepo = () => {
const navigate = useNavigate();
const [gitAccounts, setGitAccounts] = useState<string[]>([]);
const [isLoading, setIsLoading] = useState(false);
const submitRepoHandler: SubmitHandler<SubmitRepoValues> = useCallback(
async (data) => {
assert(data.account);
setIsLoading(true);
try {
assert(
@ -62,11 +64,17 @@ const CreateRepo = () => {
template: 'webapp',
});
navigate(
`/${orgSlug}/projects/create/template/deploy?projectId=${addProject.id}`,
);
if (Boolean(addProject)) {
setIsLoading(true);
navigate(
`/${orgSlug}/projects/create/template/deploy?projectId=${addProject.id}`,
);
} else {
setIsLoading(false);
}
} catch (err) {
console.error(err);
setIsLoading(false);
toast.error('Error deploying project');
}
},
@ -174,9 +182,14 @@ const CreateRepo = () => {
</label>
</div>
<div className="mb-2">
<button className="bg-blue-500 rounded-xl p-2" type="submit">
<Button
className="bg-blue-500 rounded-xl p-2"
type="submit"
disabled={isLoading}
loading={isLoading}
>
Deploy ^
</button>
</Button>
</div>
</form>
);