diff --git a/content/pages/editAdvanceSettings.json b/content/pages/editAdvanceSettings.json new file mode 100644 index 000000000..ed2fe1cbe --- /dev/null +++ b/content/pages/editAdvanceSettings.json @@ -0,0 +1,17 @@ +{ + "description": "Update credential of this data set. Updating metadata will create an on-chain transaction you have to approve in your wallet.", + "form": { + "success": "🎉 Successfully updated. 🎉", + "successAction": "Close", + "error": "Updating DDO failed.", + "data": [ + { + "name": "allow", + "label": "Wallet Address", + "placeholder": "e.g. 0x12345678901234567890abcd", + "help": "Enter wallet address and click ADD button to append the list", + "type": "credential" + } + ] + } +} diff --git a/src/components/atoms/Input/InputElement.tsx b/src/components/atoms/Input/InputElement.tsx index 39637a8ff..f3e65d772 100644 --- a/src/components/atoms/Input/InputElement.tsx +++ b/src/components/atoms/Input/InputElement.tsx @@ -12,6 +12,7 @@ import classNames from 'classnames/bind' import AssetSelection, { AssetSelectionAsset } from '../../molecules/FormFields/AssetSelection' +import Credential from '../../molecules/FormFields/Credential' const cx = classNames.bind(styles) @@ -137,6 +138,8 @@ export default function InputElement({ {...props} /> ) + case 'credential': + return default: return prefix || postfix ? (
diff --git a/src/components/molecules/FormFields/Credential/Credential.module.css b/src/components/molecules/FormFields/Credential/Credential.module.css new file mode 100644 index 000000000..242eb9ab9 --- /dev/null +++ b/src/components/molecules/FormFields/Credential/Credential.module.css @@ -0,0 +1,24 @@ +.chip { + display: flex; + margin-top: 5px; + margin-bottom: 5px; +} + +.input { + font-size: var(--font-size-base); + font-family: var(--font-family-base); + font-weight: var(--font-weight-bold); + color: var(--font-color-heading); + border: 1px solid var(--border-color); + box-shadow: none; + width: 100%; + background: var(--background-body); + padding: calc(var(--spacer) / 3); + margin: 0; + border-radius: var(--border-radius); + transition: 0.2s ease-out; + height: 43px; + min-width: 0; + appearance: none; + display: block; +} diff --git a/src/components/molecules/FormFields/Credential/index.tsx b/src/components/molecules/FormFields/Credential/index.tsx new file mode 100644 index 000000000..cde4bdfed --- /dev/null +++ b/src/components/molecules/FormFields/Credential/index.tsx @@ -0,0 +1,74 @@ +import { useField } from 'formik' +import { InputProps } from '../../../atoms/Input' +import React, { useState, ChangeEvent, FormEvent, useEffect } from 'react' +import InputGroup from '../../../atoms/Input/InputGroup' +import Button from '../../../atoms/Button' +import styles from './Credential.module.css' +import { isAddress } from 'web3-utils' +import { toast } from 'react-toastify' + +export default function Credential(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 handleChange(e: ChangeEvent) { + setValue(e.target.value) + } + + 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)) { + toast.error('Wallet address already added into list') + return + } + setArrayInput((arrayInput) => [...arrayInput, value]) + setValue('') + } + + return ( +
+ + + + + {arrayInput && + arrayInput.map((value) => { + return ( +
+ {/* handleDeleteChip(value)} + variant="outlined" + /> */} + value +
+ ) + })} +
+ ) +} diff --git a/src/components/organisms/AssetActions/Edit/DebugEditAdvanceSettings.tsx b/src/components/organisms/AssetActions/Edit/DebugEditAdvanceSettings.tsx new file mode 100644 index 000000000..e41b3f803 --- /dev/null +++ b/src/components/organisms/AssetActions/Edit/DebugEditAdvanceSettings.tsx @@ -0,0 +1,37 @@ +import { DDO, ServiceComputePrivacy } from '@oceanprotocol/lib' +import React, { ReactElement, useEffect, useState } from 'react' +import { AdvanceSettingsForm } from '../../../../models/FormEditCredential' +import { useOcean } from '../../../../providers/Ocean' +import DebugOutput from '../../../atoms/DebugOutput' +import { Credential } from '@oceanprotocol/lib/dist/node/ddo/interfaces/Credentials' + +export default function DebugEditCredential({ + values, + ddo +}: { + values: AdvanceSettingsForm + ddo: DDO +}): ReactElement { + const { ocean } = useOcean() + const [credential, setCredential] = useState() + + useEffect(() => { + if (!ocean) return + + async function transformValues() { + // const credential = await transformComputeFormToServiceComputePrivacy( + // values, + // ocean + // ) + // setCredential(credential) + } + transformValues() + }, [values, ddo, ocean]) + + return ( + <> + + + + ) +} diff --git a/src/components/organisms/AssetActions/Edit/EditAdvanceSettings.tsx b/src/components/organisms/AssetActions/Edit/EditAdvanceSettings.tsx new file mode 100644 index 000000000..e4e104c7b --- /dev/null +++ b/src/components/organisms/AssetActions/Edit/EditAdvanceSettings.tsx @@ -0,0 +1,141 @@ +import { Formik } from 'formik' +import React, { ReactElement, useState } from 'react' +import { useAsset } from '../../../../providers/Asset' +import { useUserPreferences } from '../../../../providers/UserPreferences' +import styles from './index.module.css' +import { DDO, Logger } from '@oceanprotocol/lib' +import MetadataFeedback from '../../../molecules/MetadataFeedback' +import { graphql, useStaticQuery } from 'gatsby' +import { useWeb3 } from '../../../../providers/Web3' +import { useOcean } from '../../../../providers/Ocean' +import FormAdvanceSettings from './FormAdvanceSettings' +import { + AdvanceSettingsForm, + getInitialValues, + validationSchema +} from '../../../../models/FormEditCredential' +import DebugEditAdvanceSettings from './DebugEditAdvanceSettings' +import { CredentialType } from '@oceanprotocol/lib/dist/node/ddo/interfaces/Credentials' + +const contentQuery = graphql` + query EditAvanceSettingsQuery { + content: allFile( + filter: { relativePath: { eq: "pages/editAdvanceSettings.json" } } + ) { + edges { + node { + childPagesJson { + description + form { + success + successAction + error + data { + name + placeholder + label + help + type + } + } + } + } + } + } + } +` + +export default function EditAdvanceSettings({ + setShowEdit +}: { + setShowEdit: (show: boolean) => void +}): ReactElement { + const data = useStaticQuery(contentQuery) + const content = data.content.edges[0].node.childPagesJson + + const { debug } = useUserPreferences() + const { accountId } = useWeb3() + const { ocean } = useOcean() + const { metadata, ddo, refreshDdo, price } = useAsset() + const [success, setSuccess] = useState() + const [error, setError] = useState() + + const hasFeedback = error || success + // TODO : get from env + //const credentialType = CredentialType.address + + async function handleSubmit( + values: Partial, + resetForm: () => void + ) { + try { + // const ddoEditedCredential = await ocean.assets.updateCredentials( + // ddo, + // credentialType, + // values.allowCredentail, + // [] + // ) + + const storedddo = await ocean.assets.updateMetadata(ddo, accountId) + + if (!storedddo) { + setError(content.form.error) + Logger.error(content.form.error) + return + } else { + setSuccess(content.form.success) + resetForm() + } + } catch (error) { + Logger.error(error.message) + setError(error.message) + } + } + + return ( + { + window.scrollTo({ top: 0, left: 0, behavior: 'smooth' }) + await handleSubmit(values, resetForm) + }} + > + {({ isSubmitting, values, initialValues }) => + isSubmitting || hasFeedback ? ( + { + await refreshDdo() + setShowEdit(false) + } + }} + /> + ) : ( + <> +

{content.description}

+
+ +
+ + {debug === true && ( +
+ +
+ )} + + ) + } +
+ ) +} diff --git a/src/components/organisms/AssetActions/Edit/FormAdvanceSettings.tsx b/src/components/organisms/AssetActions/Edit/FormAdvanceSettings.tsx new file mode 100644 index 000000000..89816cf2f --- /dev/null +++ b/src/components/organisms/AssetActions/Edit/FormAdvanceSettings.tsx @@ -0,0 +1,57 @@ +import React, { ChangeEvent, ReactElement } from 'react' +import styles from './FormEditMetadata.module.css' //TODO +import { Field, Form, FormikContextType, useFormikContext } from 'formik' +import Button from '../../../atoms/Button' +import Input from '../../../atoms/Input' +import { FormFieldProps } from '../../../../@types/Form' +import { useOcean } from '../../../../providers/Ocean' +import { useWeb3 } from '../../../../providers/Web3' +import { AdvanceSettingsForm } from '../../../../models/FormEditCredential' + +export default function FormAdvanceSettings({ + data, + setShowEdit, + values +}: { + data: FormFieldProps[] + setShowEdit: (show: boolean) => void + values: Partial +}): ReactElement { + const { accountId } = useWeb3() + const { ocean, config } = useOcean() + const { + isValid, + validateField, + setFieldValue + }: FormikContextType> = useFormikContext() + + function handleFieldChange( + e: ChangeEvent, + field: FormFieldProps + ) { + validateField(field.name) + setFieldValue(field.name, e.target.value) + } + + return ( +
+ {data.map((field: FormFieldProps) => ( + ) => + handleFieldChange(e, field) + } + /> + ))} + +
+ +
+ + ) +} diff --git a/src/components/organisms/AssetContent/index.tsx b/src/components/organisms/AssetContent/index.tsx index abd48cbe6..00c09054f 100644 --- a/src/components/organisms/AssetContent/index.tsx +++ b/src/components/organisms/AssetContent/index.tsx @@ -17,6 +17,7 @@ import MetaMain from './MetaMain' import EditHistory from './EditHistory' import { useWeb3 } from '../../../providers/Web3' import styles from './index.module.css' +import EditAdvanceSettings from '../AssetActions/Edit/EditAdvanceSettings' export interface AssetContentProps { path?: string @@ -48,6 +49,10 @@ export default function AssetContent(props: AssetContentProps): ReactElement { const [showPricing, setShowPricing] = useState(false) const [showEdit, setShowEdit] = useState() const [showEditCompute, setShowEditCompute] = useState() + const [ + showEditAdvanceSettings, + setShowEditAdvanceSettings + ] = useState() const [isOwner, setIsOwner] = useState(false) const { ddo, price, metadata, type } = useAsset() @@ -70,10 +75,17 @@ export default function AssetContent(props: AssetContentProps): ReactElement { setShowEditCompute(true) } + function handleEditAdvanceSettingsButton() { + window.scrollTo({ top: 0, left: 0, behavior: 'smooth' }) + setShowEditAdvanceSettings(true) + } + return showEdit ? ( ) : showEditCompute ? ( + ) : showEditAdvanceSettings ? ( + ) : (
@@ -103,6 +115,14 @@ export default function AssetContent(props: AssetContentProps): ReactElement { + | + {ddo.findServiceByType('compute') && type === 'dataset' && ( <> | diff --git a/src/models/FormEditCredential.ts b/src/models/FormEditCredential.ts new file mode 100644 index 000000000..9d8df285e --- /dev/null +++ b/src/models/FormEditCredential.ts @@ -0,0 +1,17 @@ +import * as Yup from 'yup' + +export interface AdvanceSettingsForm { + allowCredentail: string[] +} + +export const validationSchema: Yup.SchemaOf = Yup.object().shape( + { + allowCredentail: Yup.array().nullable() + } +) + +export function getInitialValues( + allowCredentail: string[] +): AdvanceSettingsForm { + return { allowCredentail } +}