From fb0500f0e06f27b28beb81cea92ae18abad55c72 Mon Sep 17 00:00:00 2001 From: Luca Milanese Date: Thu, 28 Sep 2023 15:11:33 +0200 Subject: [PATCH 1/9] feat: add credentials setter to publish form --- content/publish/form.json | 14 ++++ .../InputElement/Credential/index.module.css | 11 +++ .../InputElement/Credential/index.tsx | 84 +++++++++++++++++++ .../@shared/FormInput/InputElement/index.tsx | 3 + src/components/Publish/Services/index.tsx | 10 +++ src/components/Publish/_constants.tsx | 4 +- src/components/Publish/_types.ts | 2 + src/components/Publish/_utils.ts | 19 ++++- src/components/Publish/_validation.ts | 4 +- 9 files changed, 148 insertions(+), 3 deletions(-) create mode 100644 src/components/@shared/FormInput/InputElement/Credential/index.module.css create mode 100644 src/components/@shared/FormInput/InputElement/Credential/index.tsx diff --git a/content/publish/form.json b/content/publish/form.json index 8c3a01668..93cf4f985 100644 --- a/content/publish/form.json +++ b/content/publish/form.json @@ -304,6 +304,20 @@ "type": "checkbox", "options": ["This asset uses user defined parameters"], "required": false + }, + { + "name": "allow", + "label": "Allow ETH Address", + "placeholder": "e.g. 0xe328aB96B7CbB55A6E1c1054678137bA09780acA", + "help": "Enter an ETH address and click the ADD button to append to the list. Only ETH addresses in the allow list can consume this asset. If the list is empty anyone can download or compute this asset.", + "type": "credentials" + }, + { + "name": "deny", + "label": "Deny ETH Address", + "placeholder": "e.g. 0xe328aB96B7CbB55A6E1c1054678137bA09780acA", + "help": "Enter an ETH address and click the ADD button to append to the list. If an ETH address is in the deny list, download or compute of this asset will be denied for that ETH address.", + "type": "credentials" } ] }, diff --git a/src/components/@shared/FormInput/InputElement/Credential/index.module.css b/src/components/@shared/FormInput/InputElement/Credential/index.module.css new file mode 100644 index 000000000..5d594fdee --- /dev/null +++ b/src/components/@shared/FormInput/InputElement/Credential/index.module.css @@ -0,0 +1,11 @@ +.addedAddressesContainer { + display: flex; + justify-content: space-between; + gap: 0 calc(var(--spacer) / 4); + flex-grow: 1; + margin-top: calc(var(--spacer) / 2); +} + +.addedAddressesContainer > div { + width: 100%; +} diff --git a/src/components/@shared/FormInput/InputElement/Credential/index.tsx b/src/components/@shared/FormInput/InputElement/Credential/index.tsx new file mode 100644 index 000000000..dbeeef19b --- /dev/null +++ b/src/components/@shared/FormInput/InputElement/Credential/index.tsx @@ -0,0 +1,84 @@ +import { useField } from 'formik' +import React, { useState, ChangeEvent, FormEvent, useEffect } from 'react' +import Button from '../../../atoms/Button' +import styles from './index.module.css' +import { isAddress } from 'web3-utils' +import { toast } from 'react-toastify' +import InputGroup from '../../InputGroup' +import InputElement from '..' +import { InputProps } from '../..' + +export default function Credentials(props: InputProps) { + const [field, meta, helpers] = useField(props.name) + const [arrayInput, setArrayInput] = useState(field.value || []) + const [value, setValue] = useState('') + + useEffect(() => { + helpers.setValue(arrayInput) + }, [arrayInput]) + + function handleDeleteChip(value: string) { + const newInput = arrayInput.filter((input) => input !== value) + setArrayInput(newInput) + helpers.setValue(newInput) + } + + function handleAddValue(e: FormEvent) { + e.preventDefault() + if (!isAddress(value)) { + toast.error('Wallet address is invalid') + return + } + if (arrayInput.includes(value.toLowerCase())) { + toast.error('Wallet address already added into list') + return + } + setArrayInput((arrayInput) => [...arrayInput, value.toLowerCase()]) + setValue('') + } + + return ( +
+ + ) => + setValue(e.target.value) + } + /> + + +
+ {arrayInput && + arrayInput.map((value, i) => { + return ( +
+ + + + +
+ ) + })} +
+
+ ) +} diff --git a/src/components/@shared/FormInput/InputElement/index.tsx b/src/components/@shared/FormInput/InputElement/index.tsx index 67df35d2f..8e33d5e00 100644 --- a/src/components/@shared/FormInput/InputElement/index.tsx +++ b/src/components/@shared/FormInput/InputElement/index.tsx @@ -17,6 +17,7 @@ import { extensions, oceanTheme } from '@utils/codemirror' import { ConsumerParameters } from './ConsumerParameters' import ServiceCredential from './ServiceCredential' import ComputeEnvSelection from './ComputeEnvSelection' +import Credentials from './Credential' const cx = classNames.bind(styles) @@ -212,6 +213,8 @@ const InputElement = forwardRef( ) case 'tags': return + case 'credentials': + return default: return prefix || postfix ? (
+ + {values.services[0].usesConsumerParameters && ( value || null) - }) + }), + allow: Yup.array().of(Yup.string()).nullable(), + deny: Yup.array().of(Yup.string()).nullable() } const validationPricing = { From 7487e11dfcc51f4fa574d1791276107e8aecedc4 Mon Sep 17 00:00:00 2001 From: Luca Milanese Date: Thu, 28 Sep 2023 16:51:54 +0200 Subject: [PATCH 2/9] feat: add whitelist updater to metadata edit form --- content/pages/editMetadata.json | 14 ++++++++++ src/components/Asset/Edit/EditMetadata.tsx | 9 +++++- .../Asset/Edit/FormEditMetadata.tsx | 7 ++++- src/components/Asset/Edit/_constants.ts | 14 +++++++++- src/components/Asset/Edit/_types.ts | 2 ++ src/components/Asset/Edit/_utils.ts | 28 +++++++++++++++++++ src/components/Asset/Edit/_validation.ts | 2 ++ 7 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 src/components/Asset/Edit/_utils.ts diff --git a/content/pages/editMetadata.json b/content/pages/editMetadata.json index 2030c4698..921571f2b 100644 --- a/content/pages/editMetadata.json +++ b/content/pages/editMetadata.json @@ -165,6 +165,20 @@ "options": ["This asset uses algorithm custom parameters"], "required": false }, + { + "name": "allow", + "label": "Allow ETH Address", + "placeholder": "e.g. 0xe328aB96B7CbB55A6E1c1054678137bA09780acA", + "help": "Enter an ETH address and click the ADD button to append to the list. Only ETH addresses in the allow list can consume this asset. If the list is empty anyone can download or compute this asset.", + "type": "credentials" + }, + { + "name": "deny", + "label": "Deny ETH Address", + "placeholder": "e.g. 0xe328aB96B7CbB55A6E1c1054678137bA09780acA", + "help": "Enter an ETH address and click the ADD button to append to the list. If an ETH address is in the deny list, download or compute of this asset will be denied for that ETH address.", + "type": "credentials" + }, { "name": "paymentCollector", "label": "Payment Collector Address", diff --git a/src/components/Asset/Edit/EditMetadata.tsx b/src/components/Asset/Edit/EditMetadata.tsx index be8c8513b..1e03457eb 100644 --- a/src/components/Asset/Edit/EditMetadata.tsx +++ b/src/components/Asset/Edit/EditMetadata.tsx @@ -34,6 +34,7 @@ import { assetStateToNumber } from '@utils/assetState' import { setMinterToPublisher, setMinterToDispenser } from '@utils/dispenser' import { useAccount, useProvider, useNetwork, useSigner } from 'wagmi' import { transformConsumerParameters } from '@components/Publish/_utils' +import { updateCredentials } from './_utils' export default function Edit({ asset @@ -166,7 +167,12 @@ export default function Edit({ ...(asset as Asset), version: '4.1.0', metadata: updatedMetadata, - services: [updatedService] + services: [updatedService], + credentials: updateCredentials( + asset?.credentials, + values?.allow, + values?.deny + ) } if ( @@ -244,6 +250,7 @@ export default function Edit({ initialValues={getInitialValues( asset?.metadata, asset?.services[0], + asset?.credentials, asset?.accessDetails?.price || '0', paymentCollector, assetState diff --git a/src/components/Asset/Edit/FormEditMetadata.tsx b/src/components/Asset/Edit/FormEditMetadata.tsx index 0567729f8..6d16374ba 100644 --- a/src/components/Asset/Edit/FormEditMetadata.tsx +++ b/src/components/Asset/Edit/FormEditMetadata.tsx @@ -150,7 +150,12 @@ export default function FormEditMetadata({ )} )} - + + credential.type === 'address') + ?.values || [], + deny: + credentials?.deny?.find((credential) => credential.type === 'address') + ?.values || [], assetState, service: { usesConsumerParameters: service?.consumerParameters?.length > 0, diff --git a/src/components/Asset/Edit/_types.ts b/src/components/Asset/Edit/_types.ts index 8b6288c92..2176ee0f7 100644 --- a/src/components/Asset/Edit/_types.ts +++ b/src/components/Asset/Edit/_types.ts @@ -14,6 +14,8 @@ export interface MetadataEditForm { tags?: string[] usesConsumerParameters?: boolean consumerParameters?: FormConsumerParameter[] + allow?: string[] + deny?: string[] assetState?: string service?: { usesConsumerParameters?: boolean diff --git a/src/components/Asset/Edit/_utils.ts b/src/components/Asset/Edit/_utils.ts new file mode 100644 index 000000000..51bdcdc9c --- /dev/null +++ b/src/components/Asset/Edit/_utils.ts @@ -0,0 +1,28 @@ +import { Credentials } from '@oceanprotocol/lib' + +export function updateCredentials( + oldCredentials: Credentials, + updatedAllow: string[], + updatedDeny: string[] +): Credentials { + const updatedCredentials = { + allow: oldCredentials?.allow || [], + deny: oldCredentials?.deny || [] + } + + const credentialTypes = [ + { type: 'allow', values: updatedAllow }, + { type: 'deny', values: updatedDeny } + ] + + credentialTypes.forEach((credentialType) => { + updatedCredentials[credentialType.type] = [ + ...updatedCredentials[credentialType.type].filter( + (credential) => credential?.type !== 'address' + ), + { type: 'address', values: credentialType.values } + ] + }) + + return updatedCredentials +} diff --git a/src/components/Asset/Edit/_validation.ts b/src/components/Asset/Edit/_validation.ts index 582ebff76..79579feb6 100644 --- a/src/components/Asset/Edit/_validation.ts +++ b/src/components/Asset/Edit/_validation.ts @@ -47,6 +47,8 @@ export const validationSchema = Yup.object().shape({ .nullable() .transform((value) => value || null) }), + allow: Yup.array().of(Yup.string()).nullable(), + deny: Yup.array().of(Yup.string()).nullable(), paymentCollector: Yup.string().test( 'ValidAddress', 'Must be a valid Ethereum Address.', From f2f272a469a58e7fea98b6923e58a3c7411d1205 Mon Sep 17 00:00:00 2001 From: Luca Milanese Date: Thu, 28 Sep 2023 17:37:46 +0200 Subject: [PATCH 3/9] fix: publish with empty credentials --- src/components/Publish/_utils.ts | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/components/Publish/_utils.ts b/src/components/Publish/_utils.ts index 094c6feed..77f46915d 100644 --- a/src/components/Publish/_utils.ts +++ b/src/components/Publish/_utils.ts @@ -148,18 +148,24 @@ export async function transformPublishFormToDdo( accessTermsFileInfo[0].valid && [sanitizeUrl(accessTermsFileInfo[0].url)] const credentials = { - allow: [ - { - type: 'address', - values: allow - } - ], - deny: [ - { - type: 'address', - values: deny - } - ] + allow: + allow.length > 0 + ? [ + { + type: 'address', + values: allow + } + ] + : [], + deny: + deny.length > 0 + ? [ + { + type: 'address', + values: deny + } + ] + : [] } const newMetadata: Metadata = { From 45177ee065653916f1069a40b874aee741b367a7 Mon Sep 17 00:00:00 2001 From: Luca Milanese Date: Thu, 28 Sep 2023 17:37:56 +0200 Subject: [PATCH 4/9] fix: edit with empty credentials --- src/components/Asset/Edit/EditMetadata.tsx | 12 +++++++----- src/components/Asset/Edit/_utils.ts | 4 +++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/components/Asset/Edit/EditMetadata.tsx b/src/components/Asset/Edit/EditMetadata.tsx index 1e03457eb..688a3cf13 100644 --- a/src/components/Asset/Edit/EditMetadata.tsx +++ b/src/components/Asset/Edit/EditMetadata.tsx @@ -162,17 +162,19 @@ export default function Edit({ ) } + const updatedCredentials = updateCredentials( + asset?.credentials, + values?.allow, + values?.deny + ) + console.log(updateCredentials) // TODO: remove version update at a later time const updatedAsset: Asset = { ...(asset as Asset), version: '4.1.0', metadata: updatedMetadata, services: [updatedService], - credentials: updateCredentials( - asset?.credentials, - values?.allow, - values?.deny - ) + credentials: updatedCredentials } if ( diff --git a/src/components/Asset/Edit/_utils.ts b/src/components/Asset/Edit/_utils.ts index 51bdcdc9c..fce8948b4 100644 --- a/src/components/Asset/Edit/_utils.ts +++ b/src/components/Asset/Edit/_utils.ts @@ -20,7 +20,9 @@ export function updateCredentials( ...updatedCredentials[credentialType.type].filter( (credential) => credential?.type !== 'address' ), - { type: 'address', values: credentialType.values } + ...(credentialType.values.length > 0 + ? [{ type: 'address', values: credentialType.values }] + : []) ] }) From ee7095f4c5d1fb7b89c4b93572a6e0ca1e6aeff8 Mon Sep 17 00:00:00 2001 From: Luca Milanese Date: Thu, 28 Sep 2023 18:06:51 +0200 Subject: [PATCH 5/9] refactor: generate credentials function --- src/components/Asset/Edit/EditMetadata.tsx | 10 ++-- src/components/Asset/Edit/_utils.ts | 30 ------------ src/components/Publish/_utils.ts | 57 +++++++++++++--------- 3 files changed, 40 insertions(+), 57 deletions(-) delete mode 100644 src/components/Asset/Edit/_utils.ts diff --git a/src/components/Asset/Edit/EditMetadata.tsx b/src/components/Asset/Edit/EditMetadata.tsx index 688a3cf13..5de42cfaa 100644 --- a/src/components/Asset/Edit/EditMetadata.tsx +++ b/src/components/Asset/Edit/EditMetadata.tsx @@ -33,8 +33,10 @@ import { getEncryptedFiles } from '@utils/provider' import { assetStateToNumber } from '@utils/assetState' import { setMinterToPublisher, setMinterToDispenser } from '@utils/dispenser' import { useAccount, useProvider, useNetwork, useSigner } from 'wagmi' -import { transformConsumerParameters } from '@components/Publish/_utils' -import { updateCredentials } from './_utils' +import { + transformConsumerParameters, + generateCredentials +} from '@components/Publish/_utils' export default function Edit({ asset @@ -162,12 +164,12 @@ export default function Edit({ ) } - const updatedCredentials = updateCredentials( + const updatedCredentials = generateCredentials( asset?.credentials, values?.allow, values?.deny ) - console.log(updateCredentials) + console.log(generateCredentials) // TODO: remove version update at a later time const updatedAsset: Asset = { ...(asset as Asset), diff --git a/src/components/Asset/Edit/_utils.ts b/src/components/Asset/Edit/_utils.ts deleted file mode 100644 index fce8948b4..000000000 --- a/src/components/Asset/Edit/_utils.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Credentials } from '@oceanprotocol/lib' - -export function updateCredentials( - oldCredentials: Credentials, - updatedAllow: string[], - updatedDeny: string[] -): Credentials { - const updatedCredentials = { - allow: oldCredentials?.allow || [], - deny: oldCredentials?.deny || [] - } - - const credentialTypes = [ - { type: 'allow', values: updatedAllow }, - { type: 'deny', values: updatedDeny } - ] - - credentialTypes.forEach((credentialType) => { - updatedCredentials[credentialType.type] = [ - ...updatedCredentials[credentialType.type].filter( - (credential) => credential?.type !== 'address' - ), - ...(credentialType.values.length > 0 - ? [{ type: 'address', values: credentialType.values }] - : []) - ] - }) - - return updatedCredentials -} diff --git a/src/components/Publish/_utils.ts b/src/components/Publish/_utils.ts index 77f46915d..efe12067c 100644 --- a/src/components/Publish/_utils.ts +++ b/src/components/Publish/_utils.ts @@ -13,7 +13,8 @@ import { getEventFromTx, ConsumerParameter, Metadata, - Service + Service, + Credentials } from '@oceanprotocol/lib' import { mapTimeoutStringToSeconds, normalizeFile } from '@utils/ddo' import { generateNftCreateData } from '@utils/nft' @@ -96,6 +97,35 @@ export function transformConsumerParameters( return transformedValues as ConsumerParameter[] } +export function generateCredentials( + oldCredentials: Credentials, + updatedAllow: string[], + updatedDeny: string[] +): Credentials { + const updatedCredentials = { + allow: oldCredentials?.allow || [], + deny: oldCredentials?.deny || [] + } + + const credentialTypes = [ + { type: 'allow', values: updatedAllow }, + { type: 'deny', values: updatedDeny } + ] + + credentialTypes.forEach((credentialType) => { + updatedCredentials[credentialType.type] = [ + ...updatedCredentials[credentialType.type].filter( + (credential) => credential?.type !== 'address' + ), + ...(credentialType.values.length > 0 + ? [{ type: 'address', values: credentialType.values }] + : []) + ] + }) + + return updatedCredentials +} + export async function transformPublishFormToDdo( values: FormPublishData, // Those 2 are only passed during actual publishing process @@ -147,27 +177,6 @@ export async function transformPublishFormToDdo( const accessTermsUrlTransformed = accessTermsFileInfo?.length && accessTermsFileInfo[0].valid && [sanitizeUrl(accessTermsFileInfo[0].url)] - const credentials = { - allow: - allow.length > 0 - ? [ - { - type: 'address', - values: allow - } - ] - : [], - deny: - deny.length > 0 - ? [ - { - type: 'address', - values: deny - } - ] - : [] - } - const newMetadata: Metadata = { created: currentTime, updated: currentTime, @@ -249,6 +258,8 @@ export async function transformPublishFormToDdo( : undefined } + const newCredentials = generateCredentials(undefined, allow, deny) + const newDdo: DDO = { '@context': ['https://w3id.org/did/v1'], id: did, @@ -257,7 +268,7 @@ export async function transformPublishFormToDdo( chainId, metadata: newMetadata, services: [newService], - credentials, + credentials: newCredentials, // Only added for DDO preview, reflecting Asset response, // again, we can assume if `datatokenAddress` is not passed, // we are on preview. From 89d83e93f51c40e35636be329603091c521458bd Mon Sep 17 00:00:00 2001 From: Luca Milanese Date: Thu, 28 Sep 2023 18:26:31 +0200 Subject: [PATCH 6/9] feat: update Credentials component naming --- .../InputElement/Credential/index.module.css | 4 +- .../InputElement/Credential/index.tsx | 40 ++++++++++--------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/components/@shared/FormInput/InputElement/Credential/index.module.css b/src/components/@shared/FormInput/InputElement/Credential/index.module.css index 5d594fdee..c062c5b8e 100644 --- a/src/components/@shared/FormInput/InputElement/Credential/index.module.css +++ b/src/components/@shared/FormInput/InputElement/Credential/index.module.css @@ -1,4 +1,4 @@ -.addedAddressesContainer { +.addressListContainer { display: flex; justify-content: space-between; gap: 0 calc(var(--spacer) / 4); @@ -6,6 +6,6 @@ margin-top: calc(var(--spacer) / 2); } -.addedAddressesContainer > div { +.addressListContainer > div { width: 100%; } diff --git a/src/components/@shared/FormInput/InputElement/Credential/index.tsx b/src/components/@shared/FormInput/InputElement/Credential/index.tsx index dbeeef19b..7541cea4c 100644 --- a/src/components/@shared/FormInput/InputElement/Credential/index.tsx +++ b/src/components/@shared/FormInput/InputElement/Credential/index.tsx @@ -2,7 +2,7 @@ import { useField } from 'formik' import React, { useState, ChangeEvent, FormEvent, useEffect } from 'react' import Button from '../../../atoms/Button' import styles from './index.module.css' -import { isAddress } from 'web3-utils' +import { isAddress } from 'ethers/lib/utils.js' import { toast } from 'react-toastify' import InputGroup from '../../InputGroup' import InputElement from '..' @@ -10,16 +10,16 @@ import { InputProps } from '../..' export default function Credentials(props: InputProps) { const [field, meta, helpers] = useField(props.name) - const [arrayInput, setArrayInput] = useState(field.value || []) + const [addressList, setAddressList] = useState(field.value || []) const [value, setValue] = useState('') useEffect(() => { - helpers.setValue(arrayInput) - }, [arrayInput]) + helpers.setValue(addressList) + }, [addressList]) - function handleDeleteChip(value: string) { - const newInput = arrayInput.filter((input) => input !== value) - setArrayInput(newInput) + function handleDeleteAddress(value: string) { + const newInput = addressList.filter((input) => input !== value) + setAddressList(newInput) helpers.setValue(newInput) } @@ -29,16 +29,16 @@ export default function Credentials(props: InputProps) { toast.error('Wallet address is invalid') return } - if (arrayInput.includes(value.toLowerCase())) { - toast.error('Wallet address already added into list') + if (addressList.includes(value.toLowerCase())) { + toast.error('Wallet address already added into hte list') return } - setArrayInput((arrayInput) => [...arrayInput, value.toLowerCase()]) + setAddressList((addressList) => [...addressList, value.toLowerCase()]) setValue('') } return ( -
+
) => handleAddValue(e)} + onClick={(e: FormEvent) => { + e.preventDefault() + handleAddValue(e) + }} > Add -
- {arrayInput && - arrayInput.map((value, i) => { +
+ {addressList.length > 0 && + addressList.map((value, i) => { return ( -
+
From 344e487e6bff0be3d6ababccc4dffb2913bfaaea Mon Sep 17 00:00:00 2001 From: Luca Milanese Date: Thu, 28 Sep 2023 18:33:24 +0200 Subject: [PATCH 7/9] chore: remove console.log --- src/components/Asset/Edit/EditMetadata.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Asset/Edit/EditMetadata.tsx b/src/components/Asset/Edit/EditMetadata.tsx index 5de42cfaa..761133da9 100644 --- a/src/components/Asset/Edit/EditMetadata.tsx +++ b/src/components/Asset/Edit/EditMetadata.tsx @@ -169,7 +169,7 @@ export default function Edit({ values?.allow, values?.deny ) - console.log(generateCredentials) + // TODO: remove version update at a later time const updatedAsset: Asset = { ...(asset as Asset), From 2f7700a3e3473984fb575be76c612da0074e0b1b Mon Sep 17 00:00:00 2001 From: Luca Milanese Date: Thu, 28 Sep 2023 18:34:30 +0200 Subject: [PATCH 8/9] fix: inputElement Credentials name prop --- src/components/@shared/FormInput/InputElement/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/@shared/FormInput/InputElement/index.tsx b/src/components/@shared/FormInput/InputElement/index.tsx index 8e33d5e00..0141b9149 100644 --- a/src/components/@shared/FormInput/InputElement/index.tsx +++ b/src/components/@shared/FormInput/InputElement/index.tsx @@ -214,7 +214,7 @@ const InputElement = forwardRef( case 'tags': return case 'credentials': - return + return default: return prefix || postfix ? (
Date: Thu, 28 Sep 2023 18:37:01 +0200 Subject: [PATCH 9/9] feat: update Credentials component style --- .../FormInput/InputElement/Credential/index.module.css | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/components/@shared/FormInput/InputElement/Credential/index.module.css b/src/components/@shared/FormInput/InputElement/Credential/index.module.css index c062c5b8e..df7b52ed6 100644 --- a/src/components/@shared/FormInput/InputElement/Credential/index.module.css +++ b/src/components/@shared/FormInput/InputElement/Credential/index.module.css @@ -1,11 +1,6 @@ .addressListContainer { display: flex; - justify-content: space-between; - gap: 0 calc(var(--spacer) / 4); - flex-grow: 1; + flex-direction: column; + gap: calc(var(--spacer) / 4); margin-top: calc(var(--spacer) / 2); } - -.addressListContainer > div { - width: 100%; -}