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

Add custom provider to publish form (#707)

* Creating custom provider box selection

* adding provider to Form publish validation schema

* validating custom provider URL

* WIP validation for custom provider

* validating provider uri

* adding success/ error messages

* conditional rendering of custom provider input

* remove console.log

* fixing textFormData

* Publishing custom provider URI in DDO

* Adding serviceEndpoint to Debug

* removing pre-checked default provider

* Refactoring to reduce code duplication

* removing console.log messages

* update submit text

* update submit text

* Placing custom provider field behind Advanced Settings

* removing provider field

* updating placeholder provider

* style for advanced setting button

* refactoring customProvider

* remocing template literal

* fixing linting errors

* restricting advanced publishing settings through env var

* updating example env

* adding custom provider to formAlgoPublish

* refactoring to reduce duplication

* Reducing duplication

* updating types and initial values

* Removing Custom provider input from main algorithm form

* Removing concole.log

* Chaning customProvider to providerUri

* changing customProvider to providerUri

* advanceSettings to PascalCase

* Removing unused useOcean()

* Using useSiteMetadata() hook

* Adding allowAdvancedPublishSettings to query

* Adding temporary console.log(ocean)

* Removing console.log
This commit is contained in:
Jamie Hewitt 2021-08-20 13:49:15 +01:00 committed by GitHub
parent e703f9b03d
commit a545f723e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 194 additions and 28 deletions

View File

@ -18,6 +18,7 @@
# Enables another asset editing button holder further advanced settings
#GATSBY_ALLOW_ADVANCED_SETTINGS="true"
#GATSBY_ALLOW_ADVANCED_PUBLISH_SETTINGS="true"
# Allow/Deny Lists
#GATSBY_CREDENTIAL_TYPE="address"

View File

@ -60,5 +60,7 @@ module.exports = {
// Used to show or hide advanced settings button in asset details page
allowAdvancedSettings: process.env.GATSBY_ALLOW_ADVANCED_SETTINGS || 'false',
allowAdvancedPublishSettings:
process.env.GATSBY_ALLOW_ADVANCED_PUBLISH_SETTINGS || 'false',
credentialType: process.env.GATSBY_CREDENTIAL_TYPE || 'address'
}

View File

@ -91,6 +91,14 @@
"placeholder": "e.g. logistics, ai",
"help": "Separate tags with comma."
},
{
"name": "providerUri",
"label": "Custom Provider URL",
"type": "providerUri",
"help": "Enter the URL for your custom provider or leave blank to use the default provider. [Learn more](https://github.com/oceanprotocol/provider/).",
"placeholder": "https://provider.polygon.oceanprotocol.com/",
"advanced": true
},
{
"name": "termsAndConditions",
"label": "Terms & Conditions",

View File

@ -38,6 +38,14 @@
"options": ["Download", "Compute"],
"required": true
},
{
"name": "providerUri",
"label": "Custom Provider URL",
"type": "providerUri",
"help": "Enter the URL for your custom provider or leave blank to use the default provider. [Learn more](https://github.com/oceanprotocol/provider/).",
"placeholder": "https://provider.polygon.oceanprotocol.com/",
"advanced": true
},
{
"name": "timeout",
"label": "Timeout",

View File

@ -13,6 +13,7 @@ export interface FormFieldProps {
placeholder?: string
pattern?: string
min?: string
advanced?: boolean
}
export interface FormContent {

View File

@ -38,6 +38,7 @@ export interface MetadataPublishFormDataset {
// ---- optional fields ----
tags?: string
links?: string | EditableMetadataLinks[]
providerUri?: string
}
export interface MetadataPublishFormAlgorithm {
@ -56,6 +57,7 @@ export interface MetadataPublishFormAlgorithm {
containerTag: string
entrypoint: string
tags?: string
providerUri?: string
}
export interface MetadataEditForm {

View File

@ -3,6 +3,7 @@ import slugify from '@sindresorhus/slugify'
import styles from './InputElement.module.css'
import { InputProps } from '.'
import FilesInput from '../../molecules/FormFields/FilesInput'
import CustomProvider from '../../molecules/FormFields/CustomProvider'
import Terms from '../../molecules/FormFields/Terms'
import BoxSelection, {
BoxSelectionOption
@ -125,6 +126,8 @@ export default function InputElement({
)
case 'files':
return <FilesInput name={name} {...field} {...props} />
case 'providerUri':
return <CustomProvider name={name} {...field} {...props} />
case 'datatoken':
return <Datatoken name={name} {...field} {...props} />
case 'terms':

View File

@ -0,0 +1,3 @@
.advancedBtn {
margin-bottom: 2rem;
}

View File

@ -0,0 +1,53 @@
import React, { ReactElement, useState, FormEvent, ChangeEvent } from 'react'
import { useSiteMetadata } from '../../../hooks/useSiteMetadata'
import Input from '../../atoms/Input'
import Button from '../../atoms/Button'
import { FormContent, FormFieldProps } from '../../../@types/Form'
import { Field } from 'formik'
import styles from './AdvancedSettings.module.css'
export default function AdvancedSettings(prop: {
content: FormContent
handleFieldChange: (
e: ChangeEvent<HTMLInputElement>,
field: FormFieldProps
) => void
}): ReactElement {
const { appConfig } = useSiteMetadata()
const [advancedSettings, setAdvancedSettings] = useState<boolean>(false)
function toggleAdvancedSettings(e: FormEvent<Element>) {
e.preventDefault()
advancedSettings === true
? setAdvancedSettings(false)
: setAdvancedSettings(true)
}
return (
<>
{appConfig.allowAdvancedPublishSettings === 'true' && (
<Button
className={styles.advancedBtn}
style="text"
size="small"
onClick={toggleAdvancedSettings}
>
Advanced Settings
</Button>
)}
{prop.content.data.map(
(field: FormFieldProps) =>
advancedSettings === true &&
field.advanced === true && (
<Field
key={field.name}
{...field}
options={field.options}
component={Input}
onChange={(e: ChangeEvent<HTMLInputElement>) =>
prop.handleFieldChange(e, field)
}
/>
)
)}
</>
)
}

View File

@ -0,0 +1,60 @@
import React, { ReactElement, useState, useEffect } from 'react'
import { useField } from 'formik'
import { toast } from 'react-toastify'
import CustomInput from './URLInput/Input'
import { useOcean } from '../../../providers/Ocean'
import { InputProps } from '../../atoms/Input'
export default function CustomProvider(props: InputProps): ReactElement {
const [field, meta, helpers] = useField(props.name)
const [isLoading, setIsLoading] = useState(false)
const [providerUrl, setProviderUrl] = useState<string>()
const { ocean, config } = useOcean()
function loadProvider() {
if (!providerUrl) return
async function validateProvider() {
let valid: boolean
try {
setIsLoading(true)
valid = await ocean.provider.isValidProvider(providerUrl)
} catch (error) {
valid = false
console.error(error.message)
} finally {
valid
? toast.success('Perfect! That provider URL looks good 🐳')
: toast.error(
'Could not validate provider. Please check URL and try again'
)
setIsLoading(false)
}
}
validateProvider()
}
useEffect(() => {
loadProvider()
}, [providerUrl, config.providerUri])
async function handleButtonClick(e: React.SyntheticEvent, url: string) {
helpers.setTouched(false)
e.preventDefault()
if (providerUrl === url) {
loadProvider()
}
setProviderUrl(url)
}
return (
<CustomInput
submitText="Validate"
{...props}
{...field}
isLoading={isLoading}
handleButtonClick={handleButtonClick}
/>
)
}

View File

@ -3,7 +3,7 @@ import axios from 'axios'
import { useField } from 'formik'
import { toast } from 'react-toastify'
import FileInfo from './Info'
import FileInput from './Input'
import CustomInput from '../URLInput/Input'
import { InputProps } from '../../../atoms/Input'
import { fileinfo } from '../../../../utils/provider'
import { useWeb3 } from '../../../../providers/Web3'
@ -68,7 +68,8 @@ export default function FilesInput(props: InputProps): ReactElement {
{field?.value && field.value[0] && typeof field.value === 'object' ? (
<FileInfo name={props.name} file={field.value[0]} />
) : (
<FileInput
<CustomInput
submitText="Add File"
{...props}
{...field}
isLoading={isLoading}

View File

@ -5,11 +5,13 @@ import Loader from '../../../atoms/Loader'
import styles from './Input.module.css'
import InputGroup from '../../../atoms/Input/InputGroup'
export default function FileInput({
export default function URLInput({
submitText,
handleButtonClick,
isLoading,
...props
}: {
submitText: string
handleButtonClick(e: React.SyntheticEvent, data: string): void
isLoading: boolean
}): ReactElement {
@ -30,7 +32,7 @@ export default function FileInput({
onClick={(e: React.SyntheticEvent) => e.preventDefault()}
disabled={!field.value}
>
{isLoading ? <Loader /> : 'Add File'}
{isLoading ? <Loader /> : submitText}
</Button>
</InputGroup>
)

View File

@ -23,6 +23,7 @@ export default function Debug({
{
index: 1,
type: values.access,
serviceEndpoint: values.providerUri,
attributes: {}
}
]

View File

@ -11,6 +11,7 @@ import Input from '../../atoms/Input'
import { FormContent, FormFieldProps } from '../../../@types/Form'
import { MetadataPublishFormAlgorithm } from '../../../@types/MetaData'
import { initialValues as initialValuesAlgorithm } from '../../../models/FormAlgoPublish'
import AdvancedSettings from '../../molecules/FormFields/AdvancedSettings'
import FormTitle from './FormTitle'
import FormActions from './FormActions'
import styles from './FormPublish.module.css'
@ -33,6 +34,7 @@ const query = graphql`
required
sortOptions
options
advanced
}
warning
}
@ -145,6 +147,7 @@ export default function FormPublish(): ReactElement {
{content.data.map(
(field: FormFieldProps) =>
field.advanced !== true &&
((field.name !== 'entrypoint' &&
field.name !== 'image' &&
field.name !== 'containerTag') ||
@ -164,7 +167,10 @@ export default function FormPublish(): ReactElement {
/>
)
)}
<AdvancedSettings
content={content}
handleFieldChange={handleFieldChange}
/>
<FormActions
isValid={isValid}
resetFormAndClearStorage={resetFormAndClearStorage}

View File

@ -16,6 +16,7 @@ import { ReactComponent as Compute } from '../../../images/compute.svg'
import FormTitle from './FormTitle'
import FormActions from './FormActions'
import styles from './FormPublish.module.css'
import AdvancedSettings from '../../molecules/FormFields/AdvancedSettings'
const query = graphql`
query {
@ -35,6 +36,7 @@ const query = graphql`
required
sortOptions
options
advanced
}
warning
}
@ -125,23 +127,30 @@ export default function FormPublish(): ReactElement {
>
<FormTitle title={content.title} />
{content.data.map((field: FormFieldProps) => (
<Field
key={field.name}
{...field}
options={
field.type === 'boxSelection'
? accessTypeOptions
: field.name === 'timeout' && computeTypeSelected === true
? computeTypeOptions
: field.options
}
component={Input}
onChange={(e: ChangeEvent<HTMLInputElement>) =>
handleFieldChange(e, field)
}
/>
))}
{content.data.map(
(field: FormFieldProps) =>
field.advanced !== true && (
<Field
key={field.name}
{...field}
options={
field.type === 'boxSelection'
? accessTypeOptions
: field.name === 'timeout' && computeTypeSelected === true
? computeTypeOptions
: field.options
}
component={Input}
onChange={(e: ChangeEvent<HTMLInputElement>) =>
handleFieldChange(e, field)
}
/>
)
)}
<AdvancedSettings
content={content}
handleFieldChange={handleFieldChange}
/>
<FormActions
isValid={isValid}

View File

@ -132,14 +132,16 @@ export default function PublishPage({
'Publish with ',
metadata,
serviceType,
values.dataTokenOptions
values.dataTokenOptions,
values.providerUri
)
const ddo = await publish(
metadata as unknown as Metadata,
serviceType,
values.dataTokenOptions,
timeout
timeout,
values.providerUri
)
// Publish failed

View File

@ -32,6 +32,7 @@ interface UseSiteMetadata {
allowFreePricing: string
allowAdvancedSettings: string
credentialType: string
allowAdvancedPublishSettings: string
}
}
@ -68,6 +69,7 @@ const query = graphql`
allowDynamicPricing
allowFreePricing
allowAdvancedSettings
allowAdvancedPublishSettings
credentialType
}
}

View File

@ -51,5 +51,6 @@ export const initialValues: Partial<MetadataPublishFormAlgorithm> = {
algorithmPrivacy: false,
termsAndConditions: false,
tags: '',
timeout: 'Forever'
timeout: 'Forever',
providerUri: ''
}

View File

@ -25,10 +25,10 @@ export const validationSchema: Yup.SchemaOf<MetadataPublishFormDataset> =
.matches(/Compute|Download/g, { excludeEmptyString: true })
.required('Required'),
termsAndConditions: Yup.boolean().required('Required'),
// ---- optional fields ----
tags: Yup.string().nullable(),
links: Yup.array<FileMetadata[]>().nullable()
links: Yup.array<FileMetadata[]>().nullable(),
providerUri: Yup.string().url().nullable()
})
.defined()
@ -44,5 +44,6 @@ export const initialValues: Partial<MetadataPublishFormDataset> = {
timeout: 'Forever',
access: '',
termsAndConditions: false,
tags: ''
tags: '',
providerUri: ''
}