Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Added view toggle for password input field #4303

Merged
merged 1 commit into from Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,21 @@
.fieldContainer {
gap: 0.15rem;
.inputContainer {
:global {
.bp3-form-group {
margin-bottom: 0 !important;
}
.bp3-input-group .bp3-input:not(:last-child) {
padding-right: 36px !important;
}
}
position: relative;
}
.eyeIcon {
position: absolute;
right: 0.5rem;
top: 50%;
transform: translateY(-50%);
z-index: 1;
}
}
@@ -0,0 +1,11 @@
declare namespace PasswordInputModuleScssNamespace {
export interface IPasswordInputModuleScss {
eyeIcon: string;
fieldContainer: string;
inputContainer: string;
}
}

declare const PasswordInputModuleScssModule: PasswordInputModuleScssNamespace.IPasswordInputModuleScss;

export = PasswordInputModuleScssModule;
45 changes: 45 additions & 0 deletions chaoscenter/web/src/components/PasswordInput/PasswordInput.tsx
@@ -0,0 +1,45 @@
import React from 'react';
import { Icon, IconName } from '@harnessio/icons';
import { FormInput, Layout, Text } from '@harnessio/uicore';
import { Color, FontVariation } from '@harnessio/design-system';
import style from './PasswordInput.module.scss';

interface PassowrdInputProps {
disabled?: boolean;
placeholder?: string;
name: string;
label: string;
}

const PassowrdInput = (props: PassowrdInputProps): React.ReactElement => {
const { disabled, label, name, placeholder } = props;
const [showPassword, setShowPassword] = React.useState(false);
const stateIcon: IconName = showPassword ? 'eye-off' : 'eye-open';

function handleToggleClick(): void {
setShowPassword(!showPassword);
}

return (
<Layout.Vertical className={style.fieldContainer}>
{label && (
<Text font={{ variation: FontVariation.BODY, weight: 'semi-bold' }} color={Color.GREY_600}>
{label}
</Text>
)}
<div className={style.inputContainer}>
<FormInput.Text
name={name}
inputGroup={{
type: showPassword ? 'text' : 'password'
}}
placeholder={placeholder}
disabled={disabled}
/>
<Icon name={stateIcon} size={20} onClick={handleToggleClick} className={style.eyeIcon} />
</div>
</Layout.Vertical>
);
};

export default PassowrdInput;
3 changes: 3 additions & 0 deletions chaoscenter/web/src/components/PasswordInput/index.ts
@@ -0,0 +1,3 @@
import PassowrdInput from './PasswordInput';

export default PassowrdInput;
@@ -0,0 +1,7 @@
.mainWrapper {
:global {
.bp3-form-group {
margin-bottom: 0 !important;
}
}
}
@@ -0,0 +1,9 @@
declare namespace UserNameInputModuleScssNamespace {
export interface IUserNameInputModuleScss {
mainWrapper: string;
}
}

declare const UserNameInputModuleScssModule: UserNameInputModuleScssNamespace.IUserNameInputModuleScss;

export = UserNameInputModuleScssModule;
28 changes: 28 additions & 0 deletions chaoscenter/web/src/components/UserNameInput/UserNameInput.tsx
@@ -0,0 +1,28 @@
import React from 'react';
import { Color, FontVariation } from '@harnessio/design-system';
import { FormInput, Layout, Text } from '@harnessio/uicore';
import style from './UserNameInput.module.scss';

interface UserNameInputProps {
disabled?: boolean;
placeholder?: string;
name: string;
label: string;
}

const UserNameInput = (props: UserNameInputProps): React.ReactElement => {
const { disabled, label, name, placeholder } = props;

return (
<Layout.Vertical style={{ gap: '0.15rem' }} className={style.mainWrapper}>
{label && (
<Text font={{ variation: FontVariation.BODY, weight: 'semi-bold' }} color={Color.GREY_600}>
{label}
</Text>
)}
<FormInput.Text name={name} placeholder={placeholder} disabled={disabled} />
</Layout.Vertical>
);
};

export default UserNameInput;
3 changes: 3 additions & 0 deletions chaoscenter/web/src/components/UserNameInput/index.ts
@@ -0,0 +1,3 @@
import UserNameInput from './UserNameInput';

