1
0
mirror of https://github.com/oceanprotocol/market.git synced 2024-12-02 05:57:29 +01:00

#638 Initial design

This commit is contained in:
KY Lau 2021-06-04 18:08:47 +08:00
parent f5e01d7c0c
commit 1dccac1412
9 changed files with 390 additions and 0 deletions

View File

@ -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"
}
]
}
}

View File

@ -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 <Credential name={name} {...field} {...props} />
default:
return prefix || postfix ? (
<div className={`${prefix ? styles.prefixGroup : styles.postfixGroup}`}>

View File

@ -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;
}

View File

@ -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<string[]>(field.value)
const [value, setValue] = useState('')
useEffect(() => {
helpers.setValue(arrayInput)
}, [arrayInput])
function handleChange(e: ChangeEvent<HTMLInputElement>) {
setValue(e.target.value)
}
function handleDeleteChip(value: string) {
const newInput = arrayInput.filter((input) => input !== value)
setArrayInput(newInput)
helpers.setValue(newInput)
}
function handleAddValue(e: FormEvent<HTMLButtonElement>) {
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 (
<div>
<InputGroup>
<input
className={styles.input}
placeholder={props.placeholder}
name="search"
onChange={handleChange}
value={value}
/>
<Button
onClick={(e: FormEvent<HTMLButtonElement>) => handleAddValue(e)}
>
Add
</Button>
</InputGroup>
{arrayInput &&
arrayInput.map((value) => {
return (
<div className={styles.chip} key={value}>
{/* <Chip
label={value}
onDelete={(even) => handleDeleteChip(value)}
variant="outlined"
/> */}
value
</div>
)
})}
</div>
)
}

View File

@ -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<Credential>()
useEffect(() => {
if (!ocean) return
async function transformValues() {
// const credential = await transformComputeFormToServiceComputePrivacy(
// values,
// ocean
// )
// setCredential(credential)
}
transformValues()
}, [values, ddo, ocean])
return (
<>
<DebugOutput title="Collected Form Values" output={values} />
<DebugOutput title="Transformed Form Values" output={ddo.credentials} />
</>
)
}

View File

@ -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<string>()
const [error, setError] = useState<string>()
const hasFeedback = error || success
// TODO : get from env
//const credentialType = CredentialType.address
async function handleSubmit(
values: Partial<AdvanceSettingsForm>,
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 (
<Formik
// TODO: get credential from DDO
initialValues={getInitialValues([])}
validationSchema={validationSchema}
onSubmit={async (values, { resetForm }) => {
window.scrollTo({ top: 0, left: 0, behavior: 'smooth' })
await handleSubmit(values, resetForm)
}}
>
{({ isSubmitting, values, initialValues }) =>
isSubmitting || hasFeedback ? (
<MetadataFeedback
title="Updating Data Set"
error={error}
success={success}
setError={setError}
successAction={{
name: content.form.successAction,
onClick: async () => {
await refreshDdo()
setShowEdit(false)
}
}}
/>
) : (
<>
<p className={styles.description}>{content.description}</p>
<article className={styles.grid}>
<FormAdvanceSettings
data={content.form.data}
setShowEdit={setShowEdit}
values={initialValues}
/>
</article>
{debug === true && (
<div className={styles.grid}>
<DebugEditAdvanceSettings values={values} ddo={ddo} />
</div>
)}
</>
)
}
</Formik>
)
}

View File

@ -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<AdvanceSettingsForm>
}): ReactElement {
const { accountId } = useWeb3()
const { ocean, config } = useOcean()
const {
isValid,
validateField,
setFieldValue
}: FormikContextType<Partial<AdvanceSettingsForm>> = useFormikContext()
function handleFieldChange(
e: ChangeEvent<HTMLInputElement>,
field: FormFieldProps
) {
validateField(field.name)
setFieldValue(field.name, e.target.value)
}
return (
<Form className={styles.form}>
{data.map((field: FormFieldProps) => (
<Field
key={field.name}
{...field}
component={Input}
prefix={field.name === 'price' && config.oceanTokenSymbol}
onChange={(e: ChangeEvent<HTMLInputElement>) =>
handleFieldChange(e, field)
}
/>
))}
<footer className={styles.actions}>
<Button style="text" onClick={() => setShowEdit(false)}>
Cancel
</Button>
</footer>
</Form>
)
}

View File

@ -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<boolean>()
const [showEditCompute, setShowEditCompute] = useState<boolean>()
const [
showEditAdvanceSettings,
setShowEditAdvanceSettings
] = useState<boolean>()
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 ? (
<Edit setShowEdit={setShowEdit} />
) : showEditCompute ? (
<EditComputeDataset setShowEdit={setShowEditCompute} />
) : showEditAdvanceSettings ? (
<EditAdvanceSettings setShowEdit={setShowEditCompute} />
) : (
<article className={styles.grid}>
<div>
@ -103,6 +115,14 @@ export default function AssetContent(props: AssetContentProps): ReactElement {
<Button style="text" size="small" onClick={handleEditButton}>
Edit Metadata
</Button>
<span className={styles.separator}>|</span>
<Button
style="text"
size="small"
onClick={handleEditAdvanceSettingsButton}
>
Edit Advanced Settings
</Button>
{ddo.findServiceByType('compute') && type === 'dataset' && (
<>
<span className={styles.separator}>|</span>

View File

@ -0,0 +1,17 @@
import * as Yup from 'yup'
export interface AdvanceSettingsForm {
allowCredentail: string[]
}
export const validationSchema: Yup.SchemaOf<AdvanceSettingsForm> = Yup.object().shape(
{
allowCredentail: Yup.array().nullable()
}
)
export function getInitialValues(
allowCredentail: string[]
): AdvanceSettingsForm {
return { allowCredentail }
}