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:
parent
5c43ebe0d0
commit
7985bb35bb
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
||||
|
|
|
|||
|
|
@ -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.'
|
||||
|
|
|
|||
|
|
@ -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'));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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 = () => {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ export const RepositoriesList = ({ searchValue }: RepositoriesListProps) => {
|
|||
overflowX: 'hidden',
|
||||
overflowY: 'scroll',
|
||||
flexDirection: 'column',
|
||||
pr: '$3h',
|
||||
}}
|
||||
>
|
||||
{filteredRepositories.length > 0 ? (
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
)
|
||||
);
|
||||
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue