chore: UI implement changes feedback (#173)

* style: combobox add cursor pointer property

* chore: make repository row clickable

* style: fix scroll on repositories list

* chore: select main/master by deafult branch

* chore: add required icon on label form and max characters length

* Update ui/src/components/core/combobox/combobox.tsx

Co-authored-by: Felipe Mendes <zo.fmendes@gmail.com>

* chore: remove commented line

* chore: replace Form.MaxLength

* styles: fix styles for combobox icon

* chore: default branch based on repo config

---------

Co-authored-by: Felipe Mendes <zo.fmendes@gmail.com>
This commit is contained in:
Camila Sosa Morales 2023-03-13 15:56:17 -05:00 committed by GitHub
parent 5c43ebe0d0
commit 7985bb35bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 112 additions and 52 deletions

View File

@ -31,7 +31,7 @@ const ComboboxInput = ({
handleInputChange,
handleInputClick,
}: ComboboxInputProps) => (
<div className="relative w-full cursor-default ">
<div className="relative w-full">
<Icon
name={leftIcon}
size="sm"
@ -45,7 +45,7 @@ const ComboboxInput = ({
/>
<ComboboxLib.Input
placeholder="Search"
className={`w-full border-solid border border-slate7 h-11 py-3 pl-10 pr-10 text-sm leading-5 text-slate11 outline-none ${
className={`w-full border-solid border border-slate7 h-11 py-3 px-10 text-sm bg-transparent leading-5 text-slate11 outline-none ${
open
? 'border-b-0 rounded-t-xl bg-black border-slate6'
: 'rounded-xl bg-transparent'

View File

@ -11,9 +11,11 @@ import { AiOutlineTwitter } from '@react-icons/all-files/ai/AiOutlineTwitter';
import { ErrorIcon } from './custom/error';
import { IoClose } from '@react-icons/all-files/io5/IoClose';
import { AiFillCheckCircle } from '@react-icons/all-files/ai/AiFillCheckCircle';
import { BiGitBranch } from '@react-icons/all-files/bi/BiGitBranch';
export const IconLibrary = Object.freeze({
back: IoArrowBackCircleSharp,
branch: BiGitBranch,
check: AiOutlineCheck,
'check-circle': IoCheckmarkCircleSharp,
'chevron-down': AiOutlineDown,

View File

@ -33,6 +33,15 @@ export abstract class FormStyles {
},
});
static readonly RequiredLabel = styled('span', {
color: '$red11',
});
static readonly MaxLength = styled(FormStyles.Label, {
textAlign: 'right',
mt: '$1h',
});
static readonly ErrorMessage = styled('span', {
color: '$red11',
fontSize: '0.625rem',

View File

@ -14,13 +14,24 @@ export abstract class Form {
);
static readonly Label = forwardRef<HTMLLabelElement, Form.LabelProps>(
({ children, ...props }, ref) => (
({ children, isRequired, ...props }, ref) => (
<FormStyles.Label ref={ref} {...props}>
{children}
{children}{' '}
{isRequired && <FormStyles.RequiredLabel>*</FormStyles.RequiredLabel>}
</FormStyles.Label>
)
);
static readonly MaxLength = forwardRef<HTMLLabelElement, Form.LabelProps>(
({ children, ...props }, ref) => {
return (
<FormStyles.MaxLength ref={ref} {...props}>
{children}
</FormStyles.MaxLength>
);
}
);
static readonly Error = forwardRef<HTMLDivElement, Form.ErrorProps>(
({ children, ...props }, ref) => (
<FormStyles.ErrorMessage ref={ref} {...props}>
@ -55,7 +66,9 @@ export namespace Form {
children: React.ReactNode;
} & React.ComponentProps<typeof FormStyles.Field>;
export type LabelProps = React.ComponentProps<typeof FormStyles.Label>;
export type LabelProps = { isRequired?: boolean } & React.ComponentProps<
typeof FormStyles.Label
>;
export type ErrorProps = React.ComponentProps<typeof FormStyles.ErrorMessage>;

View File

@ -1,4 +1,4 @@
import { DropdownItem } from '@/components';
import { ComboboxItem } from '@/components';
import { githubActions, RootState } from '@/store';
import { AppLog } from '@/utils';
import { createAsyncThunk } from '@reduxjs/toolkit';
@ -23,7 +23,7 @@ export const fetchBranchesThunk = createAsyncThunk<void, FetchBranches>(
const branches = await githubClient.fetchBranches(owner, repository);
dispatch(githubActions.setBranches(branches as DropdownItem[]));
dispatch(githubActions.setBranches(branches as ComboboxItem[]));
} catch (error) {
AppLog.errorToast(
'We have a problem trying to get your branches. Please try again later.'

View File

@ -16,14 +16,7 @@ export const fetchRepositoriesThunk = createAsyncThunk(
const repositories = await githubClient.fetchRepos(url);
dispatch(
githubActions.setRepositories(
repositories.map((repo: any) => ({
name: repo.name,
url: repo.html_url,
}))
)
);
dispatch(githubActions.setRepositories(repositories));
} catch (error) {
console.log(error);
dispatch(githubActions.setQueryState('failed'));

View File

@ -1,5 +1,6 @@
import { DropdownItem } from '@/components';
import { Octokit } from 'octokit';
import { GithubState } from './github-slice';
export type UserData = {
value: string;
@ -50,7 +51,14 @@ export class GithubClient {
},
}).then((res) => res.json());
return repos;
return repos.map(
(repo: any) =>
({
name: repo.name,
url: repo.html_url,
defaultBranch: repo.default_branch,
} as GithubState.Repository)
);
} catch (error) {
return error;
}

View File

@ -2,7 +2,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { RootState } from '@/store';
import { useAppSelector } from '@/store/hooks';
import * as asyncThunk from './async-thunk';
import { DropdownItem } from '@/components';
import { ComboboxItem } from '@/components';
import { UserData } from './github-client';
export namespace GithubState {
@ -23,11 +23,12 @@ export namespace GithubState {
export type Repository = {
name: string;
url: string;
defaultBranch: string;
};
export type Repositories = Array<Repository>;
export type Branches = Array<DropdownItem>;
export type Branches = Array<ComboboxItem>;
}
export interface GithubState {

View File

@ -1,7 +1,7 @@
import { Dropdown, DropdownItem, Flex, Form, Spinner } from '@/components';
import { useEffect } from 'react';
import { Combobox, ComboboxItem, Flex, Form, Spinner } from '@/components';
import { githubActions, useAppDispatch, useGithubStore } from '@/store';
import { Mint } from '@/views/mint/mint.context';
import { useEffect } from 'react';
export const RepoBranchCommitFields = () => {
const { queryLoading, branches } = useGithubStore();
@ -27,7 +27,21 @@ export const RepoBranchCommitFields = () => {
}
}, [queryLoading, dispatch]);
const handleBranchChange = (dropdownOption: DropdownItem) => {
useEffect(() => {
if (queryLoading === 'success' && branches.length > 0) {
const defaultBranch = branches.find(
(branch) =>
branch.label.toLowerCase() ===
repositoryName.defaultBranch.toLowerCase()
);
if (defaultBranch) {
setBranchName(defaultBranch);
setCommitHash(defaultBranch.value);
}
}
}, [queryLoading, branches]);
const handleBranchChange = (dropdownOption: ComboboxItem) => {
setBranchName(dropdownOption);
setCommitHash(dropdownOption.value);
};
@ -54,7 +68,8 @@ export const RepoBranchCommitFields = () => {
<>
<Form.Field>
<Form.Label>Git Branch</Form.Label>
<Dropdown
<Combobox
leftIcon="branch"
items={branches}
selectedValue={branchName}
onChange={handleBranchChange}

View File

@ -1,6 +1,6 @@
import { Button, Card, Flex, Stepper } from '@/components';
import { Mint } from '@/views/mint/mint.context';
import { RepoRow } from '../github-repository-selection';
import { RepoRow } from '../repository-row';
import { RepoBranchCommitFields } from './repo-branch-commit-fields';
export const RepoConfigurationBody = () => {

View File

@ -20,27 +20,6 @@ export const Loading = () => (
</Flex>
);
type RepoRowProps = {
repo: string;
button: React.ReactNode;
} & React.ComponentProps<typeof Flex>;
export const RepoRow = forwardRef<HTMLDivElement, RepoRowProps>(
({ repo, button, ...props }, ref) => (
<Flex
{...props}
ref={ref}
css={{ justifyContent: 'space-between', my: '$4', ...props.css }}
>
<Flex css={{ alignItems: 'center' }}>
<Icon name="github" css={{ fontSize: '$2xl', mr: '$2' }} />
<span>{repo}</span>
</Flex>
{button}
</Flex>
)
);
export const GithubRepositoryConnection: React.FC = () => {
const { queryLoading, queryUserAndOrganizations } = useGithubStore();
const [searchValue, setSearchValue] = useState('');
@ -64,14 +43,14 @@ export const GithubRepositoryConnection: React.FC = () => {
};
return (
<Card.Container css={{ maxWidth: '$107h', maxHeight: '$95h', pb: '$0h' }}>
<Card.Container css={{ maxWidth: '$107h', maxHeight: '$95h', pr: '$3h' }}>
<MintCardHeader
title="Select Repository"
onClickBack={handlePrevStepClick}
/>
<Card.Body css={{ pt: '$4' }}>
<Grid css={{ rowGap: '$2' }}>
<Flex css={{ gap: '$4' }}>
<Flex css={{ gap: '$4', pr: '$3h' }}>
<UserOrgsCombobox />
<Input
leftIcon="search"

View File

@ -39,6 +39,7 @@ export const RepositoriesList = ({ searchValue }: RepositoriesListProps) => {
overflowX: 'hidden',
overflowY: 'scroll',
flexDirection: 'column',
pr: '$3h',
}}
>
{filteredRepositories.length > 0 ? (

View File

@ -1,7 +1,7 @@
import { Button, Separator } from '@/components';
import { githubActions, GithubState, useAppDispatch } from '@/store';
import { Mint } from '@/views/mint/mint.context';
import { RepoRow } from './github-repository-selection';
import { RepoRow } from '../repository-row';
type RepositoryProps = {
repository: GithubState.Repository;
@ -21,13 +21,13 @@ export const Repository = ({ repository, index, length }: RepositoryProps) => {
return (
<>
<RepoRow
onClick={handleSelectRepo}
repo={repository.name}
button={
<Button
colorScheme="blue"
variant="outline"
css={{ py: '$1', height: '$5', borderRadius: '$md' }}
onClick={handleSelectRepo}
>
Use for NFA
</Button>

View File

@ -0,0 +1,28 @@
import { Flex, Icon } from '@/components';
import { forwardRef } from 'react';
type RepoRowProps = {
repo: string;
button: React.ReactNode;
} & React.ComponentProps<typeof Flex>;
export const RepoRow = forwardRef<HTMLDivElement, RepoRowProps>(
({ repo, button, ...props }, ref) => (
<Flex
{...props}
ref={ref}
css={{
justifyContent: 'space-between',
my: '$4',
...props.css,
cursor: 'pointer',
}}
>
<Flex css={{ alignItems: 'center' }}>
<Icon name="github" css={{ fontSize: '$2xl', mr: '$2' }} />
<span>{repo}</span>
</Flex>
{button}
</Flex>
)
);

View File

@ -1,24 +1,30 @@
import { Form } from '@/components';
import { Mint } from '../../../mint.context';
const maxCharacters = 250;
export const AppDescriptionField = () => {
const { appDescription, setAppDescription } = Mint.useContext();
const handleAppDescriptionChange = (
e: React.ChangeEvent<HTMLTextAreaElement>
) => {
if (e.target.value.length > maxCharacters) return;
setAppDescription(e.target.value);
};
return (
<Form.Field>
<Form.Label>Description</Form.Label>
<Form.Label isRequired>Description</Form.Label>
<Form.Textarea
placeholder="Add information about your project here."
css={{ height: 'auto' }}
value={appDescription}
onChange={handleAppDescriptionChange}
/>
<Form.MaxLength>
{appDescription.length}/{maxCharacters}
</Form.MaxLength>
</Form.Field>
);
};

View File

@ -1,6 +1,8 @@
import { Form } from '@/components';
import { Mint } from '../../../mint.context';
const maxCharacters = 100;
export const AppNameField = () => {
const { appName, setAppName } = Mint.useContext();
@ -9,12 +11,15 @@ export const AppNameField = () => {
};
return (
<Form.Field>
<Form.Label>Name</Form.Label>
<Form.Label isRequired>Name</Form.Label>
<Form.Input
placeholder="Your app name"
value={appName}
onChange={handleAppNameChange}
/>
<Form.MaxLength>
{appName.length}/{maxCharacters}
</Form.MaxLength>
</Form.Field>
);
};

View File

@ -9,7 +9,7 @@ export const DomainField = () => {
};
return (
<Form.Field css={{ flex: 1 }}>
<Form.Label>Domain</Form.Label>
<Form.Label isRequired>Domain</Form.Label>
<Form.Input
placeholder="mydomain.com"
value={domain}

View File

@ -27,7 +27,7 @@ export const LogoField = () => {
return (
<Flex css={{ width: '$full', gap: '$4h', alignItems: 'flex-start' }}>
<Form.Field>
<Form.Label>Logo</Form.Label>
<Form.Label isRequired>Logo</Form.Label>
<Form.LogoFileInput value={appLogo} onChange={handleFileChange} />
{errorMessage && <Form.Error>{errorMessage}</Form.Error>}
</Form.Field>