From 2d81403f9512aac47900d4adb76fcc921814577b Mon Sep 17 00:00:00 2001 From: Hubert Koster Date: Mon, 3 Jul 2023 14:35:23 +0200 Subject: [PATCH 01/15] chore: adding field validation --- .../ApiTokenForm/api-token.form.tsx | 64 +++++++++++++++++-- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx b/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx index 173446f15..ef16b0ab3 100644 --- a/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx +++ b/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx @@ -1,4 +1,4 @@ -import React, { HTMLAttributes, useCallback, useState } from 'react'; +import React, { HTMLAttributes, useCallback, useEffect, useState } from 'react'; import { Button, Text } from '@deriv/ui'; import { useForm } from 'react-hook-form'; import { Circles } from 'react-loader-spinner'; @@ -6,6 +6,7 @@ import { yupResolver } from '@hookform/resolvers/yup'; import { scopesObjectToArray } from '@site/src/utils'; import ApiTokenCard from '../ApiTokenCard'; import useCreateToken from '@site/src/features/dashboard/hooks/useCreateToken'; +import useApiToken from '@site/src/hooks/useApiToken'; import * as yup from 'yup'; import styles from './api-token.form.module.scss'; @@ -16,7 +17,18 @@ const schema = yup payments: yup.boolean(), trading_information: yup.boolean(), admin: yup.boolean(), - name: yup.string().required(), + name: yup + .string() + .required() + .max(32, 'Only up to 32 characters are allowed.') + .matches(/^[a-z0-9_\-\s]*$/, { + message: 'Only alphanumeric characters with spaces and underscores are allowed.', + excludeEmptyString: true, + }) + .matches(/^(?!\s)[a-z0-9_\-\s]*(?) => { + const [input_value, setInputValue] = useState(''); + const [token_names, setTokenNames] = useState([]); + const [is_invalid_token, setIsInvalidToken] = useState(false); const { createToken, isCreatingToken } = useCreateToken(); + const { tokens } = useApiToken(); - const { handleSubmit, register, setValue, getValues, reset } = useForm({ + const { + handleSubmit, + register, + setValue, + getValues, + reset, + formState: { errors }, + } = useForm({ resolver: yupResolver(schema), mode: 'all', }); + useEffect(() => { + if (tokens.length > 0) { + tokens.forEach((token_object) => { + setTokenNames((prevState) => [...prevState, token_object.display_name]); + }); + } + }, [tokens]); + + useEffect(() => { + if (token_names.includes(input_value)) { + setIsInvalidToken(true); + } else { + setIsInvalidToken(false); + } + }, [input_value, token_names]); + const onSubmit = useCallback( (data: TApiTokenForm) => { const { name } = data; @@ -134,10 +173,25 @@ const ApiTokenForm = (props: HTMLAttributes) => { -
+
setInputValue((e.target as HTMLInputElement).value)} + className={styles.customTextInput} + > - +
+ {errors && errors?.name && ( + + {errors.name?.message} + + )} + {is_invalid_token && ( +
+

That name is taken. Choose another.

+
+ )}

Length of token name must be between 2 and 32 characters.

From 7996d598ec8b07c15ae1d0c5856c56a64026a1bd Mon Sep 17 00:00:00 2001 From: Hubert Koster Date: Tue, 4 Jul 2023 09:25:53 +0200 Subject: [PATCH 02/15] chore: adding more functionality --- .../ApiTokenForm/api-token.form.tsx | 26 +++++++++++++------ src/styles/index.scss | 4 +++ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx b/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx index ef16b0ab3..375b0bd3f 100644 --- a/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx +++ b/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx @@ -19,16 +19,22 @@ const schema = yup admin: yup.boolean(), name: yup .string() - .required() .max(32, 'Only up to 32 characters are allowed.') - .matches(/^[a-z0-9_\-\s]*$/, { + .matches(/^[a-zA-Z0-9_\-\s]*$/, { message: 'Only alphanumeric characters with spaces and underscores are allowed.', excludeEmptyString: true, }) - .matches(/^(?!\s)[a-z0-9_\-\s]*(?) => { mode: 'all', }); + const disable_button = is_invalid_token || Object.keys(errors).length > 0 || input_value === ''; + useEffect(() => { if (tokens.length > 0) { tokens.forEach((token_object) => { - setTokenNames((prevState) => [...prevState, token_object.display_name]); + const token_lowercase = token_object.display_name.toLowerCase(); + setTokenNames((prevState) => [...prevState, token_lowercase]); }); } }, [tokens]); useEffect(() => { - if (token_names.includes(input_value)) { + const token_name_exists = token_names.includes(input_value.toLowerCase()); + if (token_name_exists) { setIsInvalidToken(true); } else { setIsInvalidToken(false); @@ -175,10 +185,10 @@ const ApiTokenForm = (props: HTMLAttributes) => {
setInputValue((e.target as HTMLInputElement).value)} - className={styles.customTextInput} + className={`${styles.customTextInput} ${errors.name ? 'error-border' : ''}`} > -
diff --git a/src/styles/index.scss b/src/styles/index.scss index 4f0055caa..69eeaf8bf 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -89,6 +89,10 @@ h6 { color: var(--colors-coral500) !important; } +.error-border { + border-color: var(--colors-coral500) !important; +} + /* reset */ button { all: unset; From d73a09c87cd4e35d93bf9e7da30d7119df76272f Mon Sep 17 00:00:00 2001 From: Hubert Koster Date: Fri, 7 Jul 2023 12:18:11 +0200 Subject: [PATCH 03/15] chore: remove optional chaining --- .../__tests__/api-token.form.test.tsx | 38 +++++++++++++++++++ .../ApiTokenForm/api-token.form.tsx | 36 +++++++++++------- 2 files changed, 61 insertions(+), 13 deletions(-) diff --git a/src/features/dashboard/components/ApiTokenForm/__tests__/api-token.form.test.tsx b/src/features/dashboard/components/ApiTokenForm/__tests__/api-token.form.test.tsx index d36fbe738..b1b6115ec 100644 --- a/src/features/dashboard/components/ApiTokenForm/__tests__/api-token.form.test.tsx +++ b/src/features/dashboard/components/ApiTokenForm/__tests__/api-token.form.test.tsx @@ -3,6 +3,32 @@ import { cleanup, render, screen, within } from '@site/src/test-utils'; import userEvent from '@testing-library/user-event'; import ApiTokenForm from '../api-token.form'; import useCreateToken from '../../../hooks/useCreateToken'; +import useApiToken from '@site/src/hooks/useApiToken'; + +jest.mock('@site/src/hooks/useApiToken'); + +const mockUseApiToken = useApiToken as jest.MockedFunction< + () => Partial> +>; + +mockUseApiToken.mockImplementation(() => ({ + tokens: [ + { + display_name: 'testtoken1', + last_used: '', + scopes: ['read', 'trade', 'payments', 'admin'], + token: 'asdf1234', + valid_for_ip: '', + }, + { + display_name: 'testtoken2', + last_used: '', + scopes: ['read', 'trade', 'payments', 'admin'], + token: 'asdf1235', + valid_for_ip: '', + }, + ], +})); jest.mock('@site/src/features/dashboard/hooks/useCreateToken'); @@ -103,6 +129,18 @@ describe('Home Page', () => { expect(mockCreateToken).toHaveBeenCalledWith('test create token', []); }); + it('Should not be able to create a token if name already exists', async () => { + const nameInput = screen.getByRole('textbox'); + + await userEvent.type(nameInput, 'testtoken1'); + + const submitButton = screen.getByRole('button', { name: /Create/i }); + await userEvent.click(submitButton); + + const error = screen.getByText(/That name is taken. Choose another./i); + expect(error).toBeVisible; + }); + it('Should not create token when name input is empty', async () => { const nameInput = screen.getByRole('textbox'); diff --git a/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx b/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx index 375b0bd3f..600a64cea 100644 --- a/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx +++ b/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx @@ -20,12 +20,9 @@ const schema = yup name: yup .string() .max(32, 'Only up to 32 characters are allowed.') - .matches(/^[a-zA-Z0-9_\-\s]*$/, { - message: 'Only alphanumeric characters with spaces and underscores are allowed.', - excludeEmptyString: true, - }) - .matches(/^(?!\s)[a-zA-Z0-9_\-\s]*(?) => { const [input_value, setInputValue] = useState(''); const [token_names, setTokenNames] = useState([]); + const [has_tokens, setHasTokens] = useState(false); const [is_invalid_token, setIsInvalidToken] = useState(false); const { createToken, isCreatingToken } = useCreateToken(); const { tokens } = useApiToken(); @@ -100,15 +98,27 @@ const ApiTokenForm = (props: HTMLAttributes) => { const disable_button = is_invalid_token || Object.keys(errors).length > 0 || input_value === ''; + const newTokenArray = () => { + const token_array = []; + for (const token_object of tokens) { + const token_name = token_object.display_name.toLowerCase(); + token_array.push(token_name); + setTokenNames(token_array); + } + }; + useEffect(() => { - if (tokens.length > 0) { - tokens.forEach((token_object) => { - const token_lowercase = token_object.display_name.toLowerCase(); - setTokenNames((prevState) => [...prevState, token_lowercase]); - }); + if (tokens.length !== 0) { + setHasTokens(true); } }, [tokens]); + useEffect(() => { + if (has_tokens) { + newTokenArray(); + } + }, [has_tokens]); + useEffect(() => { const token_name_exists = token_names.includes(input_value.toLowerCase()); if (token_name_exists) { @@ -192,9 +202,9 @@ const ApiTokenForm = (props: HTMLAttributes) => { Create - {errors && errors?.name && ( + {errors && errors.name && ( - {errors.name?.message} + {errors.name.message} )} {is_invalid_token && ( From c86dfe8d852c26a27a07f6c852dd7239c402806a Mon Sep 17 00:00:00 2001 From: Hubert Koster Date: Tue, 11 Jul 2023 14:47:09 +0200 Subject: [PATCH 04/15] chore: optimizing code --- .../ApiTokenForm/CreateTokenField/index.tsx | 87 +++++++++++++++++++ .../__tests__/api-token.form.test.tsx | 3 - .../ApiTokenForm/api-token.form.tsx | 80 +++-------------- .../ApiTokenTable/DeleteTokenDialog/index.tsx | 1 - .../ApiTokenTable/table.lastused.cell.tsx | 1 + 5 files changed, 99 insertions(+), 73 deletions(-) create mode 100644 src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx diff --git a/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx b/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx new file mode 100644 index 000000000..b7a2f055c --- /dev/null +++ b/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx @@ -0,0 +1,87 @@ +import React, { Dispatch, SetStateAction, useCallback, useEffect, useState } from 'react'; +import { Text, Button } from '@deriv/ui'; +import styles from '../api-token.form.module.scss'; +import useApiToken from '@site/src/hooks/useApiToken'; +import { FieldErrorsImpl, UseFormRegisterReturn } from 'react-hook-form'; + +type TCreateTokenField = { + register: UseFormRegisterReturn; + errors: Partial< + FieldErrorsImpl<{ + read: boolean; + trade: boolean; + payments: boolean; + trading_information: boolean; + admin: boolean; + name: string; + }> + >; + form_is_cleared: boolean; + setFormIsCleared: Dispatch>; +}; + +const CreateTokenField = ({ + errors, + register, + form_is_cleared, + setFormIsCleared, +}: TCreateTokenField) => { + const { tokens } = useApiToken(); + const [input_value, setInputValue] = useState(''); + + useEffect(() => { + if (form_is_cleared) { + setInputValue(''); + setFormIsCleared(false); + } + }, [form_is_cleared]); + console.log(errors); + + const getTokenNames = useCallback(() => { + const token_names = []; + for (const token_object of tokens) { + const token_name = token_object.display_name.toLowerCase(); + token_names.push(token_name); + } + return token_names; + }, [tokens]); + + const token_name_exists = getTokenNames().includes(input_value.toLowerCase()); + const disable_button = token_name_exists || Object.keys(errors).length > 0 || input_value === ''; + + return ( + +
+
+ + Name your token and click on Create to generate your token. + +
+
+
setInputValue((e.target as HTMLInputElement).value)} + className={`${styles.customTextInput} ${errors.name ? 'error-border' : ''}`} + > + + +
+ {errors && errors.name && ( + + {errors.name.message} + + )} + {token_name_exists && ( +
+

That name is taken. Choose another.

+
+ )} +
+

Length of token name must be between 2 and 32 characters.

+
+
+ ); +}; + +export default CreateTokenField; diff --git a/src/features/dashboard/components/ApiTokenForm/__tests__/api-token.form.test.tsx b/src/features/dashboard/components/ApiTokenForm/__tests__/api-token.form.test.tsx index b1b6115ec..16bb238ff 100644 --- a/src/features/dashboard/components/ApiTokenForm/__tests__/api-token.form.test.tsx +++ b/src/features/dashboard/components/ApiTokenForm/__tests__/api-token.form.test.tsx @@ -134,9 +134,6 @@ describe('Home Page', () => { await userEvent.type(nameInput, 'testtoken1'); - const submitButton = screen.getByRole('button', { name: /Create/i }); - await userEvent.click(submitButton); - const error = screen.getByText(/That name is taken. Choose another./i); expect(error).toBeVisible; }); diff --git a/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx b/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx index 600a64cea..633282039 100644 --- a/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx +++ b/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx @@ -1,14 +1,14 @@ -import React, { HTMLAttributes, useCallback, useEffect, useState } from 'react'; -import { Button, Text } from '@deriv/ui'; +import React, { HTMLAttributes, useCallback, useState } from 'react'; +import { Text } from '@deriv/ui'; import { useForm } from 'react-hook-form'; import { Circles } from 'react-loader-spinner'; import { yupResolver } from '@hookform/resolvers/yup'; import { scopesObjectToArray } from '@site/src/utils'; import ApiTokenCard from '../ApiTokenCard'; import useCreateToken from '@site/src/features/dashboard/hooks/useCreateToken'; -import useApiToken from '@site/src/hooks/useApiToken'; import * as yup from 'yup'; import styles from './api-token.form.module.scss'; +import CreateTokenField from './CreateTokenField'; const schema = yup .object({ @@ -77,12 +77,8 @@ const scopes: TScope[] = [ ]; const ApiTokenForm = (props: HTMLAttributes) => { - const [input_value, setInputValue] = useState(''); - const [token_names, setTokenNames] = useState([]); - const [has_tokens, setHasTokens] = useState(false); - const [is_invalid_token, setIsInvalidToken] = useState(false); const { createToken, isCreatingToken } = useCreateToken(); - const { tokens } = useApiToken(); + const [form_is_cleared, setFormIsCleared] = useState(false); const { handleSubmit, @@ -96,38 +92,6 @@ const ApiTokenForm = (props: HTMLAttributes) => { mode: 'all', }); - const disable_button = is_invalid_token || Object.keys(errors).length > 0 || input_value === ''; - - const newTokenArray = () => { - const token_array = []; - for (const token_object of tokens) { - const token_name = token_object.display_name.toLowerCase(); - token_array.push(token_name); - setTokenNames(token_array); - } - }; - - useEffect(() => { - if (tokens.length !== 0) { - setHasTokens(true); - } - }, [tokens]); - - useEffect(() => { - if (has_tokens) { - newTokenArray(); - } - }, [has_tokens]); - - useEffect(() => { - const token_name_exists = token_names.includes(input_value.toLowerCase()); - if (token_name_exists) { - setIsInvalidToken(true); - } else { - setIsInvalidToken(false); - } - }, [input_value, token_names]); - const onSubmit = useCallback( (data: TApiTokenForm) => { const { name } = data; @@ -139,6 +103,7 @@ const ApiTokenForm = (props: HTMLAttributes) => { trading_information: data.trading_information, }); createToken(name, selectedTokenScope); + setFormIsCleared(true); reset(); }, [createToken, reset], @@ -186,35 +151,12 @@ const ApiTokenForm = (props: HTMLAttributes) => { /> ))} -
-
- - Name your token and click on Create to generate your token. - -
-
-
setInputValue((e.target as HTMLInputElement).value)} - className={`${styles.customTextInput} ${errors.name ? 'error-border' : ''}`} - > - - -
- {errors && errors.name && ( - - {errors.name.message} - - )} - {is_invalid_token && ( -
-

That name is taken. Choose another.

-
- )} -
-

Length of token name must be between 2 and 32 characters.

-
+
diff --git a/src/features/dashboard/components/ApiTokenTable/DeleteTokenDialog/index.tsx b/src/features/dashboard/components/ApiTokenTable/DeleteTokenDialog/index.tsx index e5a783eda..dfe4cec4d 100644 --- a/src/features/dashboard/components/ApiTokenTable/DeleteTokenDialog/index.tsx +++ b/src/features/dashboard/components/ApiTokenTable/DeleteTokenDialog/index.tsx @@ -32,7 +32,6 @@ const DeleteTokenDialog = ({ onDelete, setToggleModal }: TDeleteTokendialog) => text: 'Yes, delete', color: 'primary', onClick: () => { - setToggleModal(false); onDelete(); }, }, diff --git a/src/features/dashboard/components/ApiTokenTable/table.lastused.cell.tsx b/src/features/dashboard/components/ApiTokenTable/table.lastused.cell.tsx index 9734e4b43..8c315be79 100644 --- a/src/features/dashboard/components/ApiTokenTable/table.lastused.cell.tsx +++ b/src/features/dashboard/components/ApiTokenTable/table.lastused.cell.tsx @@ -16,6 +16,7 @@ const ApiLastUsedCell = ({ const onDelete = () => { const values = row.original; deleteToken(values.token); + setToggleModal(false); }; return ( From 1f3aa00e6670655f5f5f7134aea7c99a7c65a751 Mon Sep 17 00:00:00 2001 From: Hubert Koster Date: Tue, 11 Jul 2023 14:47:44 +0200 Subject: [PATCH 05/15] chore: removing console log --- .../dashboard/components/ApiTokenForm/CreateTokenField/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx b/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx index b7a2f055c..bae8e39e2 100644 --- a/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx +++ b/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx @@ -35,7 +35,6 @@ const CreateTokenField = ({ setFormIsCleared(false); } }, [form_is_cleared]); - console.log(errors); const getTokenNames = useCallback(() => { const token_names = []; From 91d9cfdbe465893c20003c3e05831f9f04a63e64 Mon Sep 17 00:00:00 2001 From: Hubert Koster Date: Tue, 11 Jul 2023 16:05:44 +0200 Subject: [PATCH 06/15] chore: adding extra validation --- .../ApiTokenForm/CreateTokenField/index.tsx | 11 +++++++++-- .../components/ApiTokenForm/api-token.form.tsx | 1 + src/styles/index.scss | 6 ++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx b/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx index bae8e39e2..e0dc0eec3 100644 --- a/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx +++ b/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx @@ -47,6 +47,7 @@ const CreateTokenField = ({ const token_name_exists = getTokenNames().includes(input_value.toLowerCase()); const disable_button = token_name_exists || Object.keys(errors).length > 0 || input_value === ''; + const error_border_active = token_name_exists || errors.name; return ( @@ -59,9 +60,15 @@ const CreateTokenField = ({
setInputValue((e.target as HTMLInputElement).value)} - className={`${styles.customTextInput} ${errors.name ? 'error-border' : ''}`} + className={`${styles.customTextInput} ${error_border_active ? 'error-border' : ''}`} > - + diff --git a/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx b/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx index 633282039..8c7035f1a 100644 --- a/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx +++ b/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx @@ -19,6 +19,7 @@ const schema = yup admin: yup.boolean(), name: yup .string() + .min(2, 'Your token name must be atleast 2 characters long.') .max(32, 'Only up to 32 characters are allowed.') .matches(/^[a-zA-Z0-9]+(?:[- _][a-zA-Z0-9]+)*$/, { message: diff --git a/src/styles/index.scss b/src/styles/index.scss index 69eeaf8bf..89b6d12aa 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -91,6 +91,12 @@ h6 { .error-border { border-color: var(--colors-coral500) !important; + &:focus-within { + border-color: var(--colors-coral500) !important; + } + &:focus { + outline: var(--colors-coral500) !important; + } } /* reset */ From 79cb7289ea22162304632ec40a6d87d3688506bc Mon Sep 17 00:00:00 2001 From: Hubert Koster Date: Wed, 12 Jul 2023 11:25:22 +0200 Subject: [PATCH 07/15] chore: refactor --- .../components/ApiTokenForm/CreateTokenField/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx b/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx index e0dc0eec3..56db11106 100644 --- a/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx +++ b/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx @@ -1,4 +1,4 @@ -import React, { Dispatch, SetStateAction, useCallback, useEffect, useState } from 'react'; +import React, { Dispatch, SetStateAction, useEffect, useMemo, useState } from 'react'; import { Text, Button } from '@deriv/ui'; import styles from '../api-token.form.module.scss'; import useApiToken from '@site/src/hooks/useApiToken'; @@ -36,7 +36,7 @@ const CreateTokenField = ({ } }, [form_is_cleared]); - const getTokenNames = useCallback(() => { + const getTokenNames = useMemo(() => { const token_names = []; for (const token_object of tokens) { const token_name = token_object.display_name.toLowerCase(); @@ -45,7 +45,7 @@ const CreateTokenField = ({ return token_names; }, [tokens]); - const token_name_exists = getTokenNames().includes(input_value.toLowerCase()); + const token_name_exists = getTokenNames.includes(input_value.toLowerCase()); const disable_button = token_name_exists || Object.keys(errors).length > 0 || input_value === ''; const error_border_active = token_name_exists || errors.name; From e33bb2cfeb6335fd4327baadaf5ecdb3e78f9d6d Mon Sep 17 00:00:00 2001 From: Hubert Koster Date: Fri, 14 Jul 2023 11:17:51 +0200 Subject: [PATCH 08/15] chore: updating regex --- .../dashboard/components/ApiTokenForm/api-token.form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx b/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx index 8c7035f1a..73531f7a6 100644 --- a/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx +++ b/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx @@ -21,7 +21,7 @@ const schema = yup .string() .min(2, 'Your token name must be atleast 2 characters long.') .max(32, 'Only up to 32 characters are allowed.') - .matches(/^[a-zA-Z0-9]+(?:[- _][a-zA-Z0-9]+)*$/, { + .matches(/^(?=.*[a-zA-Z0-9])[a-zA-Z0-9_ ]*$/, { message: 'Only alphanumeric characters with spaces, dashes and underscores are allowed. (Example: my_application)', excludeEmptyString: true, From a928d783a796ac72062e9fb5b657ee1b05f48e04 Mon Sep 17 00:00:00 2001 From: Hubert Koster Date: Fri, 14 Jul 2023 11:53:53 +0200 Subject: [PATCH 09/15] chore: updating error --- .../components/ApiTokenForm/CreateTokenField/index.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx b/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx index 56db11106..39a34307b 100644 --- a/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx +++ b/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx @@ -46,6 +46,8 @@ const CreateTokenField = ({ }, [tokens]); const token_name_exists = getTokenNames.includes(input_value.toLowerCase()); + const no_min_max_error = + (errors && errors.name?.type === 'min') || (errors && errors.name?.type === 'max'); const disable_button = token_name_exists || Object.keys(errors).length > 0 || input_value === ''; const error_border_active = token_name_exists || errors.name; @@ -83,9 +85,11 @@ const CreateTokenField = ({

That name is taken. Choose another.

)} -
-

Length of token name must be between 2 and 32 characters.

-
+ {!no_min_max_error && ( +
+

Length of token name must be between 2 and 32 characters.

+
+ )} ); }; From f839bfd7e6f554d24ba19d65b4082f41baf2f3cb Mon Sep 17 00:00:00 2001 From: Hubert Koster Date: Fri, 14 Jul 2023 13:30:26 +0200 Subject: [PATCH 10/15] chore: updating error message --- .../dashboard/components/ApiTokenForm/api-token.form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx b/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx index 73531f7a6..060f48686 100644 --- a/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx +++ b/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx @@ -23,7 +23,7 @@ const schema = yup .max(32, 'Only up to 32 characters are allowed.') .matches(/^(?=.*[a-zA-Z0-9])[a-zA-Z0-9_ ]*$/, { message: - 'Only alphanumeric characters with spaces, dashes and underscores are allowed. (Example: my_application)', + 'Only alphanumeric characters with spaces and underscores are allowed. (Example: my_application)', excludeEmptyString: true, }) .matches( From 1246dbd1233a68f5529bc3eecfb7e202c1516d4f Mon Sep 17 00:00:00 2001 From: Hubert Koster Date: Mon, 17 Jul 2023 12:18:45 +0200 Subject: [PATCH 11/15] chore: allowing trailing spaces in table --- src/features/dashboard/components/Table/index.tsx | 1 + src/features/dashboard/components/Table/table.scss | 1 + 2 files changed, 2 insertions(+) diff --git a/src/features/dashboard/components/Table/index.tsx b/src/features/dashboard/components/Table/index.tsx index cc75d1e6c..4e6e9d68a 100644 --- a/src/features/dashboard/components/Table/index.tsx +++ b/src/features/dashboard/components/Table/index.tsx @@ -43,6 +43,7 @@ const Table = ({ return ( {row.cells.map((cell) => { + console.log(cell); return ( {cell.render('Cell', getCustomCellProps(cell))} diff --git a/src/features/dashboard/components/Table/table.scss b/src/features/dashboard/components/Table/table.scss index 8023c790f..52024dfb8 100644 --- a/src/features/dashboard/components/Table/table.scss +++ b/src/features/dashboard/components/Table/table.scss @@ -39,6 +39,7 @@ td:first-child, th:first-child { padding-left: rem(3.2); + white-space: pre; } tbody tr { From cd5bd6d64bed4492a67c6e8f3469a5a25cd9c847 Mon Sep 17 00:00:00 2001 From: Hubert Koster Date: Mon, 17 Jul 2023 13:00:56 +0200 Subject: [PATCH 12/15] chore: fixing input --- .../ApiTokenForm/api-token.form.module.scss | 13 +++++-------- src/features/dashboard/components/Table/index.tsx | 1 - 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/features/dashboard/components/ApiTokenForm/api-token.form.module.scss b/src/features/dashboard/components/ApiTokenForm/api-token.form.module.scss index 42c3f2ec2..4571be415 100644 --- a/src/features/dashboard/components/ApiTokenForm/api-token.form.module.scss +++ b/src/features/dashboard/components/ApiTokenForm/api-token.form.module.scss @@ -56,19 +56,16 @@ form { position: relative; box-sizing: border-box; margin: rem(1) 0; - &:focus-within { - border-color: var(--colors-blue400); - } &:hover { border: 1px solid var(--colors-greyLight600); } + &:focus-within { + border-color: var(--colors-blue500); + } button { - top: 0; - bottom: 0; - right: 0; - position: absolute; border-top-left-radius: 0; border-bottom-left-radius: 0; + height: rem(3); } label { position: absolute; @@ -98,7 +95,7 @@ form { } &:focus { outline-color: unset; - outline: 1px solid var(--colors-blue500); + outline: unset; border-radius: rem(0.3); & ~ label { color: var(--colors-blue400); diff --git a/src/features/dashboard/components/Table/index.tsx b/src/features/dashboard/components/Table/index.tsx index 4e6e9d68a..cc75d1e6c 100644 --- a/src/features/dashboard/components/Table/index.tsx +++ b/src/features/dashboard/components/Table/index.tsx @@ -43,7 +43,6 @@ const Table = ({ return ( {row.cells.map((cell) => { - console.log(cell); return ( {cell.render('Cell', getCustomCellProps(cell))} From c597b8145d5e1c847ee5648d3a74bf0666739b2f Mon Sep 17 00:00:00 2001 From: Hubert Koster Date: Mon, 17 Jul 2023 15:13:46 +0200 Subject: [PATCH 13/15] chore: removing things that will be added in different task --- .../components/ApiTokenForm/CreateTokenField/index.tsx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx b/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx index 39a34307b..1cd535472 100644 --- a/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx +++ b/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx @@ -46,8 +46,6 @@ const CreateTokenField = ({ }, [tokens]); const token_name_exists = getTokenNames.includes(input_value.toLowerCase()); - const no_min_max_error = - (errors && errors.name?.type === 'min') || (errors && errors.name?.type === 'max'); const disable_button = token_name_exists || Object.keys(errors).length > 0 || input_value === ''; const error_border_active = token_name_exists || errors.name; @@ -85,11 +83,6 @@ const CreateTokenField = ({

That name is taken. Choose another.

)} - {!no_min_max_error && ( -
-

Length of token name must be between 2 and 32 characters.

-
- )} ); }; From 3f12afed1bf31a57e905a5a5918c14bd6be80958 Mon Sep 17 00:00:00 2001 From: Hubert Koster Date: Tue, 18 Jul 2023 10:57:12 +0200 Subject: [PATCH 14/15] chore: fixing bug --- src/features/dashboard/components/Table/table.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/dashboard/components/Table/table.scss b/src/features/dashboard/components/Table/table.scss index 52024dfb8..481ddf212 100644 --- a/src/features/dashboard/components/Table/table.scss +++ b/src/features/dashboard/components/Table/table.scss @@ -39,7 +39,7 @@ td:first-child, th:first-child { padding-left: rem(3.2); - white-space: pre; + white-space: break-spaces; } tbody tr { From 9dd089de4de7609878f196a0bc46751b4a246e7a Mon Sep 17 00:00:00 2001 From: Hubert Koster Date: Tue, 18 Jul 2023 11:03:35 +0200 Subject: [PATCH 15/15] chore: fixing token dropdown position --- .../ApiTokenNavbarItem/api_token_switcher.module.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ApiTokenNavbarItem/api_token_switcher.module.scss b/src/components/ApiTokenNavbarItem/api_token_switcher.module.scss index a2cb3e6c7..bc72e1ba3 100644 --- a/src/components/ApiTokenNavbarItem/api_token_switcher.module.scss +++ b/src/components/ApiTokenNavbarItem/api_token_switcher.module.scss @@ -121,7 +121,7 @@ @media (max-width: 1200px) { position: fixed; width: 100%; - top: calc(var(--nav-height) + rem(3.3)); + top: calc(var(--nav-height) + rem(7)); left: 0; right: 0; }