diff --git a/.env.example b/.env.example
index a91d4aca9..ada5e4e24 100644
--- a/.env.example
+++ b/.env.example
@@ -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"
diff --git a/app.config.js b/app.config.js
index a657752e1..5e508c6bf 100644
--- a/app.config.js
+++ b/app.config.js
@@ -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'
}
diff --git a/content/pages/publish/form-algorithm.json b/content/pages/publish/form-algorithm.json
index d5839527f..8ddc85e68 100644
--- a/content/pages/publish/form-algorithm.json
+++ b/content/pages/publish/form-algorithm.json
@@ -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",
diff --git a/content/pages/publish/form-dataset.json b/content/pages/publish/form-dataset.json
index 847ee53ef..8563a8c9b 100644
--- a/content/pages/publish/form-dataset.json
+++ b/content/pages/publish/form-dataset.json
@@ -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",
diff --git a/src/@types/Form.d.ts b/src/@types/Form.d.ts
index 929061e77..b1c234d4a 100644
--- a/src/@types/Form.d.ts
+++ b/src/@types/Form.d.ts
@@ -13,6 +13,7 @@ export interface FormFieldProps {
placeholder?: string
pattern?: string
min?: string
+ advanced?: boolean
}
export interface FormContent {
diff --git a/src/@types/MetaData.d.ts b/src/@types/MetaData.d.ts
index 1eeddc054..6cfede111 100644
--- a/src/@types/MetaData.d.ts
+++ b/src/@types/MetaData.d.ts
@@ -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 {
diff --git a/src/components/atoms/Input/InputElement.tsx b/src/components/atoms/Input/InputElement.tsx
index 966407381..cb1d8395f 100644
--- a/src/components/atoms/Input/InputElement.tsx
+++ b/src/components/atoms/Input/InputElement.tsx
@@ -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
+ case 'providerUri':
+ return
case 'datatoken':
return
case 'terms':
diff --git a/src/components/molecules/FormFields/AdvancedSettings.module.css b/src/components/molecules/FormFields/AdvancedSettings.module.css
new file mode 100644
index 000000000..c6b65a3bc
--- /dev/null
+++ b/src/components/molecules/FormFields/AdvancedSettings.module.css
@@ -0,0 +1,3 @@
+.advancedBtn {
+ margin-bottom: 2rem;
+}
diff --git a/src/components/molecules/FormFields/AdvancedSettings.tsx b/src/components/molecules/FormFields/AdvancedSettings.tsx
new file mode 100644
index 000000000..4588ec867
--- /dev/null
+++ b/src/components/molecules/FormFields/AdvancedSettings.tsx
@@ -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,
+ field: FormFieldProps
+ ) => void
+}): ReactElement {
+ const { appConfig } = useSiteMetadata()
+ const [advancedSettings, setAdvancedSettings] = useState(false)
+ function toggleAdvancedSettings(e: FormEvent) {
+ e.preventDefault()
+ advancedSettings === true
+ ? setAdvancedSettings(false)
+ : setAdvancedSettings(true)
+ }
+ return (
+ <>
+ {appConfig.allowAdvancedPublishSettings === 'true' && (
+
+ )}
+ {prop.content.data.map(
+ (field: FormFieldProps) =>
+ advancedSettings === true &&
+ field.advanced === true && (
+ ) =>
+ prop.handleFieldChange(e, field)
+ }
+ />
+ )
+ )}
+ >
+ )
+}
diff --git a/src/components/molecules/FormFields/CustomProvider.tsx b/src/components/molecules/FormFields/CustomProvider.tsx
new file mode 100644
index 000000000..3f8f9190c
--- /dev/null
+++ b/src/components/molecules/FormFields/CustomProvider.tsx
@@ -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()
+ 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 (
+
+ )
+}
diff --git a/src/components/molecules/FormFields/FilesInput/index.tsx b/src/components/molecules/FormFields/FilesInput/index.tsx
index 0ebdaf1ac..e07cf226a 100644
--- a/src/components/molecules/FormFields/FilesInput/index.tsx
+++ b/src/components/molecules/FormFields/FilesInput/index.tsx
@@ -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' ? (
) : (
- e.preventDefault()}
disabled={!field.value}
>
- {isLoading ? : 'Add File'}
+ {isLoading ? : submitText}
)
diff --git a/src/components/pages/Publish/Debug.tsx b/src/components/pages/Publish/Debug.tsx
index 2aa2375e4..73a8ffdb6 100644
--- a/src/components/pages/Publish/Debug.tsx
+++ b/src/components/pages/Publish/Debug.tsx
@@ -23,6 +23,7 @@ export default function Debug({
{
index: 1,
type: values.access,
+ serviceEndpoint: values.providerUri,
attributes: {}
}
]
diff --git a/src/components/pages/Publish/FormAlgoPublish.tsx b/src/components/pages/Publish/FormAlgoPublish.tsx
index 3d60937f8..b6320b59e 100644
--- a/src/components/pages/Publish/FormAlgoPublish.tsx
+++ b/src/components/pages/Publish/FormAlgoPublish.tsx
@@ -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 {
/>
)
)}
-
+
- {content.data.map((field: FormFieldProps) => (
- ) =>
- handleFieldChange(e, field)
- }
- />
- ))}
+ {content.data.map(
+ (field: FormFieldProps) =>
+ field.advanced !== true && (
+ ) =>
+ handleFieldChange(e, field)
+ }
+ />
+ )
+ )}
+
= {
algorithmPrivacy: false,
termsAndConditions: false,
tags: '',
- timeout: 'Forever'
+ timeout: 'Forever',
+ providerUri: ''
}
diff --git a/src/models/FormPublish.ts b/src/models/FormPublish.ts
index 8f6550459..001a0ad60 100644
--- a/src/models/FormPublish.ts
+++ b/src/models/FormPublish.ts
@@ -25,10 +25,10 @@ export const validationSchema: Yup.SchemaOf =
.matches(/Compute|Download/g, { excludeEmptyString: true })
.required('Required'),
termsAndConditions: Yup.boolean().required('Required'),
-
// ---- optional fields ----
tags: Yup.string().nullable(),
- links: Yup.array().nullable()
+ links: Yup.array().nullable(),
+ providerUri: Yup.string().url().nullable()
})
.defined()
@@ -44,5 +44,6 @@ export const initialValues: Partial = {
timeout: 'Forever',
access: '',
termsAndConditions: false,
- tags: ''
+ tags: '',
+ providerUri: ''
}