export default UserNameInput;
1 change: 1 addition & 0 deletions chaoscenter/web/src/strings/strings.en.yaml
Expand Up @@ -1005,6 +1005,7 @@ showDisabledUsers: Include disabled users
showLess: ' Show less'
showingAll: Showing all
showingLastRuns: Showing last 50 runs only
signIn: Sign In
signOut: Sign Out
singleRun: Single Run
source: Source
Expand Down
1 change: 1 addition & 0 deletions chaoscenter/web/src/strings/types.ts
Expand Up @@ -848,6 +848,7 @@ export interface StringsMap {
'showLess': unknown
'showingAll': unknown
'showingLastRuns': unknown
'signIn': unknown
'signOut': unknown
'singleRun': unknown
'source': unknown
Expand Down
72 changes: 43 additions & 29 deletions chaoscenter/web/src/views/Login/LoginPage.tsx
@@ -1,12 +1,14 @@
import React from 'react';
import { FormInput, Formik, Button, Text, Container } from '@harnessio/uicore';
import { Formik, Button, Text, Container, Layout } from '@harnessio/uicore';
import { Icon } from '@harnessio/icons';
import { Color } from '@harnessio/design-system';
import { Form } from 'formik';
import type { UseMutateFunction } from '@tanstack/react-query';
import AuthLayout from '@components/AuthLayout/AuthLayout';
import { useStrings } from '@strings';
import type { ErrorModel, LoginMutationProps, LoginResponse } from '@api/auth';
import PassowrdInput from '@components/PasswordInput';
import UserNameInput from '@components/UserNameInput';

interface LoginForm {
username: string;
Expand All @@ -22,36 +24,48 @@ export default function LoginPageView({ handleLogin, loading }: LoginPageViewPro
const { getString } = useStrings();

return (
<>
<AuthLayout>
<Icon name="chaos-litmuschaos" size={60} margin={{ bottom: 'medium' }} />
<Text font={{ size: 'large', weight: 'bold' }} color={Color.BLACK}>
{getString('welcomeToLitmus')}
</Text>
<Text font={{ size: 'medium' }} color={Color.BLACK} margin={{ top: 'xsmall' }}>
{getString('loginDescription')}
</Text>
<AuthLayout>
<Icon name="chaos-litmuschaos" size={60} margin={{ bottom: 'medium' }} />
<Text font={{ size: 'large', weight: 'bold' }} color={Color.BLACK}>
{getString('welcomeToLitmus')}
</Text>
<Text font={{ size: 'medium' }} color={Color.BLACK} margin={{ top: 'xsmall' }}>
{getString('loginDescription')}
</Text>

<Container margin={{ top: 'xxxlarge' }}>
<Formik<LoginForm>
initialValues={{ username: '', password: '' }}
formName="loginPageForm"
onSubmit={data =>
handleLogin({
body: data
})
}
>
<Form>
<FormInput.Text name="username" label={`Username`} disabled={loading} />
<FormInput.Text name="password" label={'Password'} inputGroup={{ type: 'password' }} disabled={loading} />
<Container margin={{ top: 'xxxlarge' }}>
<Formik<LoginForm>
initialValues={{ username: '', password: '' }}
formName="loginPageForm"
onSubmit={data =>
handleLogin({
body: data
})
}
>
<Form>
<Layout.Vertical style={{ gap: '1.5rem' }}>
<Layout.Vertical style={{ gap: '1rem' }} width={'100%'}>
<UserNameInput
name="username"
label={getString('username')}
placeholder={getString('enterYourUsername')}
disabled={loading}
/>
<PassowrdInput
name="password"
label={getString('password')}
placeholder={getString('enterYourPassword')}
disabled={loading}
/>
</Layout.Vertical>
<Button type="submit" intent="primary" loading={loading} disabled={loading} width="100%">
{'Sign in'}
{getString('signIn')}
</Button>
</Form>
</Formik>
</Container>
</AuthLayout>
</>
</Layout.Vertical>
</Form>
</Formik>
</Container>
</AuthLayout>
);
}