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:
parent
e703f9b03d
commit
a545f723e9
@ -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"
|
||||
|
@ -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'
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
1
src/@types/Form.d.ts
vendored
1
src/@types/Form.d.ts
vendored
@ -13,6 +13,7 @@ export interface FormFieldProps {
|
||||
placeholder?: string
|
||||
pattern?: string
|
||||
min?: string
|
||||
advanced?: boolean
|
||||
}
|
||||
|
||||
export interface FormContent {
|
||||
|
2
src/@types/MetaData.d.ts
vendored
2
src/@types/MetaData.d.ts
vendored
@ -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 {
|
||||
|
@ -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':
|
||||
|
@ -0,0 +1,3 @@
|
||||
.advancedBtn {
|
||||
margin-bottom: 2rem;
|
||||
}
|
53
src/components/molecules/FormFields/AdvancedSettings.tsx
Normal file
53
src/components/molecules/FormFields/AdvancedSettings.tsx
Normal 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)
|
||||
}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
60
src/components/molecules/FormFields/CustomProvider.tsx
Normal file
60
src/components/molecules/FormFields/CustomProvider.tsx
Normal 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}
|
||||
/>
|
||||
)
|
||||
}
|
@ -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}
|
||||
|
@ -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>
|
||||
)
|
@ -23,6 +23,7 @@ export default function Debug({
|
||||
{
|
||||
index: 1,
|
||||
type: values.access,
|
||||
serviceEndpoint: values.providerUri,
|
||||
attributes: {}
|
||||
}
|
||||
]
|
||||
|
@ -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}
|
||||
|
@ -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}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -51,5 +51,6 @@ export const initialValues: Partial<MetadataPublishFormAlgorithm> = {
|
||||
algorithmPrivacy: false,
|
||||
termsAndConditions: false,
|
||||
tags: '',
|
||||
timeout: 'Forever'
|
||||
timeout: 'Forever',
|
||||
providerUri: ''
|
||||
}
|
||||
|
@ -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: ''
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user